Index: /trunk/nv/core/transform.hh
===================================================================
--- /trunk/nv/core/transform.hh	(revision 505)
+++ /trunk/nv/core/transform.hh	(revision 506)
@@ -34,4 +34,8 @@
 		const vec3& get_position() const { return m_position; }
 		const quat& get_orientation() const { return m_orientation; }
+		bool is_identity() const
+		{
+			return m_position == vec3() && m_orientation == quat();
+		}
 
 	public:
Index: /trunk/nv/engine/mesh_manager.hh
===================================================================
--- /trunk/nv/engine/mesh_manager.hh	(revision 505)
+++ /trunk/nv/engine/mesh_manager.hh	(revision 506)
@@ -24,5 +24,5 @@
 {
 
-	enum shader_type
+	enum shader_geo
 	{
 		NORMAL = 0,
@@ -34,5 +34,5 @@
 		vertex_array va;
 		uint32       count;
-		shader_type  shader;
+		shader_geo  shader;
 	};
 
Index: /trunk/nv/gl/gl_device.hh
===================================================================
--- /trunk/nv/gl/gl_device.hh	(revision 505)
+++ /trunk/nv/gl/gl_device.hh	(revision 506)
@@ -28,9 +28,15 @@
 	};
 
+	struct gl_shader_info : public shader_info
+	{
+		unsigned glid;
+		unsigned ref;
+	};
+	
 	struct gl_program_info : public program_info
 	{
 		unsigned glid;
-		unsigned glidv;
-		unsigned glidf;
+		shader vertex;
+		shader fragment;
 		bool validated;
 	};
@@ -45,11 +51,16 @@
 		virtual image_data* create_image_data( const uint8* data, uint32 size ); // temporary
 
-		virtual program create_program( string_view vs_source, string_view fs_source );
+		virtual shader create_shader( shader_type type, string_view sh_source );
+		virtual program create_program( shader vs, shader fs );
 		virtual texture create_texture( texture_type type, pixel_format format );
 		virtual buffer create_buffer( buffer_type type, buffer_hint hint );
+
+		virtual void attach( program p, shader s );
+		virtual void detach( program p, shader s );
 
 		virtual void release( buffer b );
 		virtual void release( texture t );
 		virtual void release( program p );
+		virtual void release( shader s );
 		virtual const texture_info* get_texture_info( texture t ) const;
 		virtual const buffer_info* get_buffer_info( buffer t ) const;
@@ -68,5 +79,5 @@
 
 	private:
-		bool compile( gl_program_info* p, string_view vertex_program, string_view fragment_program );
+		bool compile( program p, shader vp, shader fp );
 		bool compile( uint32 sh_type, string_view shader_code, unsigned& glid );
 		void update_uniforms( gl_program_info* p );
@@ -77,4 +88,5 @@
 		handle_store< gl_texture_info, texture >         m_textures;
 		handle_store< gl_buffer_info,  buffer >          m_buffers;
+		handle_store< gl_shader_info, shader >           m_shaders;
 		handle_store< gl_program_info, program >         m_programs;
 	};
Index: /trunk/nv/gl/gl_enum.hh
===================================================================
--- /trunk/nv/gl/gl_enum.hh	(revision 505)
+++ /trunk/nv/gl/gl_enum.hh	(revision 506)
@@ -42,4 +42,5 @@
 	unsigned int framebuffer_slot_to_enum( framebuffer_slot slot );
 	unsigned int output_slot_to_enum( output_slot slot );
+	unsigned int shader_type_to_enum( shader_type type );
 
 	unsigned int buffer_access_to_bitfield( buffer_access type );
Index: /trunk/nv/interface/context.hh
===================================================================
--- /trunk/nv/interface/context.hh	(revision 505)
+++ /trunk/nv/interface/context.hh	(revision 506)
@@ -164,15 +164,22 @@
 		virtual texture create_texture( texture_type type, pixel_format format ) { return m_device->create_texture( type, format ); }
 		// TODO: remove?
-		virtual texture create_texture( ivec2 size, image_format aformat, sampler asampler, const void* data = nullptr )
+		texture create_texture( ivec2 size, image_format aformat, sampler asampler, const void* data = nullptr )
 		{ 
 			return create_texture( TEXTURE_2D, size, aformat, asampler, data );
 		}
-		virtual texture create_texture( const image_data* data, sampler asampler )
+		texture create_texture( const image_data* data, sampler asampler )
 		{
 			return create_texture( data->get_size(), data->get_format(), asampler, data->get_data() );
 		}
