Index: trunk/nv/engine/program_manager.hh
===================================================================
--- trunk/nv/engine/program_manager.hh	(revision 316)
+++ trunk/nv/engine/program_manager.hh	(revision 316)
@@ -0,0 +1,40 @@
+// Copyright (C) 2014 ChaosForge Ltd
+// http://chaosforge.org/
+//
+// This file is part of NV Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+/**
+ * @file program_manager.hh
+ * @author Kornel Kisielewicz
+ * @brief program manager
+ */
+
+#ifndef NV_ENGINE_PROGRAM_MANAGER_HH
+#define NV_ENGINE_PROGRAM_MANAGER_HH
+
+#include <nv/common.hh>
+#include <nv/engine/resource_system.hh>
+
+namespace nv
+{
+
+	class program_manager : public resource_manager< program >
+	{
+	public:
+		program_manager( context* a_context );
+		virtual const char* get_storage_name() const { return "programs"; }
+		virtual const char* get_resource_name() const { return "program"; }
+	protected:
+		virtual resource_id load_resource( lua::table_guard& table );
+		void load_source( lua::table_guard& table, string& out, const string& append );
+		virtual void release( program p );
+	private:
+		context* m_context;
+		string   m_vertex_head;
+		string   m_fragment_head;
+	};
+
+}
+
+#endif // NV_ENGINE_PROGRAM_MANAGER_HH
Index: trunk/nv/engine/resource_system.hh
===================================================================
--- trunk/nv/engine/resource_system.hh	(revision 316)
+++ trunk/nv/engine/resource_system.hh	(revision 316)
@@ -0,0 +1,105 @@
+// Copyright (C) 2014 ChaosForge Ltd
+// http://chaosforge.org/
+//
+// This file is part of NV Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+/**
+ * @file resource_manager.hh
+ * @author Kornel Kisielewicz
+ * @brief engine resource manager
+ */
+
+#ifndef NV_ENGINE_RESOURCE_MANAGER_HH
+#define NV_ENGINE_RESOURCE_MANAGER_HH
+
+#include <nv/common.hh>
+#include <nv/interface/context.hh>
+#include <nv/lua/lua_state.hh>
+#include <unordered_map>
+
+namespace nv
+{
+
+	typedef uint32 resource_id;
+	typedef uint32 resource_type_id;
+
+	class resource_system;
+
+	class resource_manager_base
+	{
+	public:	
+		resource_manager_base() : m_lua( nullptr ) {}
+		void initialize( lua::state* state );
+		virtual const char* get_storage_name() const = 0;
+		virtual const char* get_resource_name() const = 0;
+		virtual void clear() { m_names.clear(); }
+		void load_all();
+		resource_id load_resource( const std::string& id );
+	protected:
+		virtual resource_id load_resource( lua::table_guard& table ) = 0;
+
+		lua::state* m_lua;
+		std::unordered_map< string, resource_id > m_names;
+	};
+
+	template < typename T >
+	class resource_manager : public resource_manager_base
+	{
+	public:
+		resource_manager() { m_data.push_back(T()); }
+		T get_resource( resource_id id )
+		{
+			return ( id < m_data.size() ? m_data[ id ] : T() );
+		}
+		T get_resource( const string& id )
+		{
+			auto m = m_names.find( id );
+			if ( m != m_names.end() )
+			{
+				return get_resource( m->second );
+			}
+			return get_resource( load_resource( id ) );
+		}
+		virtual void clear()
+		{
+			resource_manager_base::clear();
+			for ( uint32 i = 1; i < m_data.size(); ++i )
+				release( m_data[i] );
+			m_data.clear();
+			m_data.push_back( T() );
+		}
+		virtual ~resource_manager() 
+		{
+			clear();
+		}
+	protected:
+		virtual void release( T ) {}
+
+		resource_id add( T resource )
+		{
+			m_data.push_back( resource );
+			return m_data.size() - 1;
+		}
+
+		std::vector< T > m_data;
+	};
+
+
+	class resource_system
+	{
+	public:
+		explicit resource_system() : m_lua_state( nullptr ) { m_managers.push_back(nullptr); }
+		resource_type_id register_resource_type( const string& name, resource_manager_base* manager );
+		resource_type_id get_resource_type_id( const string& name ) const;
+		void initialize( lua::state* a_lua_state );
+		virtual ~resource_system();
+	protected:
+		std::vector< resource_manager_base* >     m_managers;
+		std::unordered_map< string, resource_id > m_manager_names;
+		lua::state* m_lua_state; 
+	};
+
+}
+
+#endif // NV_ENGINE_RESOURCE_MANAGER_HH
Index: trunk/nv/gl/gl_device.hh
===================================================================
--- trunk/nv/gl/gl_device.hh	(revision 315)
+++ trunk/nv/gl/gl_device.hh	(revision 316)
@@ -58,4 +58,5 @@
 		virtual int get_attribute_location( program p, const string& name, bool fatal = true ) const;
 		virtual void prepare_program( program p );
