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