-
-
-		virtual program create_program( string_view vs_source, string_view fs_source ) { return m_device->create_program( vs_source, fs_source ); }
+		shader create_shader( shader_type type, string_view sh_source ) { return m_device->create_shader( type, sh_source ); }
+		program create_program( shader vs, shader fs ) { return m_device->create_program( vs, fs ); }
+		virtual program create_program( string_view vs_source, string_view fs_source )
+		{
+			shader vs = create_shader( VERTEX_SHADER, vs_source );
+			if ( !vs ) return program();
+			shader fs = create_shader( FRAGMENT_SHADER, fs_source );
+			if ( !fs ) return program();
+			return create_program( vs, fs );
+		}
 		virtual buffer create_buffer( buffer_type type, buffer_hint hint, size_t size, const void* source = nullptr ) = 0;
 		virtual void   create_buffer( buffer, size_t, const void* = nullptr ) = 0;
Index: /trunk/nv/interface/device.hh
===================================================================
--- /trunk/nv/interface/device.hh	(revision 505)
+++ /trunk/nv/interface/device.hh	(revision 506)
@@ -25,4 +25,10 @@
 {
 	class window;
+
+	enum shader_type
+	{
+		VERTEX_SHADER,
+		FRAGMENT_SHADER
+	};
 
 	enum output_slot
@@ -95,12 +101,15 @@
 	struct texture_tag {};
 	struct buffer_tag {};
+	struct shader_tag {};
 	struct program_tag {};
 
 	typedef handle< uint32, 16, 16, buffer_tag >       buffer;
 	typedef handle< uint32, 16, 16, texture_tag >      texture;
+	typedef handle< uint32, 16, 16, shader_tag >       shader;
 	typedef handle< uint32, 16, 16, program_tag >      program;
 
 	NV_RTTI_DECLARE_NAME( buffer,  "buffer" )
 	NV_RTTI_DECLARE_NAME( texture, "texture" )
+	NV_RTTI_DECLARE_NAME( shader,  "shader" )
 	NV_RTTI_DECLARE_NAME( program, "program" )
 
@@ -184,4 +193,9 @@
 	};
 
+	struct shader_info
+	{
+		shader_type type;
+	};
+
 	struct program_info
 	{
@@ -200,5 +214,7 @@
 		}
 	protected:
-		virtual program create_program( string_view vs_source, string_view fs_source ) = 0;
+		virtual shader create_shader( shader_type type, string_view sh_source ) = 0;
+//		virtual program create_program( string_view vs_source, string_view fs_source ) = 0;
+		virtual program create_program( shader vs, shader fs ) = 0;
 		virtual buffer  create_buffer( buffer_type type, buffer_hint hint ) = 0;
 		virtual texture create_texture( texture_type type, pixel_format format ) = 0;
@@ -206,8 +222,11 @@
 		// TODO: remove?
 //		virtual texture create_texture( ivec2 size, image_format aformat, sampler asampler, const void* data = nullptr ) { return create_texture( TEXTURE_2D, size, aformat, asampler, data ); }
+		virtual void attach( program p, shader s ) = 0;
+		virtual void detach( program p, shader s ) = 0;
 
 		virtual void release( texture ) = 0;
 		virtual void release( buffer ) = 0;
 		virtual void release( program ) = 0;
+		virtual void release( shader ) = 0;
 	public:
 
Index: /trunk/src/gl/gl_device.cc
===================================================================
--- /trunk/src/gl/gl_device.cc	(revision 505)
+++ /trunk/src/gl/gl_device.cc	(revision 506)
@@ -22,20 +22,4 @@
 	for ( auto& i : get_link_uniform_factory() ) 
 		m_shader_header.append( "uniform sampler2D "+i.first +";\n" );
-}
-
-program gl_device::create_program( string_view vs_source, string_view fs_source )
-{
-	program result = m_programs.create();
-	gl_program_info* info = m_programs.get( result );
-
-	info->m_attribute_map   = new attribute_map;
-	info->m_engine_uniforms = new engine_uniform_list;
-	info->m_uniform_map     = new uniform_map;
-
-	info->glid = glCreateProgram();
-	info->validated = false;
-	compile( info, vs_source, fs_source );
-	prepare_program( result );
-	return result;
 }
 
@@ -92,4 +76,39 @@
 	while ( m_programs.size() > 0 )
 		release( m_programs.get_handle(0) );
