Index: trunk/nv/interface/camera.hh
===================================================================
--- trunk/nv/interface/camera.hh	(revision 231)
+++ trunk/nv/interface/camera.hh	(revision 232)
@@ -41,7 +41,32 @@
 		}
 	private:
+		bool m_dirty;
 		mat4 m_projection;
 		mat4 m_view;
 	};
+
+	// TODO - this and camera should have dirty states
+	class scene_state
+	{
+	public:
+		const camera& get_camera() const   { return m_camera; }
+		camera& get_camera()               { return m_camera; }
+		void set_camera( const camera& c ) { m_camera = c; }
+		void set_model( const mat4& m )    { m_model  = m; } 
+
+		const mat4& get_model()      const { return m_model; }
+		const mat4& get_view()       const { return m_camera.get_view(); }
+		const mat4& get_projection() const { return m_camera.get_projection(); }
+		mat4 get_modelview()  const { return get_view() * m_model; }
+		mat4 get_mvp()        const { return m_camera.get_projection() * get_modelview(); }
+
+		mat4 get_view_inv()   const { return glm::inverse( get_view() ); }
+		mat3 get_normal()     const { return glm::transpose(glm::inverse(glm::mat3( get_modelview() ) ) ); }
+	protected:
+		mat4   m_model;
+		camera m_camera; 
+	};
+
+
 }
 
Index: trunk/nv/interface/context.hh
===================================================================
--- trunk/nv/interface/context.hh	(revision 231)
+++ trunk/nv/interface/context.hh	(revision 232)
@@ -14,4 +14,5 @@
 
 #include <nv/common.hh>
+#include <nv/interface/camera.hh>
 #include <nv/interface/program.hh>
 #include <nv/interface/vertex_buffer.hh>
@@ -51,11 +52,27 @@
 	{
 	public:
-		context( device* a_device ) { m_device = a_device; }
+		context( device* a_device )	
+		{ 
+			// TODO: this will pose a problem in case of multiple contexts
+			program::initialize_engine_uniforms();
+			m_device = a_device; 
+		}
 		virtual void clear( const clear_state& cs ) = 0;
 		// temporary
 		virtual void draw( primitive prim, const render_state& rs, program* p, vertex_array* va, size_t count ) = 0;
+
 		virtual void draw( const render_state& rs, program* p, mesh_interface* mesh )
 		{
 			draw( mesh->get_primitive_type(), rs, p, mesh->get_vertex_array(), mesh->get_index_count() );
+		}
+		virtual void draw( const render_state& rs, const scene_state& s, program* p, mesh_interface* mesh )
+		{
+			p->apply_engine_uniforms( this, &s );
+			draw( rs, p, mesh );
+		}
+		virtual void draw( primitive prim, const render_state& rs, const scene_state& s, program* p, vertex_array* va, size_t count )
+		{
+			p->apply_engine_uniforms( this, &s );
+			draw( prim, rs, p, va, count );
 		}
 
@@ -64,5 +81,9 @@
 		virtual void set_viewport( const ivec4& viewport ) = 0;
 		virtual device* get_device() { return m_device; }
-		virtual ~context() {}
+		virtual ~context() 
+		{
+			// TODO: this will pose a problem in case of multiple contexts
+			program::destroy_engine_uniforms();
+		}
 	protected:
 		device*      m_device;
Index: trunk/nv/interface/program.hh
===================================================================
--- trunk/nv/interface/program.hh	(revision 231)
+++ trunk/nv/interface/program.hh	(revision 232)
@@ -1,3 +1,3 @@
-// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
+// Copyright (C) 2012-2014 ChaosForge / Kornel Kisielewicz
 // http://chaosforge.org/
 //
@@ -14,4 +14,5 @@
 
 #include <unordered_map>
+#include <nv/interface/uniform.hh>
 #include <nv/logging.hh>
 #include <nv/exception.hh>
@@ -22,4 +23,6 @@
 namespace nv
 {
+	class camera;
+
 	enum slot
 	{
@@ -30,4 +33,20 @@
 		TANGENT  = 4,
 	};
+
+	enum texture_slot
+	{
+		TEX_DIFFUSE  = 0,
+		TEX_SPECULAR = 1,
+		TEX_NORMAL   = 2,
+		TEXTURE_0    = 0,
+		TEXTURE_1    = 1,
+		TEXTURE_2    = 2,
+		TEXTURE_3    = 3,
+		TEXTURE_4    = 4,
+		TEXTURE_5    = 5,
+		TEXTURE_6    = 6,
+		TEXTURE_7    = 7,
+	};
+
 
 	class attribute
@@ -48,47 +67,4 @@
 	};
 
-	class uniform_base
-	{
-	public: 
-		uniform_base( const string& name, datatype type, int location, int length ) 
-			: m_name( name ), m_type( type ), m_location(location), m_length( length ), m_dirty( true ) {}
-		datatype get_type() const { return m_type; }
-		int get_location() const { return m_location; }
-		int get_length() const { return m_length; }
-		bool is_dirty() const { return m_dirty; }
-		void clean() { m_dirty = false; }
-	protected:
-		string   m_name;
-		datatype m_type;
-		int      m_location;
-		int      m_length;
-		bool     m_dirty;
-	};
-
-	template< typename T >
-	class uniform : public uniform_base
-	{
-	public:
-		typedef T value_type;
-
-		uniform( const string& name, int location, int length ) 
-			: uniform_base( name, type_to_enum< T >::type, location, length ), m_value()
-		{}
-
-		void set_value( const T& value ) 
-		{ 
-			if ( value != m_value )
-			{
-				m_value = value; 
-				m_dirty = true;
-			}
-		}
-
-		const T& get_value() { return m_value; }
-	protected:
-		T m_value;
-	};
-
-	typedef std::unordered_map< string, uniform_base* > uniform_map;
 	typedef std::unordered_map< string, attribute* >    attribute_map;
 
@@ -102,8 +78,6 @@
 		virtual ~program()
 		{
-			for ( attribute_map::iterator i = m_attribute_map.begin(); 
-				i != m_attribute_map.end(); ++i ) delete i->second;
-			for ( uniform_map::iterator i = m_uniform_map.begin(); 
-					i != m_uniform_map.end(); ++i ) delete i->second;
+			for ( auto& i : m_attribute_map )   delete i.second;
+			for ( auto& i : m_uniform_map )     delete i.second;
 		}
 
@@ -181,5 +155,89 @@
 			}
 		}