+		virtual const string& get_shader_header() const { return m_shader_header; }
 		virtual ~gl_device();
 	protected:
@@ -69,5 +70,5 @@
 		void load_uniforms( gl_program_info* p );
 		bool compile( uint32 sh_type, const std::string& shader_code, unsigned& glid );
-
+		std::string m_shader_header;
 		const void* m_info;
 		entity_store< gl_texture_info, texture >         m_textures;
Index: trunk/nv/gl/gl_enum.hh
===================================================================
--- trunk/nv/gl/gl_enum.hh	(revision 315)
+++ trunk/nv/gl/gl_enum.hh	(revision 316)
@@ -41,4 +41,5 @@
 	unsigned int datatype_to_gl_enum( datatype type );
 	datatype gl_enum_to_datatype( unsigned int gl_enum );
+	std::string datatype_to_glsl_type( datatype type );
 
 } // namespace nv
Index: trunk/nv/interface/device.hh
===================================================================
--- trunk/nv/interface/device.hh	(revision 315)
+++ trunk/nv/interface/device.hh	(revision 316)
@@ -144,4 +144,5 @@
 		virtual uint32 get_ticks() = 0;
 		virtual void delay( uint32 ms ) = 0;
+		virtual const string& get_shader_header() const = 0;
 
 		virtual texture create_texture( image_data* data, sampler asampler ) 
Index: trunk/nv/interface/uniform.hh
===================================================================
--- trunk/nv/interface/uniform.hh	(revision 315)
+++ trunk/nv/interface/uniform.hh	(revision 316)
@@ -114,4 +114,5 @@
 	public:
 		virtual engine_uniform_base* create( uniform_base* ) = 0;
+		virtual datatype get_datatype() const = 0;
 		virtual ~engine_uniform_factory_base() {}
 	};
@@ -125,4 +126,5 @@
 			return new T( u );
 		}
+		virtual datatype get_datatype() const { return type_to_enum<typename T::value_type>::type; }
 	};
 
Index: trunk/nv/lua/lua_nova.hh
===================================================================
--- trunk/nv/lua/lua_nova.hh	(revision 315)
+++ trunk/nv/lua/lua_nova.hh	(revision 316)
@@ -13,4 +13,5 @@
 	namespace lua
 	{
+		void register_storage( state* a_state, const string& name, const string& constructor_name );
 		void register_nova( state* a_state );
 	}
Index: trunk/src/engine/program_manager.cc
===================================================================
--- trunk/src/engine/program_manager.cc	(revision 316)
+++ trunk/src/engine/program_manager.cc	(revision 316)
@@ -0,0 +1,63 @@
+// Copyright (C) 2014 ChaosForge Ltd
+// http://chaosforge.org/
+//
+// This file is part of NV Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+#include "nv/engine/program_manager.hh"
+#include "nv/range.hh"
+#include "nv/lua/lua_nova.hh"
+
+nv::program_manager::program_manager( context* a_context ) : m_context( a_context )
+{
+	m_vertex_head   = a_context->get_device()->get_shader_header();
+	m_fragment_head = a_context->get_device()->get_shader_header();
+}
+
+nv::resource_id nv::program_manager::load_resource( lua::table_guard& table )
+{
+	NV_LOG( LOG_DEBUG, table.get_string("id") );
+	std::string vsource;
+	std::string fsource;
+	std::string csource;
+	if ( table.is_table("common") )
+	{
+		lua::table_guard common( table, "common" );
+		load_source( common, csource, "" );
+	}
+	{
+		lua::table_guard vtable( table, "vertex" );
+		load_source( vtable, vsource, m_vertex_head+"\n"+csource+"\n");
+	}
+	{
+		lua::table_guard ftable( table, "fragment" );
+		load_source( ftable, fsource, m_fragment_head+"\n"+csource+"\n" );
+	}
+
+	nv::program program = m_context->get_device()->create_program( vsource, fsource );
+	return add( program );
+}
+
+void nv::program_manager::release( program p )
+{
+	m_context->get_device()->release( p );
+}
+
+void nv::program_manager::load_source( lua::table_guard& table, string& out, const string& append )
+{
+	out = append;
+	std::string include;
+	if ( table.is_string( "include" ) )
+	{
+		out += nv::slurp( table.get_string( "include" ) );
+	}
+
+	if ( table.is_string( "file" ) )
+	{
+		out += "#line 1\n"+nv::slurp( table.get_string( "file" ) );
+	}
+	else if ( table.is_string( "source" ) )
+	{
+		out += table.get_string( "source" );
+	}
+}
Index: trunk/src/engine/resource_system.cc
===================================================================
--- trunk/src/engine/resource_system.cc	(revision 316)
+++ trunk/src/engine/resource_system.cc	(revision 316)
@@ -0,0 +1,58 @@
+// Copyright (C) 2014 ChaosForge Ltd
+// http://chaosforge.org/
+//
+// This file is part of NV Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+#include "nv/engine/resource_system.hh"
+#include "nv/range.hh"
+#include "nv/lua/lua_nova.hh"
+
+void nv::resource_manager_base::initialize( lua::state* a_lua_state )
+{
+	m_lua = a_lua_state;
+	std::string constructor_name( get_resource_name() );
+	constructor_name = "register_"+constructor_name;
+	lua::register_storage( m_lua, get_storage_name(), constructor_name.c_str() );
+}
+
+nv::resource_id nv::resource_manager_base::load_resource( const std::string& id )
+{
+	lua::table_guard table( m_lua, lua::path( get_storage_name(), id ) );
+	resource_id rid = load_resource( table );
+	if ( rid != 0 ) m_names[ id ] = rid;
+	return rid;
+}
+
+void nv::resource_manager_base::load_all()
+{
+	clear();
+	lua::table_guard table( m_lua, get_storage_name() );
+	uint32 count = table.get_integer( "__counter" );
+	for ( auto i : range( count ) )
+	{
+		lua::table_guard sub_table( table, i+1 );
+		resource_id rid = load_resource( sub_table );
+		if ( rid != 0 ) m_names[ sub_table.get_string("id") ] = rid;
+	}
+}
+
+nv::resource_type_id nv::resource_system::register_resource_type( const string& name, resource_manager_base* manager )
+{
+	return 0;
+}
+
+nv::resource_type_id nv::resource_system::get_resource_type_id( const string& name ) const
+{
+	return 0;
+}
+
+void nv::resource_system::initialize( lua::state* a_lua_state )
+{
+
+}
+
+nv::resource_system::~resource_system()
+{
+
+}
Index: trunk/src/gl/gl_device.cc
===================================================================
--- trunk/src/gl/gl_device.cc	(revision 315)
+++ trunk/src/gl/gl_device.cc	(revision 316)
@@ -47,4 +47,9 @@
 #endif
 