+	while ( m_shaders.size() > 0 )
+		release( m_shaders.get_handle( 0 ) );
+}
+
+nv::shader nv::gl_device::create_shader( shader_type type, string_view sh_source )
+{
+	uint32 glid = 0;
+	if ( !compile( shader_type_to_enum( type ), sh_source, glid ) )
+		return shader();
+
+	shader result = m_shaders.create();
+	gl_shader_info* info = m_shaders.get( result );
+	info->type = type;
+	info->glid = glid;
+	info->ref  = 0;
+
+	return result;
+}
+
+nv::program nv::gl_device::create_program( shader vs, shader fs )
+{
+	program result = m_programs.create();
+	gl_program_info* info = m_programs.get( result );
+
+	info->m_attribute_map = new attribute_map;
+	info->m_engine_uniforms = new engine_uniform_list;
+	info->m_uniform_map = new uniform_map;
+
+	info->glid = glCreateProgram();
+	info->validated = false;
+
+	compile( result, vs, fs );
+	prepare_program( result );
+	return result;
+
 }
 
@@ -156,4 +175,27 @@
 }
 
+void nv::gl_device::attach( program p, shader s )
+{
+	gl_program_info* pinfo = m_programs.get( p );
+	gl_shader_info*  sinfo = m_shaders.get( s );
+
+	if ( sinfo && pinfo )
+	{
+		glAttachShader( pinfo->glid, sinfo->glid );
+		sinfo->ref++;
+	}
+
+}
+
+void nv::gl_device::detach( program p, shader s )
+{
+	gl_program_info* pinfo = m_programs.get( p );
+	gl_shader_info*  sinfo = m_shaders.get( s );
+	if ( sinfo && pinfo )
+	{
+		glDetachShader( pinfo->glid, sinfo->glid );
+		sinfo->ref--;
+	}
+}
 const buffer_info* nv::gl_device::get_buffer_info( buffer t ) const
 {
@@ -169,8 +211,6 @@
 			delete i.second;
 
-		glDetachShader( info->glid, info->glidv );
-		glDetachShader( info->glid, info->glidf );
-		glDeleteShader( info->glidv );
-		glDeleteShader( info->glidf );
+		detach( p, info->vertex );
+		detach( p, info->fragment );
 		glDeleteProgram( info->glid );
 
@@ -182,4 +222,15 @@
 	}
 }
+
+void nv::gl_device::release( shader s )
+{
+	gl_shader_info* info = m_shaders.get( s );
+	if ( info && info->ref == 0 )
+	{
+		glDeleteShader( info->glid );
+		m_shaders.destroy( s );
+	}
+}
+
 
 nv::gl_texture_info* nv::gl_device::get_full_texture_info( texture t )
@@ -285,8 +336,9 @@
 }
 
-bool nv::gl_device::compile( gl_program_info* p, string_view vertex_program, string_view fragment_program )
-{
-	if (!compile( GL_VERTEX_SHADER,   vertex_program, p->glidv ))   { return false; }
-	if (!compile( GL_FRAGMENT_SHADER, fragment_program, p->glidf )) { return false; }
+bool nv::gl_device::compile( program pp, shader vp, shader fp )
+{
+	gl_program_info* p = m_programs.get( pp );
+	p->vertex = vp;
+	p->fragment = fp;
 
 	glBindAttribLocation( p->glid, static_cast<GLuint>( slot::POSITION   ), "nv_position"  );
@@ -298,6 +350,6 @@
 	glBindAttribLocation( p->glid, static_cast<GLuint>( slot::BONEWEIGHT ), "nv_boneweight");
 
-	glAttachShader( p->glid, p->glidf );
-	glAttachShader( p->glid, p->glidv );
+	attach( pp, p->vertex );
+	attach( pp, p->fragment );
 	glLinkProgram( p->glid );
 
Index: /trunk/src/gl/gl_enum.cc
===================================================================
--- /trunk/src/gl/gl_enum.cc	(revision 505)
+++ /trunk/src/gl/gl_enum.cc	(revision 506)
@@ -319,4 +319,14 @@
 }
 
+
+unsigned int nv::shader_type_to_enum( shader_type type )
+{
+	switch ( type )
+	{
+	case VERTEX_SHADER:   return GL_VERTEX_SHADER;
+	case FRAGMENT_SHADER: return GL_FRAGMENT_SHADER;
+		NV_RETURN_COVERED_DEFAULT( 0 );
+	}
+}
 
 unsigned int nv::buffer_access_to_bitfield( buffer_access type )
