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 );
+}