+
+		void apply_engine_uniforms( const context* ctx, const scene_state* s )
+		{
+			for ( auto u : m_engine_uniforms )
+			{
+				u->set( ctx, s );
+			}
+		}
+
+		void apply_link_engine_uniforms()
+		{
+			engine_link_uniform_factory_map& factory_map = get_link_uniform_factory();
+			for ( auto& i : m_uniform_map )
+			{
+				auto j = factory_map.find( i.first );
+				if ( j != factory_map.end() )
+				{
+					j->second->set( i.second );
+				}				
+			}
+		}
+
+		void bind_engine_uniforms()
+		{
+			engine_uniform_factory_map& factory_map = get_uniform_factory();
+			for ( auto& i : m_uniform_map )
+			{
+				auto j = factory_map.find( i.first );
+				if ( j != factory_map.end() )
+				{
+					m_engine_uniforms.push_back( j->second->create( i.second ) );
+				}				
+			}
+		}
+
+		// This is done this way to avoid compilation unit creation
+		static engine_uniform_factory_map& get_uniform_factory()
+		{
+			static engine_uniform_factory_map s_engine_uniform_factory_map;
+			return s_engine_uniform_factory_map;
+		}
+
+		// This is done this way to avoid compilation unit creation
+		static engine_link_uniform_factory_map& get_link_uniform_factory()
+		{
+			static engine_link_uniform_factory_map s_engine_link_uniform_factory_map;
+			return s_engine_link_uniform_factory_map;
+		}
+
+		static void initialize_engine_uniforms()
+		{
+			engine_uniform_factory_map& factory_map = get_uniform_factory();
+			factory_map[ "nv_m_view" ]       = new engine_uniform_factory< engine_uniform_m_view >();
+			factory_map[ "nv_m_view_inv" ]   = new engine_uniform_factory< engine_uniform_m_view_inv >();
+			factory_map[ "nv_m_view" ]       = new engine_uniform_factory< engine_uniform_m_view >();
+			factory_map[ "nv_m_model" ]      = new engine_uniform_factory< engine_uniform_m_model >();
+			factory_map[ "nv_m_modelview" ]  = new engine_uniform_factory< engine_uniform_m_modelview >();
+			factory_map[ "nv_m_projection" ] = new engine_uniform_factory< engine_uniform_m_projection >();
+			factory_map[ "nv_m_normal" ]     = new engine_uniform_factory< engine_uniform_m_normal >();
+			factory_map[ "nv_m_mvp" ]        = new engine_uniform_factory< engine_uniform_m_mvp >();
+
+			engine_link_uniform_factory_map& factory_link_map = get_link_uniform_factory();
+			factory_link_map[ "nv_texture_0" ] = new engine_link_uniform_int<0>();
+			factory_link_map[ "nv_texture_1" ] = new engine_link_uniform_int<1>();
+			factory_link_map[ "nv_texture_2" ] = new engine_link_uniform_int<2>();
+			factory_link_map[ "nv_texture_3" ] = new engine_link_uniform_int<3>();
+			factory_link_map[ "nv_texture_4" ] = new engine_link_uniform_int<4>();
+			factory_link_map[ "nv_texture_5" ] = new engine_link_uniform_int<5>();
+			factory_link_map[ "nv_texture_6" ] = new engine_link_uniform_int<6>();
+			factory_link_map[ "nv_texture_7" ] = new engine_link_uniform_int<7>();
+			factory_link_map[ "nv_t_diffuse" ] = new engine_link_uniform_int<0>();
+			factory_link_map[ "nv_t_specular"] = new engine_link_uniform_int<1>();
+			factory_link_map[ "nv_t_normal"  ] = new engine_link_uniform_int<2>();
+		}
+
+		static void destroy_engine_uniforms()
+		{
+			for ( auto& i : get_uniform_factory() ) delete i.second;
+			for ( auto& i : get_link_uniform_factory() ) delete i.second;
+			get_uniform_factory().clear();
+			get_link_uniform_factory().clear();
+		}
+
 	protected:
+
 		uniform_base* create_uniform( datatype utype, const string& name, int location, int length )
 		{
@@ -201,6 +259,7 @@
 		}
 
-		attribute_map m_attribute_map;
-		uniform_map   m_uniform_map;
+		attribute_map                     m_attribute_map;
+		uniform_map	                      m_uniform_map;
+		engine_uniform_list               m_engine_uniforms;
 	};
 
Index: trunk/nv/interface/uniform.hh
===================================================================
--- trunk/nv/interface/uniform.hh	(revision 232)
+++ trunk/nv/interface/uniform.hh	(revision 232)
@@ -0,0 +1,187 @@
+// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
+// http://chaosforge.org/
+//
+// This file is part of NV Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+/**
+ * @file uniform.hh
+ * @author Kornel Kisielewicz epyon@chaosforge.org
+ * @brief uniform classes
+ */
+
+#ifndef NV_UNIFORM_HH
+#define NV_UNIFORM_HH
+
+#include <unordered_map>
+#include <nv/interface/camera.hh>
+#include <nv/common.hh>
+#include <nv/string.hh>
+
+namespace nv
+{
+	class context;
+
+	class uniform_base
+	{
+	public: 
+		uniform_base( const string& name, datatype type, int location, int length ) 
+			: m_name( name ), m_type( type ), m_location(location), m_length( length ), m_dirty( true ) {}
+		datatype get_type() const { return m_type; }
+		int get_location() const { return m_location; }
+		int get_length() const { return m_length; }
+		bool is_dirty() const { return m_dirty; }
+		void clean() { m_dirty = false; }
+	protected:
+		string   m_name;
+		datatype m_type;
+		int      m_location;
+		int      m_length;
+		bool     m_dirty;
+	};
+
+	template< typename T >
+	class uniform : public uniform_base
+	{
+	public:
+		typedef T value_type;
+
+		uniform( const string& name, int location, int length ) 
+			: uniform_base( name, type_to_enum< T >::type, location, length ), m_value()
+		{}
+
+		void set_value( const T& value ) 
+		{ 
+			if ( value != m_value )
+			{
+				m_value = value; 
+				m_dirty = true;
+			}
+		}
+
+		const T& get_value() { return m_value; }
+	protected:
+		T m_value;
+	};
+
+	class engine_uniform_base
+	{
+	public:
+		virtual void set( const context* , const scene_state* ) = 0;
+		virtual ~engine_uniform_base() {}
+	};
+
+	template < typename T >
+	class engine_uniform : public engine_uniform_base
+	{
+	public:
+		typedef T          value_type;
+		typedef uniform<T> uniform_type;
+
+		engine_uniform( uniform_base* u ) : m_uniform( (uniform<T>*)u ) {}
+	protected:
+		uniform<T>* m_uniform;
+	};
+
+	class engine_uniform_factory_base
+	{
+	public:
+		virtual engine_uniform_base* create( uniform_base* ) = 0;
+		virtual ~engine_uniform_factory_base() {}
+	};
+
+	template < typename T >
+	class engine_uniform_factory : public engine_uniform_factory_base
+	{
+	public:
+		virtual engine_uniform_base* create( uniform_base* u )
+		{
+			return new T( u );
+		}
+	};
+
+	class engine_link_uniform_base
+	{
+	public:
+		virtual void set( uniform_base* ) = 0;
+		virtual ~engine_link_uniform_base() {}
+	};
+
+	template < typename T >
+	class engine_link_uniform : public engine_link_uniform_base
+	{
+	public:
+		typedef T          value_type;
+		typedef uniform<T> uniform_type;
+
+		engine_link_uniform() {}
+		virtual void set( uniform_base* u ) { set_impl( (uniform<T>*)u ); }
+		virtual void set_impl( uniform<T>* u ) = 0;
+	};
+
+	typedef std::unordered_map< string, uniform_base* >                uniform_map;
+	typedef std::vector< engine_uniform_base* >                        engine_uniform_list;
+	typedef std::unordered_map< string, engine_uniform_factory_base* > engine_uniform_factory_map;
+	typedef std::unordered_map< string, engine_link_uniform_base* >    engine_link_uniform_factory_map;
+
+	class engine_uniform_m_view : public engine_uniform< mat4 >
+	{
+	public:
+		engine_uniform_m_view( uniform_base* u ) : engine_uniform( u ) {}
+		virtual void set( const context* , const scene_state* s ) { m_uniform->set_value( s->get_view() ); }
+	};
+
+	class engine_uniform_m_view_inv : public engine_uniform< mat4 >
+	{
+	public:
+		engine_uniform_m_view_inv( uniform_base* u ) : engine_uniform( u ) {}
+		virtual void set( const context* , const scene_state* s ) { m_uniform->set_value( s->get_view_inv() ); }
+	};
+
+	class engine_uniform_m_model : public engine_uniform< mat4 >
+	{
+	public:
+		engine_uniform_m_model( uniform_base* u ) : engine_uniform( u ) {}
+		virtual void set( const context* , const scene_state* s ) { m_uniform->set_value( s->get_model() ); }
+	};
+
+	class engine_uniform_m_modelview : public engine_uniform< mat4 >
+	{
+	public:
+		engine_uniform_m_modelview( uniform_base* u ) : engine_uniform( u ) {}
+		virtual void set( const context* , const scene_state* s ) { m_uniform->set_value( s->get_modelview() ); }
+	};
+
+	class engine_uniform_m_projection : public engine_uniform< mat4 >
+	{
+	public:
+		engine_uniform_m_projection( uniform_base* u ) : engine_uniform( u ) {}
+		virtual void set( const context* , const scene_state* s ) { m_uniform->set_value( s->get_projection() ); }
+	};
+
+	class engine_uniform_m_normal : public engine_uniform< mat3 >
+	{
+	public:
+		engine_uniform_m_normal( uniform_base* u ) : engine_uniform( u ) {}
+		virtual void set( const context* , const scene_state* s ) { m_uniform->set_value( s->get_normal() ); }
+	};
+
+	class engine_uniform_m_mvp : public engine_uniform< mat4 >
+	{
+	public:
+		engine_uniform_m_mvp( uniform_base* u ) : engine_uniform( u ) {}
+		virtual void set( const context* , const scene_state* s ) { m_uniform->set_value( s->get_mvp() ); }
+	};
+
+	template< int VALUE >
+	class engine_link_uniform_int : public engine_link_uniform< int >
+	{
+	public:
+		engine_link_uniform_int() {}
+		virtual void set_impl( uniform<int>* u ) { u->set_value(VALUE); }
+	};
+
+
+
+}
+
+#endif // NV_UNIFORM_HH
Index: trunk/src/gl/gl_program.cc
===================================================================
--- trunk/src/gl/gl_program.cc	(revision 231)
+++ trunk/src/gl/gl_program.cc	(revision 232)
@@ -189,4 +189,7 @@
 		m_uniform_map[ name ] = create_uniform( utype, name, uni_loc, uni_len );
 	}
+
+	apply_link_engine_uniforms();
+	bind_engine_uniforms();
 }
 