+	m_shader_header  = "#version 120\n";
+	for ( auto& i : get_uniform_factory() ) 
+		m_shader_header += "uniform "+datatype_to_glsl_type( i.second->get_datatype() )+" "+i.first+";\n";
+	for ( auto& i : get_link_uniform_factory() ) 
+		m_shader_header += "uniform sampler2D "+i.first+";\n";
 }
 
Index: trunk/src/gl/gl_enum.cc
===================================================================
--- trunk/src/gl/gl_enum.cc	(revision 315)
+++ trunk/src/gl/gl_enum.cc	(revision 316)
@@ -277,2 +277,21 @@
 	}
 }
+
+std::string nv::datatype_to_glsl_type( datatype type )
+{
+	switch( type )
+	{
+	case INT            : return "int";
+	case FLOAT          : return "float";
+	case FLOAT_VECTOR_2 : return "vec2";
+	case FLOAT_VECTOR_3 : return "vec3";
+	case FLOAT_VECTOR_4 : return "vec4";
+	case FLOAT_MATRIX_2 : return "mat2";
+	case FLOAT_MATRIX_3 : return "mat3";
+	case FLOAT_MATRIX_4 : return "mat4";
+	case INT_VECTOR_2   : return "ivec2";
+	case INT_VECTOR_3   : return "ivec3";
+	case INT_VECTOR_4   : return "ivec4";
+	default : return "error";
+	}
+}
Index: trunk/src/lua/lua_nova.cc
===================================================================
--- trunk/src/lua/lua_nova.cc	(revision 315)
+++ trunk/src/lua/lua_nova.cc	(revision 316)
@@ -680,5 +680,5 @@
 	lua_rawget( L, -2 );
 
-	if ( !lua_isnil( L, -1 ) ) luaL_error( L, "lua.nova - storage \"%s\" already registered!", lua_tolstring( L, lua_upvalueindex(1), 0 ) );
+	if ( !lua_isnil( L, -1 ) ) luaL_error( L, "lua.nova - storage \"%s\" already registered!", lua_tolstring( L, 1, 0 ) );
 
 	lua_newtable( L ); // g t
@@ -805,2 +805,15 @@
 	lua_settop( L, stack );
 }
+
+void nv::lua::register_storage( state* a_state, const string& name, const string& constructor_name )
+{
+	// TODO: error checking
+	lua_State* L = a_state->get_raw();
+	int stack = lua_gettop( L );
+	// TODO: check if nova is loaded
+	lua_pushcfunction( L, nova_register_storage );
+	lua_pushstring( L, name.c_str() );
+	lua_call( L, 1, 1 );
+	lua_setglobal( L, constructor_name.c_str() );
+	lua_settop( L, stack );
+}
