Index: trunk/src/gfx/debug_draw.cc
===================================================================
--- trunk/src/gfx/debug_draw.cc	(revision 302)
+++ trunk/src/gfx/debug_draw.cc	(revision 303)
@@ -29,5 +29,5 @@
 
 nv::debug_data::debug_data( device* a_device )
-	: m_device( a_device ), m_program( nullptr ), m_va()
+	: m_device( a_device ), m_program(), m_va()
 {
 	m_program = m_device->create_program( nv_debug_draw_vertex_shader, nv_debug_draw_fragment_shader );
@@ -76,4 +76,4 @@
 {
 	m_device->release( m_va );
-	delete m_program;
+	m_device->release( m_program );
 }
Index: trunk/src/gfx/keyframed_mesh.cc
===================================================================
--- trunk/src/gfx/keyframed_mesh.cc	(revision 302)
+++ trunk/src/gfx/keyframed_mesh.cc	(revision 303)
@@ -98,7 +98,7 @@
 
 
-void nv::keyframed_mesh::update( program* a_program )
-{
-	a_program->set_opt_uniform( "nv_interpolate", m_interpolation );
+void nv::keyframed_mesh::update( program a_program )
+{
+	m_context->get_device()->set_opt_uniform( a_program, "nv_interpolate", m_interpolation );
 }
 
@@ -165,14 +165,14 @@
 }
 
-void nv::keyframed_mesh_gpu::update( program* a_program )
+void nv::keyframed_mesh_gpu::update( program a_program )
 {
 	if ( m_loc_next_position == -1 )
 	{
-		m_loc_next_position = a_program->get_attribute( "nv_next_position" )->get_location();
-		m_loc_next_normal   = a_program->get_attribute( "nv_next_normal" )->get_location();
+		device* dev = m_context->get_device();
+		m_loc_next_position = dev->get_attribute_location( a_program, "nv_next_position" );
+		m_loc_next_normal   = dev->get_attribute_location( a_program, "nv_next_normal" );
 		if ( m_has_tangent )
-			m_loc_next_tangent  = a_program->get_attribute( "nv_next_tangent" )->get_location();
-
-		device* dev = m_context->get_device();
+			m_loc_next_tangent  = dev->get_attribute_location( a_program, "nv_next_tangent" );
+
 		dev->add_vertex_buffer( m_va, (slot)m_loc_next_position, m_pbuffer, FLOAT, 3, 0, m_vsize, false );
 		dev->add_vertex_buffer( m_va, (slot)m_loc_next_normal,   m_pbuffer, FLOAT, 3, sizeof( vec3 ), m_vsize, false );
Index: trunk/src/gfx/skeletal_mesh.cc
===================================================================
--- trunk/src/gfx/skeletal_mesh.cc	(revision 302)
+++ trunk/src/gfx/skeletal_mesh.cc	(revision 303)
@@ -213,8 +213,8 @@
 }
 
-void nv::skeletal_mesh_gpu::update( program* a_program )
+void nv::skeletal_mesh_gpu::update( program a_program )
 {
 	if ( m_bone_data )
-		a_program->set_opt_uniform_array( "nv_m_bones", m_transform, m_bone_data->get_count() );
+		m_context->get_device()->set_opt_uniform_array( a_program, "nv_m_bones", m_transform, m_bone_data->get_count() );
 }
 
Index: trunk/src/gl/gl_context.cc
===================================================================
--- trunk/src/gl/gl_context.cc	(revision 302)
+++ trunk/src/gl/gl_context.cc	(revision 303)
@@ -9,5 +9,4 @@
 #include "nv/lib/sdl.hh"
 #include "nv/gl/gl_device.hh"
-#include "nv/gl/gl_program.hh"
 
 using namespace nv;
@@ -23,9 +22,12 @@
 }
 
-void nv::gl_context::bind( program* p )
-{
-	gl_program* glp = static_cast< gl_program* >( p );
-	glUseProgram( glp->glid );
-	glp->update_uniforms();
+void nv::gl_context::bind( program p )
+{
+	gl_program_info* info = ((gl_device*)m_device)->m_programs.get( p );
+	if ( info )
+	{
+		glUseProgram( info->glid );
+		((gl_device*)m_device)->update_uniforms( info );
+	}
 }
 
@@ -41,5 +43,5 @@
 void nv::gl_context::bind( vertex_array va )
 {
-	vertex_array_info* info = get_vertex_array_info( va );
+	const vertex_array_info* info = m_device->get_vertex_array_info( va );
 	if ( info )
 	{
@@ -68,5 +70,5 @@
 }
 
-void nv::gl_context::unbind( program* )
+void nv::gl_context::unbind( program )
 {
 	glUseProgram( 0 );
@@ -84,5 +86,5 @@
 void nv::gl_context::unbind( vertex_array va )
 {
-	vertex_array_info* info = get_vertex_array_info( va );
+	const vertex_array_info* info = m_device->get_vertex_array_info( va );
 	if ( info )
 	{
@@ -483,8 +485,20 @@
 }
 
-void gl_context::draw( primitive prim, const render_state& rs, program* p, vertex_array va, size_t count )
+void nv::gl_context::apply_engine_uniforms( program p, const scene_state& s )
+{
+	gl_program_info* info = ((gl_device*)m_device)->m_programs.get( p );
+	if ( info )
+	{
+		for ( auto u : info->m_engine_uniforms )
+		{
+			u->set( this, &s );
+		}
+	}
+}
+
+void gl_context::draw( primitive prim, const render_state& rs, program p, vertex_array va, size_t count )
 {
 	apply_render_state( rs );
-	vertex_array_info* info = get_vertex_array_info( va );
+	const vertex_array_info* info = m_device->get_vertex_array_info( va );
 	if ( count > 0 && info )
 	{
Index: trunk/src/gl/gl_device.cc
===================================================================
--- trunk/src/gl/gl_device.cc	(revision 302)
+++ trunk/src/gl/gl_device.cc	(revision 303)
@@ -6,5 +6,4 @@
 
 #include "nv/gl/gl_window.hh"
-#include "nv/gl/gl_program.hh"
 #include "nv/logging.hh"
 #include "nv/lib/sdl.hh"
@@ -50,7 +49,13 @@
 }
 
-program* gl_device::create_program( const string& vs_source, const string& fs_source )
-{
-	return new gl_program( vs_source, fs_source );
+program gl_device::create_program( const string& vs_source, const string& fs_source )
+{
+	program result = m_programs.create();
+	gl_program_info* info = m_programs.get( result );
+
+	info->glid = glCreateProgram();
+	compile( info, vs_source, fs_source );
+	prepare_program( result );
+	return result;
 }
 
@@ -85,8 +90,12 @@
 gl_device::~gl_device()
 {
+	while ( m_vertex_arrays.size() > 0 )
+		release( m_vertex_arrays.get_handle(0) );
 	while ( m_textures.size() > 0 )
 		release( m_textures.get_handle(0) );
 	while ( m_buffers.size() > 0 )
 		release( m_buffers.get_handle(0) );
+	while ( m_programs.size() > 0 )
+		release( m_programs.get_handle(0) );
 
 	SDL_Quit();
@@ -154,5 +163,5 @@
 }
 
-const texture_info* nv::gl_device::get_texture_info( texture t )
+const texture_info* nv::gl_device::get_texture_info( texture t ) const
 {
 	return m_textures.get( t );
@@ -178,6 +187,301 @@
 }
 
-const buffer_info* nv::gl_device::get_buffer_info( buffer t )
+const buffer_info* nv::gl_device::get_buffer_info( buffer t ) const
 {
 	return m_buffers.get( t );
 }
+
+nv::vertex_array nv::gl_device::create_vertex_array()
+{
+	vertex_array result = m_vertex_arrays.create();
+	vertex_array_info* info = m_vertex_arrays.get( result );
+	info->count       = 0;
+	info->index       = buffer();
+	info->index_owner = false;
+	info->index_type  = USHORT;
+	return result;
+}
+
+void nv::gl_device::release( vertex_array va )
+{
+	vertex_array_info* info = m_vertex_arrays.get( va );
+	if ( info )
+	{
+		for ( uint32 i = 0; i < info->count; ++i )
+		{
+			if ( info->attr[i].owner ) release( info->attr[i].vbuffer );
+		}
+		if ( info->index.is_valid() && info->index_owner) release( info->index );
+		m_vertex_arrays.destroy( va );
+	}
+}
+
+void nv::gl_device::release( program p )
+{
+	gl_program_info* info = m_programs.get( p );
+	if ( info )
+	{
+		for ( auto& i : info->m_uniform_map )
+			delete i.second;
+
+		glDetachShader( info->glid, info->glidv );
+		glDetachShader( info->glid, info->glidf );
+		glDeleteShader( info->glidv );
+		glDeleteShader( info->glidf );
+		glDeleteProgram( info->glid );
+
+		m_programs.destroy( p );
+	}
+}
+
+const vertex_array_info* nv::gl_device::get_vertex_array_info( vertex_array va ) const 
+{
+	return m_vertex_arrays.get( va );
+}
+
+vertex_array_info* nv::gl_device::get_vertex_array_info_mutable( vertex_array va ) 
+{
+	return m_vertex_arrays.get( va );
+}
+
+void nv::gl_device::prepare_program( program p )
+{
+	gl_program_info* info = m_programs.get( p );
+	if ( info )
+	{
+		auto& map  = get_uniform_factory();
+		auto& lmap = get_link_uniform_factory();
+
+		for ( auto& i : info->m_uniform_map )
+		{
+			auto j = lmap.find( i.first );
+			if ( j != lmap.end() )
+			{
+				j->second->set( i.second );
+			}			
+
+			auto k = map.find( i.first );
+			if ( k != map.end() )
+			{
+				info->m_engine_uniforms.push_back( k->second->create( i.second ) );
+			}				
+		}
+	}
+}
+
+uniform_base* nv::gl_device::get_uniform( program p, const string& name, bool fatal /*= true */ ) const
+{
+	const gl_program_info* info = m_programs.get( p );
+	{
+		uniform_map::const_iterator i = info->m_uniform_map.find( name );
+		if ( i != info->m_uniform_map.end() )
+		{
+			return i->second;
+		}
+		if ( fatal )
+		{
+			NV_LOG( LOG_ERROR, "Uniform '" << name << "' not found in program!" );
+			NV_THROW( runtime_error, ( "Uniform '"+name+"' not found!" ) );
+		}
+	}
+	return nullptr;
+}
+
+int nv::gl_device::get_attribute_location( program p, const string& name, bool fatal /*= true */ ) const
+{
+	const gl_program_info* info = m_programs.get( p );
+	if ( info )
+	{
+		attribute_map::const_iterator i = info->m_attribute_map.find( name );
+		if ( i != info->m_attribute_map.end() )
+		{
+			return i->second.location;
+		}
+		if ( fatal )
+		{
+			NV_LOG( LOG_ERROR, "Attribute '" << name << "' not found in program!" );
+			NV_THROW( runtime_error, ( "Attribute '"+name+"' not found!" ) );
+		}
+	}
+	return -1;
+}
+
+bool nv::gl_device::compile( gl_program_info* p, const string& vertex_program, const string& fragment_program )
+{
+	if (!compile( GL_VERTEX_SHADER,   vertex_program, p->glidv ))   { return false; }
+	if (!compile( GL_FRAGMENT_SHADER, fragment_program, p->glidf )) { return false; }
+
+	glBindAttribLocation( p->glid, static_cast<GLuint>( slot::POSITION   ), "nv_position"  );
+	glBindAttribLocation( p->glid, static_cast<GLuint>( slot::TEXCOORD   ), "nv_texcoord"  );
+	glBindAttribLocation( p->glid, static_cast<GLuint>( slot::NORMAL     ), "nv_normal"    );
+	glBindAttribLocation( p->glid, static_cast<GLuint>( slot::COLOR      ), "nv_color"     );
+	glBindAttribLocation( p->glid, static_cast<GLuint>( slot::TANGENT    ), "nv_tangent"   );
+	glBindAttribLocation( p->glid, static_cast<GLuint>( slot::BONEINDEX  ), "nv_boneindex" );
+	glBindAttribLocation( p->glid, static_cast<GLuint>( slot::BONEWEIGHT ), "nv_boneweight");
+
+	glAttachShader( p->glid, p->glidf );
+	glAttachShader( p->glid, p->glidv );
+	glLinkProgram( p->glid );
+
+	const uint32 buffer_size = 2048;
+	char buffer[ buffer_size ] = { 0 };
+	int length;
+	int status;
+
+	glGetProgramiv( p->glid, GL_LINK_STATUS, &status );
+	glGetProgramInfoLog( p->glid, buffer_size, &length, buffer );
+
+	NV_LOG( LOG_INFO, "Program #" << p->glid << (status == GL_FALSE ? " failed to compile!" : " compiled successfully.") );
+
+	if ( length > 0 )
+	{
+		NV_LOG( LOG_INFO, "Program #" << p->glid << " log: " << buffer );
+	}
+
+	if ( status == GL_FALSE ) 
+	{
+		return false;
+	}
+
+	glValidateProgram( p->glid );
+	glGetProgramiv( p->glid, GL_VALIDATE_STATUS, &status );
+
+	if ( status == GL_FALSE )
+	{
+		glGetProgramInfoLog( p->glid, buffer_size, &length, buffer );
+		NV_LOG( LOG_ERROR, "Program #" << p->glid << " validation error : " << buffer );
+		return false;
+	}
+	load_attributes( p );
+	load_uniforms( p );
+	return true;
+}
+
+void nv::gl_device::update_uniforms( gl_program_info* p )
+{
+	for ( uniform_map::iterator i = p->m_uniform_map.begin(); 	i != p->m_uniform_map.end(); ++i ) 
+	{
+		uniform_base* ubase = i->second;
+		if ( ubase->is_dirty() )
+		{
+			int uloc = ubase->get_location();
+			switch( ubase->get_type() )
+			{
+			case FLOAT          : glUniform1fv( uloc, ubase->get_length(), ((uniform< enum_to_type< FLOAT >::type >*)( ubase ))->get_value() ); break;
+			case INT            : glUniform1iv( uloc, ubase->get_length(), ((uniform< enum_to_type< INT >::type >*)( ubase ))->get_value() ); break;
+			case FLOAT_VECTOR_2 : glUniform2fv( uloc, ubase->get_length(), (GLfloat*)((uniform< enum_to_type< FLOAT_VECTOR_2 >::type >*)( ubase ))->get_value()); break;
+			case FLOAT_VECTOR_3 : glUniform3fv( uloc, ubase->get_length(), (GLfloat*)((uniform< enum_to_type< FLOAT_VECTOR_3 >::type >*)( ubase ))->get_value()); break;
+			case FLOAT_VECTOR_4 : glUniform4fv( uloc, ubase->get_length(), (GLfloat*)((uniform< enum_to_type< FLOAT_VECTOR_4 >::type >*)( ubase ))->get_value()); break;
+			case INT_VECTOR_2   : glUniform2iv( uloc, ubase->get_length(), (GLint*)((uniform< enum_to_type< INT_VECTOR_2 >::type >*)( ubase ))->get_value()); break;
+			case INT_VECTOR_3   : glUniform3iv( uloc, ubase->get_length(), (GLint*)((uniform< enum_to_type< INT_VECTOR_3 >::type >*)( ubase ))->get_value()); break;
+			case INT_VECTOR_4   : glUniform4iv( uloc, ubase->get_length(), (GLint*)((uniform< enum_to_type< INT_VECTOR_4 >::type >*)( ubase ))->get_value()); break;
+			case FLOAT_MATRIX_2 : glUniformMatrix2fv( uloc, ubase->get_length(), GL_FALSE, (GLfloat*)((uniform< enum_to_type< FLOAT_MATRIX_2 >::type >*)( ubase ))->get_value()); break;
+			case FLOAT_MATRIX_3 : glUniformMatrix3fv( uloc, ubase->get_length(), GL_FALSE, (GLfloat*)((uniform< enum_to_type< FLOAT_MATRIX_3 >::type >*)( ubase ))->get_value()); break;
+			case FLOAT_MATRIX_4 : glUniformMatrix4fv( uloc, ubase->get_length(), GL_FALSE, (GLfloat*)((uniform< enum_to_type< FLOAT_MATRIX_4 >::type >*)( ubase ))->get_value()); break;
+			default : break; // error?
+			}
+			ubase->clean();
+		}
+	}
+}
+
+void nv::gl_device::load_attributes( gl_program_info* p )
+{
+	int params;
+	glGetProgramiv( p->glid, GL_ACTIVE_ATTRIBUTES, &params );
+
+	for ( unsigned i = 0; i < (unsigned)params; ++i )
+	{
+		int attr_nlen;
+		int attr_len;
+		unsigned attr_type;
+		char name_buffer[128];
+
+		glGetActiveAttrib( p->glid, i, 128, &attr_nlen, &attr_len, &attr_type, name_buffer );
+
+		string name( name_buffer, size_t(attr_nlen) );
+
+		// skip built-ins
+		if ( name.substr(0,3) == "gl_" ) continue;
+
+		int attr_loc = glGetAttribLocation( p->glid, name.c_str() );
+
+		attribute& attr = p->m_attribute_map[ name ];
+		attr.name     = name;
+		attr.location = attr_loc;
+		attr.type     = gl_enum_to_datatype( attr_type );
+		attr.length   = attr_len;
+	}
+}
+
+void nv::gl_device::load_uniforms( gl_program_info* p )
+{
+	int params;
+	glGetProgramiv( p->glid, GL_ACTIVE_UNIFORMS, &params );
+
+	for ( unsigned i = 0; i < size_t(params); ++i )
+	{
+		int uni_nlen;
+		int uni_len;
+		unsigned uni_type;
+		char name_buffer[128];
+
+		glGetActiveUniform( p->glid, i, 128, &uni_nlen, &uni_len, &uni_type, name_buffer );
+
+		string name( name_buffer, size_t(uni_nlen) );
+
+		// skip built-ins
+		if ( name.substr(0,3) == "gl_" ) continue;
+
+		int uni_loc = glGetUniformLocation( p->glid, name.c_str() );
+		datatype utype = gl_enum_to_datatype( uni_type );
+
+		// check for array
+		string::size_type arrchar = name.find('[');
+		if ( arrchar != string::npos )
+		{
+			name = name.substr( 0, arrchar );
+		}
+
+		uniform_base* u = uniform_base::create( utype, name, uni_loc, uni_len );
+		NV_ASSERT( u, "Unknown uniform type!" );
+		p->m_uniform_map[ name ] = u;
+	}
+}
+
+bool nv::gl_device::compile( uint32 sh_type, const std::string& shader_code, unsigned& glid )
+{
+	glid = glCreateShader( sh_type );
+
+	const char* pc = shader_code.c_str();
+
+	glShaderSource( glid,   1, &pc, 0 );
+	glCompileShader( glid );
+
+	const uint32 buffer_size = 1024;
+	char buffer[ buffer_size ] = { 0 };
+	int length;
+	int compile_ok = GL_FALSE;
+	glGetShaderiv(glid, GL_COMPILE_STATUS, &compile_ok);
+	glGetShaderInfoLog( glid, buffer_size, &length, buffer );
+
+	if ( length > 0 )
+	{
+		if ( compile_ok == 0 )
+		{
+			NV_LOG( LOG_ERROR, "Shader #" << glid << " error: " << buffer );
+		}
+		else
+		{
+			NV_LOG( LOG_INFO, "Shader #" << glid << " compiled successfully: " << buffer );
+		}
+	}
+	else
+	{
+		NV_LOG( LOG_INFO, "Shader #" << glid << " compiled successfully." );
+	}
+	return compile_ok != 0;
+
+}
+
+
Index: trunk/src/gl/gl_program.cc
===================================================================
--- trunk/src/gl/gl_program.cc	(revision 302)
+++ 	(revision )
@@ -1,263 +1,0 @@
-// Copyright (C) 2012-2013 Kornel Kisielewicz
-// This file is part of NV Libraries.
-// For conditions of distribution and use, see copyright notice in nv.hh
-
-#include "nv/gl/gl_program.hh"
-
-#include "nv/gl/gl_enum.hh"
-#include "nv/logging.hh"
-#include "nv/lib/gl.hh"
-
-#include <glm/glm.hpp>
-#include <glm/gtc/type_ptr.hpp>
-
-using namespace nv;
-
-gl_shader::gl_shader( uint32 sh_type ) 
-	: shader_type( sh_type ), object_id(0)
-{
-	// no op
-}
-
-gl_shader::gl_shader( uint32 sh_type, const string& shader_code )
-	: shader_type( sh_type ), object_id(0)
-{
-	compile( shader_code );
-}
-
-gl_shader::~gl_shader()
-{
-	free();
-}
-
-bool gl_shader::compile( const string& shader_code )
-{
-	generate();
-
-	const char* pc = shader_code.c_str();
-
-	glShaderSource( object_id,   1, &pc, 0 );
-	glCompileShader( object_id );
-
-	return validate();
-}
-
-void gl_shader::generate()
-{
-	if ( is_valid() )
-	{
-		free();
-	}
-	object_id = glCreateShader( shader_type );
-}
-
-void gl_shader::free()
-{
-	glDeleteShader( object_id );
-	object_id = 0;
-}
-
-bool gl_shader::validate()
-{
-	const uint32 buffer_size = 1024;
-	char buffer[ buffer_size ] = { 0 };
-	int length;
-	int compile_ok = GL_FALSE;
-	glGetShaderiv(object_id, GL_COMPILE_STATUS, &compile_ok);
-	glGetShaderInfoLog( object_id, buffer_size, &length, buffer );
-
-	if ( length > 0 )
-	{
-		if ( compile_ok == 0 )
-		{
-			NV_LOG( LOG_ERROR, "Shader #" << object_id << " error: " << buffer );
-		}
-		else
-		{
-			NV_LOG( LOG_INFO, "Shader #" << object_id << " compiled successfully: " << buffer );
-		}
-	}
-	else
-	{
-		NV_LOG( LOG_INFO, "Shader #" << object_id << " compiled successfully." );
-	}
-	return compile_ok != 0;
-}
-
-gl_program::gl_program( const string& vertex_program, const string& fragment_program )
-	: vertex_shader( GL_VERTEX_SHADER ), fragment_shader( GL_FRAGMENT_SHADER )
-{
-	glid = glCreateProgram();
-	compile( vertex_program, fragment_program );
-}
-
-gl_program::~gl_program()
-{
-	if ( glid != 0 )
-	{
-		// Detach the shaders from the program
-		glDetachShader( glid, vertex_shader.get_id() );
-		glDetachShader( glid, fragment_shader.get_id() );
-		glDeleteProgram( glid );
-	}
-}
-
-bool gl_program::compile( const string& vertex_program, const string& fragment_program )
-{
-	if (!vertex_shader.compile( vertex_program )) { return false; }
-	if (!fragment_shader.compile( fragment_program )) { return false; }
-
-	glBindAttribLocation( glid, static_cast<GLuint>( slot::POSITION   ), "nv_position"  );
-	glBindAttribLocation( glid, static_cast<GLuint>( slot::TEXCOORD   ), "nv_texcoord"  );
-	glBindAttribLocation( glid, static_cast<GLuint>( slot::NORMAL     ), "nv_normal"    );
-	glBindAttribLocation( glid, static_cast<GLuint>( slot::COLOR      ), "nv_color"     );
-	glBindAttribLocation( glid, static_cast<GLuint>( slot::TANGENT    ), "nv_tangent"   );
-	glBindAttribLocation( glid, static_cast<GLuint>( slot::BONEINDEX  ), "nv_boneindex" );
-	glBindAttribLocation( glid, static_cast<GLuint>( slot::BONEWEIGHT ), "nv_boneweight");
-
-	glAttachShader( glid, fragment_shader.get_id() );
-	glAttachShader( glid, vertex_shader.get_id() );
-	glLinkProgram( glid );
-
-	if (!validate())
-	{
-		return false;
-	}
-	load_attributes();
-	load_uniforms();
-	return true;
-}
-
-bool gl_program::is_valid() const
-{
-	return glid != 0;
-}
-
-void gl_program::load_attributes()
-{
-	int params;
-	glGetProgramiv( glid, GL_ACTIVE_ATTRIBUTES, &params );
-
-	for ( unsigned i = 0; i < (unsigned)params; ++i )
-	{
-		int attr_nlen;
-		int attr_len;
-		unsigned attr_type;
-		char name_buffer[128];
-
-		glGetActiveAttrib( glid, i, 128, &attr_nlen, &attr_len, &attr_type, name_buffer );
-
-		string name( name_buffer, size_t(attr_nlen) );
-
-		// skip built-ins
-		if ( name.substr(0,3) == "gl_" ) continue;
-
-		int attr_loc = glGetAttribLocation( glid, name.c_str() );
-
-		m_attribute_map[ name ] = new attribute( name, attr_loc, gl_enum_to_datatype( attr_type ), attr_len );
-	}
-}
-
-void gl_program::load_uniforms()
-{
-	int params;
-	glGetProgramiv( glid, GL_ACTIVE_UNIFORMS, &params );
-
-	for ( unsigned i = 0; i < size_t(params); ++i )
-	{
-		int uni_nlen;
-		int uni_len;
-		unsigned uni_type;
-		char name_buffer[128];
-
-		glGetActiveUniform( glid, i, 128, &uni_nlen, &uni_len, &uni_type, name_buffer );
-
-		string name( name_buffer, size_t(uni_nlen) );
-		
-		// skip built-ins
-		if ( name.substr(0,3) == "gl_" ) continue;
-
-		int uni_loc = glGetUniformLocation( glid, name.c_str() );
-		datatype utype = gl_enum_to_datatype( uni_type );
-		
-		// check for array
-		string::size_type arrchar = name.find('[');
-		if ( arrchar != string::npos )
-		{
-			name = name.substr( 0, arrchar );
-		}
-
-		uniform_base* u = create_uniform( utype, name, uni_loc, uni_len );
-		NV_ASSERT( u, "Unknown uniform type!" );
-		m_uniform_map[ name ] = u;
-	}
-
-	apply_link_engine_uniforms();
-	bind_engine_uniforms();
-}
-
-void gl_program::update_uniforms()
-{
-	for ( uniform_map::iterator i = m_uniform_map.begin(); 	i != m_uniform_map.end(); ++i ) 
-	{
-		uniform_base* ubase = i->second;
-		if ( ubase->is_dirty() )
-		{
-			int uloc = ubase->get_location();
-			switch( ubase->get_type() )
-			{
-			case FLOAT          : glUniform1fv( uloc, ubase->get_length(), ((uniform< enum_to_type< FLOAT >::type >*)( ubase ))->get_value() ); break;
-			case INT            : glUniform1iv( uloc, ubase->get_length(), ((uniform< enum_to_type< INT >::type >*)( ubase ))->get_value() ); break;
-			case FLOAT_VECTOR_2 : glUniform2fv( uloc, ubase->get_length(), (GLfloat*)((uniform< enum_to_type< FLOAT_VECTOR_2 >::type >*)( ubase ))->get_value()); break;
-			case FLOAT_VECTOR_3 : glUniform3fv( uloc, ubase->get_length(), (GLfloat*)((uniform< enum_to_type< FLOAT_VECTOR_3 >::type >*)( ubase ))->get_value()); break;
-			case FLOAT_VECTOR_4 : glUniform4fv( uloc, ubase->get_length(), (GLfloat*)((uniform< enum_to_type< FLOAT_VECTOR_4 >::type >*)( ubase ))->get_value()); break;
-			case INT_VECTOR_2   : glUniform2iv( uloc, ubase->get_length(), (GLint*)((uniform< enum_to_type< INT_VECTOR_2 >::type >*)( ubase ))->get_value()); break;
-			case INT_VECTOR_3   : glUniform3iv( uloc, ubase->get_length(), (GLint*)((uniform< enum_to_type< INT_VECTOR_3 >::type >*)( ubase ))->get_value()); break;
-			case INT_VECTOR_4   : glUniform4iv( uloc, ubase->get_length(), (GLint*)((uniform< enum_to_type< INT_VECTOR_4 >::type >*)( ubase ))->get_value()); break;
-			case FLOAT_MATRIX_2 : glUniformMatrix2fv( uloc, ubase->get_length(), GL_FALSE, (GLfloat*)((uniform< enum_to_type< FLOAT_MATRIX_2 >::type >*)( ubase ))->get_value()); break;
-			case FLOAT_MATRIX_3 : glUniformMatrix3fv( uloc, ubase->get_length(), GL_FALSE, (GLfloat*)((uniform< enum_to_type< FLOAT_MATRIX_3 >::type >*)( ubase ))->get_value()); break;
-			case FLOAT_MATRIX_4 : glUniformMatrix4fv( uloc, ubase->get_length(), GL_FALSE, (GLfloat*)((uniform< enum_to_type< FLOAT_MATRIX_4 >::type >*)( ubase ))->get_value()); break;
-			default : break; // error?
-			}
-			ubase->clean();
-		}
-	}
-
-}
-
-
-bool gl_program::validate()
-{
-	const uint32 buffer_size = 2048;
-	char buffer[ buffer_size ] = { 0 };
-	int length;
-	int status;
-
-	glGetProgramiv( glid, GL_LINK_STATUS, &status );
-	glGetProgramInfoLog( glid, buffer_size, &length, buffer );
-
-	NV_LOG( LOG_INFO, "Program #" << glid << (status == GL_FALSE ? " failed to compile!" : " compiled successfully.") );
-
-	if ( length > 0 )
-	{
-		NV_LOG( LOG_INFO, "Program #" << glid << " log: " << buffer );
-	}
-
-	if ( status == GL_FALSE ) 
-	{
-		return false;
-	}
-
-	glValidateProgram( glid );
-	glGetProgramiv( glid, GL_VALIDATE_STATUS, &status );
-
-	if ( status == GL_FALSE )
-	{
-		glGetProgramInfoLog( glid, buffer_size, &length, buffer );
-		NV_LOG( LOG_ERROR, "Program #" << glid << " validation error : " << buffer );
-		return false;
-	}
-	return true;
-}
-
-
Index: trunk/src/gui/gui_renderer.cc
===================================================================
--- trunk/src/gui/gui_renderer.cc	(revision 302)
+++ trunk/src/gui/gui_renderer.cc	(revision 303)
@@ -66,5 +66,5 @@
 public:
 	screen_render_data( context* actx, size_t initial_size )
-		: buffer( actx, VERTEX_BUFFER, DYNAMIC_DRAW, initial_size ), ctx( actx ), varray(), shader(nullptr)
+		: buffer( actx, VERTEX_BUFFER, DYNAMIC_DRAW, initial_size ), ctx( actx ), varray(), shader()
 	{
 
@@ -72,5 +72,5 @@
 	~screen_render_data() 
 	{ 
-		delete shader; 
+		ctx->get_device()->release( shader ); 
 		ctx->get_device()->release( varray ); 
 	}
@@ -80,5 +80,5 @@
 	nv::texture       tex;
 	nv::vertex_array  varray;
-	nv::program*      shader;
+	nv::program       shader;
 };
 
