Index: trunk/nv/engine/particle_engine.hh
===================================================================
--- trunk/nv/engine/particle_engine.hh	(revision 500)
+++ trunk/nv/engine/particle_engine.hh	(revision 501)
@@ -128,5 +128,5 @@
 	{
 		uint32 quota;
-		bool   local;
+//		bool   local;
 		vec3   common_up;
 		vec3   common_dir;
@@ -204,5 +204,4 @@
 		void update_emmiters( particle_system_info* info, float dtime );
 
-		device*  m_device;
 		context* m_context;
 
Index: trunk/nv/gfx/sliced_buffer.hh
===================================================================
--- trunk/nv/gfx/sliced_buffer.hh	(revision 500)
+++ trunk/nv/gfx/sliced_buffer.hh	(revision 501)
@@ -197,5 +197,5 @@
 		virtual ~sliced_buffer() 
 		{
-			m_context->get_device()->release( m_buffer );
+			m_context->release( m_buffer );
 		}
 	private:
@@ -204,7 +204,7 @@
 			m_capacity = size;
 			if ( m_buffer )
-				m_context->get_device()->create_buffer( m_buffer, size * value_type_size, nullptr );
+				m_context->create_buffer( m_buffer, size * value_type_size, nullptr );
 			else
-				m_buffer = m_context->get_device()->create_buffer( m_type, m_hint, size * value_type_size, nullptr );
+				m_buffer = m_context->create_buffer( m_type, m_hint, size * value_type_size, nullptr );
 		}
 	private:
Index: trunk/nv/gl/gl_context.hh
===================================================================
--- trunk/nv/gl/gl_context.hh	(revision 500)
+++ trunk/nv/gl/gl_context.hh	(revision 501)
@@ -38,7 +38,15 @@
 		virtual vertex_array create_vertex_array( const vertex_array_desc& desc );
 		virtual framebuffer create_framebuffer( uint32 temp_samples = 1 );
+		using context::release;
 		virtual void release( vertex_array va );
 		virtual void release( framebuffer f );
 		virtual const framebuffer_info* get_framebuffer_info( framebuffer f ) const;
+
+		using context::create_texture;
+		virtual texture create_texture( texture_type type, ivec2 size, image_format aformat, sampler asampler, const void* data = nullptr );
+		virtual texture create_texture( texture_type type, ivec3 size, image_format aformat, sampler asampler, const void* data = nullptr );
+
+		virtual buffer create_buffer( buffer_type type, buffer_hint hint, size_t size, const void* source = nullptr );
+		virtual void create_buffer( buffer, size_t, const void* = nullptr );
 
 		virtual void set_draw_buffers( uint32 count, const output_slot* slots );
@@ -77,5 +85,4 @@
 	protected:
 		void bind( program p );
-//		void bind( buffer b );
 		void bind( vertex_array va );
 		void unbind( program p );
@@ -105,4 +112,6 @@
 		texture_slot m_active_slot;
 		texture      m_bound_textures[ texture_slot::MAX_TEXTURES ];
+		program      m_bound_program;
+
 		vec4  m_clear_color;
 		float m_clear_depth;
Index: trunk/nv/gl/gl_device.hh
===================================================================
--- trunk/nv/gl/gl_device.hh	(revision 500)
+++ trunk/nv/gl/gl_device.hh	(revision 501)
@@ -46,9 +46,6 @@
 
 		virtual program create_program( string_view vs_source, string_view fs_source );
-		virtual buffer create_buffer( buffer_type type, buffer_hint hint, size_t size, const void* source = nullptr );
-		virtual texture create_texture( texture_type type, ivec2 size, image_format aformat, sampler asampler, const void* data = nullptr );
-		virtual texture create_texture( texture_type type, ivec3 size, image_format aformat, sampler asampler, const void* data = nullptr );
 		virtual texture create_texture( texture_type type, pixel_format format );
-		virtual void create_buffer( buffer b, size_t size, const void* source = nullptr );
+		virtual buffer create_buffer( buffer_type type, buffer_hint hint );
 
 		virtual void release( buffer b );
@@ -64,4 +61,7 @@
 		virtual ~gl_device();
 	protected:
+		gl_texture_info* get_full_texture_info( texture t );
+		gl_buffer_info* get_full_buffer_info( buffer t );
+
 		void prepare_program( program p );
 		uniform_base* get_uniform( program p, const string_view& name, bool fatal = true ) const;
@@ -73,4 +73,5 @@
 		void load_attributes( gl_program_info* p );
 		void load_uniforms( gl_program_info* p );
+
 		string_buffer m_shader_header;
 		handle_store< gl_texture_info, texture >         m_textures;
Index: trunk/nv/interface/camera.hh
===================================================================
--- trunk/nv/interface/camera.hh	(revision 500)
+++ trunk/nv/interface/camera.hh	(revision 501)
@@ -84,11 +84,13 @@
 		const mat4& get_view()       const { return m_camera.get_view(); }
 		const mat4& get_projection() const { return m_camera.get_projection(); }
-		mat4 get_modelview()  const { return get_view() * m_model; }
-		mat4 get_mvp()        const { return m_camera.get_projection() * get_modelview(); }
+		mat4 get_viewprojection() const { return m_camera.get_projection() * get_view(); }
+		mat4 get_modelview()      const { return get_view() * m_model; }
+		mat4 get_mvp()            const { return m_camera.get_projection() * get_modelview(); }
 
 		mat4 get_view_inv()       const { return math::inverse( get_view() ); }
 		mat4 get_model_inv()      const { return math::inverse( get_model() ); }
 		mat4 get_modelview_inv()  const { return math::inverse( get_modelview() ); }
-		mat4 get_projection_inv() const { return math::inverse( get_projection() ); }
+		mat4 get_projection_inv()     const { return math::inverse( get_projection() ); }
+		mat4 get_viewprojection_inv() const { return math::inverse( get_viewprojection() ); }
 		mat4 get_mvp_inv()        const { return math::inverse( get_mvp() ); }
 		mat3 get_normal()         const { return math::transpose( math::inverse( mat3( get_modelview() ) ) ); }
Index: trunk/nv/interface/context.hh
===================================================================
--- trunk/nv/interface/context.hh	(revision 500)
+++ trunk/nv/interface/context.hh	(revision 501)
@@ -157,4 +157,27 @@
 		virtual void release( framebuffer ) = 0;
 
+		virtual void release( program p ) { m_device->release( p ); }
+		virtual void release( texture t ) { m_device->release( t ); }
+		virtual void release( buffer b ) { m_device->release( b ); }
+
+		virtual texture create_texture( texture_type type, ivec2 size, image_format aformat, sampler asampler, const void* data = nullptr ) = 0;
+		virtual texture create_texture( texture_type type, ivec3 size, image_format aformat, sampler asampler, const void* data = nullptr ) = 0;
+		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 )
+		{ 
+			return create_texture( TEXTURE_2D, size, aformat, asampler, data );
+		}
+		virtual 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 ); }
+		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;
+
+
 		virtual const framebuffer_info* get_framebuffer_info( framebuffer ) const = 0;
 
@@ -219,5 +242,5 @@
 		vertex_array create_vertex_array( const VTX* v, size_t count, buffer_hint hint )
 		{
-			buffer       vb = m_device->create_buffer( VERTEX_BUFFER, hint, count * sizeof( VTX ), v );
+			buffer       vb = create_buffer( VERTEX_BUFFER, hint, count * sizeof( VTX ), v );
 			vertex_array_desc desc;
 			desc.add_vertex_buffers< VTX >( vb, true );
@@ -228,6 +251,6 @@
 		vertex_array create_vertex_array( const VTX* v, size_t vcount, const IDX* i, size_t icount, buffer_hint hint )
 		{
-			buffer       vb = m_device->create_buffer( VERTEX_BUFFER, hint, count * sizeof( VTX ), v );
-			buffer       ib = m_device->create_buffer( INDEX_BUFFER, hint, icount * sizeof( IDX ), i );
+			buffer       vb = create_buffer( VERTEX_BUFFER, hint, count * sizeof( VTX ), v );
+			buffer       ib = create_buffer( INDEX_BUFFER, hint, icount * sizeof( IDX ), i );
 			vertex_array_desc desc;
 			desc.add_vertex_buffers< VTX >( vb, true );
@@ -248,10 +271,10 @@
 					if ( desc[0].vslot == slot::INDEX )
 					{
-						buffer b = m_device->create_buffer( INDEX_BUFFER, hint, channel.raw_size(), channel.raw_data() );
+						buffer b = create_buffer( INDEX_BUFFER, hint, channel.raw_size(), channel.raw_data() );
 						va_desc.set_index_buffer( b, desc[0].etype, true );
 					}
 					else
 					{
-						buffer b = m_device->create_buffer( VERTEX_BUFFER, hint, channel.raw_size(), channel.raw_data() );
+						buffer b = create_buffer( VERTEX_BUFFER, hint, channel.raw_size(), channel.raw_data() );
 						va_desc.add_vertex_buffers( b, desc );
 					}
Index: trunk/nv/interface/device.hh
===================================================================
--- trunk/nv/interface/device.hh	(revision 500)
+++ trunk/nv/interface/device.hh	(revision 501)
@@ -199,43 +199,32 @@
 			initialize_engine_uniforms();
 		}
+	protected:
 		virtual program create_program( string_view vs_source, string_view fs_source ) = 0;
-		virtual buffer create_buffer( buffer_type type, buffer_hint hint, size_t size, const void* source = nullptr ) = 0;
-		virtual texture create_texture( texture_type type, ivec2 size, image_format aformat, sampler asampler, const void* data = nullptr ) = 0;
-		virtual texture create_texture( texture_type type, ivec3 size, image_format aformat, sampler asampler, const void* data = nullptr ) = 0;
+		virtual buffer  create_buffer( buffer_type type, buffer_hint hint ) = 0;
 		virtual texture create_texture( texture_type type, pixel_format format ) = 0;
 
 		// 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 create_buffer( buffer, size_t, const void* = nullptr ) = 0;
-
-
-		virtual image_data* create_image_data( string_view filename ) = 0; // temporary
-		virtual image_data* create_image_data( const uint8* data, uint32 size ) = 0; // temporary
+//		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 release( texture ) = 0;
 		virtual void release( buffer ) = 0;
 		virtual void release( program ) = 0;
+	public:
+
+
+		virtual image_data* create_image_data( string_view filename ) = 0; // temporary
+		virtual image_data* create_image_data( const uint8* data, uint32 size ) = 0; // temporary
 		virtual const texture_info* get_texture_info( texture ) const = 0;
 		virtual const buffer_info* get_buffer_info( buffer ) const = 0;
 		virtual string_view get_shader_header() const = 0;
 
-		virtual texture create_texture( const image_data* data, sampler asampler ) 
-		{
-			return create_texture( data->get_size(), data->get_format(), asampler, data->get_data() );
-		}
-
-		int try_get_attribute_location( program p, const string_view& name ) const
-		{
-			return get_attribute_location( p, name, false );
-		}
-
-		int try_get_block_location( program p, const string_view& name ) const
-		{
-			return get_block_location( p, name, false );
-		}
-
 		virtual int get_attribute_location( program p, const string_view& name, bool fatal = true ) const = 0;
 		virtual int get_block_location( program p, const string_view& name, bool fatal = true ) const = 0;
 		virtual bool bind_block( program p, const string_view& name, uint32 index ) = 0;
+
+		virtual ~device()
+		{
+			destroy_engine_uniforms();
+		}
 
 		template < typename T >
@@ -249,5 +238,5 @@
 					// TODO: nicer check
 					NV_ASSERT( static_cast<int>( count ) <= base->get_length(), "LENGTH CHECK FAIL" );
-					static_cast< uniform<T>* >( base )->set_value( value, count );
+					static_cast<uniform<T>*>( base )->set_value( value, count );
 					return true;
 				}
@@ -277,5 +266,5 @@
 				if ( base->type_check( type_to_enum<T>::type ) )
 				{
-					static_cast< uniform<T>* >( base )->set_value( value );
+					static_cast<uniform<T>*>( base )->set_value( value );
 					return true;
 				}
@@ -290,9 +279,4 @@
 		}
 
-		virtual ~device()
-		{
-			destroy_engine_uniforms();
-		}
-
 		// This is done this way to avoid compilation unit creation
 		static engine_uniform_factory_map& get_uniform_factory()
@@ -312,4 +296,5 @@
 
 	protected:
+
 		virtual uniform_base* get_uniform( program p, const string_view& name, bool fatal = true ) const = 0;
 
@@ -327,4 +312,6 @@
 			factory_map[ "nv_m_projection" ]    = new engine_uniform_factory< engine_uniform_m_projection >();
 			factory_map[ "nv_m_projection_inv"] = new engine_uniform_factory< engine_uniform_m_projection_inv >();
+			factory_map[ "nv_m_viewprojection" ]     = new engine_uniform_factory< engine_uniform_m_viewprojection >();
+			factory_map[ "nv_m_viewprojection_inv" ] = new engine_uniform_factory< engine_uniform_m_viewprojection_inv >();
 			factory_map[ "nv_m_normal" ]        = new engine_uniform_factory< engine_uniform_m_normal >();
 			factory_map[ "nv_m_mvp" ]           = new engine_uniform_factory< engine_uniform_m_mvp >();
@@ -344,4 +331,6 @@
 			factory_link_map[ "nv_texture_6"  ] = new engine_link_uniform_int<6>();
 			factory_link_map[ "nv_texture_7"  ] = new engine_link_uniform_int<7>();
+			factory_link_map[ "nv_texture_8"  ] = new engine_link_uniform_int<8>();
+			factory_link_map[ "nv_texture_9"  ] = new engine_link_uniform_int<9>();
 			factory_link_map[ "nv_t_diffuse"  ] = new engine_link_uniform_int<int( TEX_DIFFUSE )>();
 			factory_link_map[ "nv_t_normal"   ] = new engine_link_uniform_int<int( TEX_NORMAL )>();
Index: trunk/nv/interface/uniform.hh
===================================================================
--- trunk/nv/interface/uniform.hh	(revision 500)
+++ trunk/nv/interface/uniform.hh	(revision 501)
@@ -251,4 +251,18 @@
 	};
 
+	class engine_uniform_m_viewprojection : public engine_uniform< mat4 >
+	{
+	public:
+		engine_uniform_m_viewprojection( uniform_base* u ) : engine_uniform( u ) {}
+		virtual void set( const context*, const scene_state* s ) { m_uniform->set_value( s->get_viewprojection() ); }
+	};
+
+	class engine_uniform_m_viewprojection_inv : public engine_uniform< mat4 >
+	{
+	public:
+		engine_uniform_m_viewprojection_inv( uniform_base* u ) : engine_uniform( u ) {}
+		virtual void set( const context*, const scene_state* s ) { m_uniform->set_value( s->get_viewprojection_inv() ); }
+	};
+
 	class engine_uniform_v_camera_position : public engine_uniform< vec3 >
 	{
Index: trunk/src/engine/material_manager.cc
===================================================================
--- trunk/src/engine/material_manager.cc	(revision 500)
+++ trunk/src/engine/material_manager.cc	(revision 501)
@@ -20,5 +20,5 @@
 	uint8 data[2 * 2 * 3];
 	nv::raw_fill_n( data, 2 * 2 * 3, 0 );
-	m_default = m_context->get_device()->create_texture( ivec2(2,2), nv::image_format( nv::RGB ), nv::sampler(), data );
+	m_default = m_context->create_texture( ivec2(2,2), nv::image_format( nv::RGB ), nv::sampler(), data );
 }
 
@@ -34,5 +34,5 @@
 				if ( auto data = m_image_manager->get( mat->paths[i] ).lock() )
 				{
-					result->textures[i] = m_context->get_device()->create_texture( &*data, smp );
+					result->textures[i] = m_context->create_texture( &*data, smp );
 				}
 			}
@@ -53,5 +53,5 @@
 	for ( const texture& t : m->textures )
 	{
-		m_context->get_device()->release( t );
+		m_context->release( t );
 	}
 }
Index: trunk/src/engine/particle_engine.cc
===================================================================
--- trunk/src/engine/particle_engine.cc	(revision 500)
+++ trunk/src/engine/particle_engine.cc	(revision 501)
@@ -320,5 +320,5 @@
 
 	data.quota   = table.get<uint32>("quota", 1024 );
-	data.local   = table.get<bool>("local_space", false );
+//	data.local   = table.get<bool>("local_space", false );
 	data.accurate_facing = table.get<bool>("accurate_facing", false );
 	data.emmiter_count   = 0;
@@ -467,7 +467,6 @@
 {
 	m_context       = a_context;
-	m_device        = a_context->get_device();
-	m_program_local = m_device->create_program( nv_particle_engine_vertex_shader_local, nv_particle_engine_fragment_shader );
-	m_program_world = m_device->create_program( nv_particle_engine_vertex_shader_world, nv_particle_engine_fragment_shader );
+	m_program_local = m_context->create_program( nv_particle_engine_vertex_shader_local, nv_particle_engine_fragment_shader );
+	m_program_world = m_context->create_program( nv_particle_engine_vertex_shader_world, nv_particle_engine_fragment_shader );
 
 	register_standard_emmiters();
@@ -533,5 +532,5 @@
 	info->count = 0;
 	info->quota = max_particles;
-	info->vtx_buffer = m_device->create_buffer( VERTEX_BUFFER, STREAM_DRAW, info->quota * sizeof( particle_quad )/*, info->quads_[0].data*/ );
+	info->vtx_buffer = m_context->create_buffer( VERTEX_BUFFER, STREAM_DRAW, info->quota * sizeof( particle_quad )/*, info->quads_[0].data*/ );
 	vertex_array_desc desc;
 	desc.add_vertex_buffers< particle_vtx >( info->vtx_buffer, true );
@@ -545,6 +544,6 @@
 {
 	clear();
-	m_device->release( m_program_world );
-	m_device->release( m_program_local );
+	m_context->release( m_program_world );
+	m_context->release( m_program_local );
 }
 
@@ -785,5 +784,5 @@
 	vec3 source;
 	mat3 orient;
-	bool local = info->data->local;
+//	bool local = info->data->local;
 // 	if ( !local ) 
 // 	{
Index: trunk/src/engine/program_manager.cc
===================================================================
--- trunk/src/engine/program_manager.cc	(revision 500)
+++ trunk/src/engine/program_manager.cc	(revision 501)
@@ -36,5 +36,5 @@
 	}
 
-	add( id, m_context->get_device()->create_program( vsource, fsource ) );
+	add( id, m_context->create_program( vsource, fsource ) );
 	return true;
 }
@@ -42,5 +42,5 @@
 void nv::program_manager::release( program p )
 {
-	m_context->get_device()->release( p );
+	m_context->release( p );
 }
 
Index: trunk/src/gfx/debug_draw.cc
===================================================================
--- trunk/src/gfx/debug_draw.cc	(revision 500)
+++ trunk/src/gfx/debug_draw.cc	(revision 501)
@@ -35,5 +35,5 @@
 	: m_context( a_context ), m_program(), m_va()
 {
-	m_program = m_context->get_device()->create_program( nv_debug_draw_vertex_shader, nv_debug_draw_fragment_shader );
+	m_program = m_context->create_program( nv_debug_draw_vertex_shader, nv_debug_draw_fragment_shader );
 	m_buffer_size = 0;
 }
@@ -45,5 +45,5 @@
 		if ( m_va.is_valid() ) m_context->release( m_va );
 		m_buffer_size = nv::max( m_data.size(), 4096U, m_buffer_size );
-		m_vb = m_context->get_device()->create_buffer( VERTEX_BUFFER, nv::STREAM_DRAW, m_buffer_size * sizeof( debug_vtx ) );
+		m_vb = m_context->create_buffer( VERTEX_BUFFER, nv::STREAM_DRAW, m_buffer_size * sizeof( debug_vtx ) );
 		vertex_array_desc va_desc;
 		va_desc.add_vertex_buffers< debug_vtx >( m_vb, true );
@@ -89,4 +89,4 @@
 {
 	m_context->release( m_va );
-	m_context->get_device()->release( m_program );
+	m_context->release( m_program );
 }
Index: trunk/src/gl/gl_context.cc
===================================================================
--- trunk/src/gl/gl_context.cc	(revision 500)
+++ trunk/src/gl/gl_context.cc	(revision 501)
@@ -66,5 +66,4 @@
 		}
 	}
-	glBindBuffer( GL_ARRAY_BUFFER, 0 );
 	glBindVertexArray( 0 );
 
@@ -104,7 +103,7 @@
 		{
 			if ( info->attr[i].owner ) 
-				m_device->release( info->attr[i].vbuffer );
-		}
-		if ( info->index.is_valid() && info->index_owner) m_device->release( info->index );
+				release( info->attr[i].vbuffer );
+		}
+		if ( info->index.is_valid() && info->index_owner) release( info->index );
 		glDeleteVertexArrays( 1, &info->glid );
 		m_vertex_arrays.destroy( va );
@@ -223,6 +222,4 @@
 		glBindFramebuffer( GL_DRAW_FRAMEBUFFER, tinfo ? tinfo->glid : 0 );
 		unsigned filter = mask == clear_state::COLOR_BUFFER ? GL_LINEAR : GL_NEAREST;
-		int remove_below;
-		filter = GL_NEAREST;
 		glBlitFramebuffer( src1.x, src1.y, src2.x, src2.y, dst1.x, dst1.y, dst2.x, dst2.y, clear_state_buffers_to_mask( mask ), filter );
 		glBindFramebuffer( GL_READ_FRAMEBUFFER, 0 );
@@ -270,4 +267,5 @@
 }
 
+
 void nv::gl_context::bind( buffer b, texture t )
 {
@@ -304,4 +302,5 @@
 			set_active_texture( slot );
 			glBindTexture( texture_type_to_enum( info->type ), info->glid );
+			m_bound_textures[slot] = t;
 		}
 	}
@@ -314,5 +313,6 @@
 	if ( info )
 	{
-		glUseProgram( info->glid );
+		if ( m_bound_program != p )
+			glUseProgram( info->glid );
 		gdevice->update_uniforms( info );
 		if ( !info->validated )
@@ -320,4 +320,5 @@
 			validate_program( p );
 		}
+		m_bound_program = p;
 	}
 }
@@ -369,5 +370,7 @@
 void nv::gl_context::unbind( program )
 {
-	glUseProgram( 0 );
+	if ( m_bound_program )
+		glUseProgram( 0 );
+	m_bound_program = program();
 }
 
@@ -375,5 +378,8 @@
 {
 	if ( slot != m_active_slot )
+	{
 		glActiveTexture( GL_TEXTURE0 + static_cast<GLenum>( slot ) );
+		m_active_slot = slot;
+	}
 }
 
@@ -419,11 +425,11 @@
 		unsigned     gl_type = texture_type_to_enum( info->type );
 
-		if ( m_bound_textures[ m_active_slot ] != t )
-			glBindTexture( gl_type, info->glid );
-		int this_should_be_subTexImage;
+		bind( t, texture_slot::TEXTURE_0 );
 		if ( info->type == TEXTURE_3D || info->type == TEXTURE_2D_ARRAY )
-			glTexImage3D( gl_type, 0, static_cast<GLint>( nv::image_format_to_internal_enum( format.format ) ), size.x, size.y, size.z, 0, nv::image_format_to_enum( format.format ), nv::datatype_to_gl_enum( format.type ), data );
+//			glTexImage3D( gl_type, 0, static_cast<GLint>( nv::image_format_to_internal_enum( format.format ) ), size.x, size.y, size.z, 0, nv::image_format_to_enum( format.format ), nv::datatype_to_gl_enum( format.type ), data );
+			glTexSubImage3D( gl_type, 0, 0, 0, 0, size.x, size.y, size.z, nv::image_format_to_enum( format.format ), nv::datatype_to_gl_enum( format.type ), data );
 		else
-			glTexImage2D( gl_type, 0, static_cast<GLint>( nv::image_format_to_internal_enum(format.format) ), size.x, size.y, 0, nv::image_format_to_enum(format.format), nv::datatype_to_gl_enum(format.type), data );
+//			glTexImage2D( gl_type, 0, static_cast<GLint>( nv::image_format_to_internal_enum(format.format) ), size.x, size.y, 0, nv::image_format_to_enum(format.format), nv::datatype_to_gl_enum(format.type), data );
+			glTexSubImage2D( gl_type, 0, 0, 0, size.x, size.y, nv::image_format_to_enum( format.format ), nv::datatype_to_gl_enum( format.type ), data );
 	}
 }
@@ -518,7 +524,10 @@
 void gl_context::set_viewport( const ivec4& viewport )
 {
-	NV_ASSERT_ALWAYS( viewport.z > 0 && viewport.w > 0, "viewport dimensions must be greater than zero!" );
-	m_viewport = viewport;
-	glViewport( viewport.x, viewport.y, viewport.z, viewport.w );
+	if ( m_viewport != viewport )
+	{
+		NV_ASSERT_ALWAYS( viewport.z > 0 && viewport.w > 0, "viewport dimensions must be greater than zero!" );
+		m_viewport = viewport;
+		glViewport( viewport.x, viewport.y, viewport.z, viewport.w );
+	}
 }
 
@@ -860,4 +869,144 @@
 }
 
+nv::texture nv::gl_context::create_texture( texture_type type, ivec2 size, image_format aformat, sampler asampler, const void* data /*= nullptr */ )
+{
+	texture result = create_texture( type, aformat.format );
+	gl_texture_info* info = static_cast<gl_device*>( m_device )->get_full_texture_info( result );
+	bind( result, texture_slot::TEXTURE_0 );
+	unsigned glid = info->glid;
+	unsigned gl_type = texture_type_to_enum( type );
+	GLenum gl_internal = GLenum( image_format_to_internal_enum( aformat.format ) );
+	unsigned gl_enum = image_format_to_enum( aformat.format );
+
+	bool is_depth = aformat.format == DEPTH16 || aformat.format == DEPTH24 || aformat.format == DEPTH32;
+
+	// Detect if mipmapping was requested
+	// 	if ( gl_type == GL_TEXTURE_2D && gl_enum != GL_RED_INTEGER && asampler.filter_min != sampler::LINEAR && asampler.filter_min != sampler::NEAREST )
+	// 	{
+	// 		// TODO: This should not be done if we use framebuffers!
+	// 		glTexParameteri( gl_type, GL_GENERATE_MIPMAP, GL_TRUE);
+	// 	}
+
+	if ( asampler.filter_max != sampler::NEAREST )
+	{
+		asampler.filter_max = sampler::LINEAR;
+	}
+
+	if ( gl_type != GL_TEXTURE_2D_MULTISAMPLE )
+	{
+		glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_min ) ) );
+		glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_max ) ) );
+	}
+
+	if ( gl_type != GL_TEXTURE_2D_MULTISAMPLE && gl_enum != GL_RED_INTEGER )
+	{
+		glTexParameteri( gl_type, GL_TEXTURE_WRAP_S, GLint( nv::sampler_wrap_to_enum( asampler.wrap_s ) ) );
+		glTexParameteri( gl_type, GL_TEXTURE_WRAP_T, GLint( nv::sampler_wrap_to_enum( asampler.wrap_t ) ) );
+	}
+
+	if ( is_depth )
+	{
+		//		glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+		//		glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+
+		// This is to allow usage of shadow2DProj function in the shader
+		glTexParameteri( gl_type, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE );
+		glTexParameteri( gl_type, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL );
+	}
+
+	// #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+	// #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+	// 
+	// 	float aniso = 0.0f;
+	// 	glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &aniso );
+	// 	NV_LOG_INFO( "Anisotropy at ", aniso, " (", int( aniso ), " ) " );
+	// 	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso );
+
+	if ( gl_type != GL_TEXTURE_2D_MULTISAMPLE )
+		glTexImage2D( gl_type, 0, gl_internal, size.x, size.y, 0, gl_enum, nv::datatype_to_gl_enum( aformat.type ), data );
+	else
+		glTexImage2DMultisample( gl_type, 4, gl_internal, size.x, size.y, 1 );
+
+	if ( gl_type == GL_TEXTURE_2D && gl_enum != GL_RED_INTEGER && asampler.filter_min != sampler::LINEAR && asampler.filter_min != sampler::NEAREST )
+	{
+		// TODO: This should not be done if we use framebuffers!
+		glGenerateMipmap( gl_type );
+	}
+
+	bind( texture(), texture_slot::TEXTURE_0 );
+
+	info->type = type;
+	info->format = aformat;
+	info->tsampler = asampler;
+	info->size = ivec3( size.x, size.y, 1 );
+	info->glid = glid;
+
+	return result;
+}
+
+nv::texture nv::gl_context::create_texture( texture_type type, ivec3 size, image_format aformat, sampler asampler, const void* data /*= nullptr */ )
+{
+	texture result = create_texture( type, aformat.format );
+	gl_texture_info* info = static_cast<gl_device*>( m_device )->get_full_texture_info( result );
+	bind( result, texture_slot::TEXTURE_0 );
+	unsigned glid = info->glid;
+
+	unsigned gl_type = texture_type_to_enum( type );
+
+	bool is_depth = aformat.format == DEPTH16 || aformat.format == DEPTH24 || aformat.format == DEPTH32;
+
+	if ( asampler.filter_max != sampler::NEAREST )
+	{
+		asampler.filter_max = sampler::LINEAR;
+	}
+
+	glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_min ) ) );
+	glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_max ) ) );
+	glTexParameteri( gl_type, GL_TEXTURE_WRAP_S, GLint( nv::sampler_wrap_to_enum( asampler.wrap_s ) ) );
+	glTexParameteri( gl_type, GL_TEXTURE_WRAP_T, GLint( nv::sampler_wrap_to_enum( asampler.wrap_t ) ) );
+
+	if ( is_depth )
+	{
+		glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+		glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+
+		// This is to allow usage of shadow2DProj function in the shader
+		glTexParameteri( gl_type, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE );
+		glTexParameteri( gl_type, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL );
+	}
+
+	//glTexStorage3D( GL_TEXTURE_2D_ARRAY, mipLevelCount, GL_RGBA8, width, height, layerCount );
+	glTexImage3D( gl_type, 0, GLint( nv::image_format_to_internal_enum( aformat.format ) ), size.x, size.y, size.z, 0, nv::image_format_to_enum( aformat.format ), nv::datatype_to_gl_enum( aformat.type ), data );
+
+	bind( texture(), texture_slot::TEXTURE_0 );
+
+	info->type = type;
+	info->format = aformat;
+	info->tsampler = asampler;
+	info->size = size;
+	info->glid = glid;
+
+	return result;
+}
+
+nv::buffer nv::gl_context::create_buffer( buffer_type type, buffer_hint hint, size_t size, const void* source /*= nullptr */ )
+{
+	buffer result = static_cast<gl_device*>( m_device )->create_buffer( type, hint );
+	if ( size > 0 ) create_buffer( result, size, source );
+	return result;
+}
+
+void nv::gl_context::create_buffer( buffer b, size_t size, const void* source /*= nullptr */ )
+{
+	gl_buffer_info* info = static_cast<gl_device*>( m_device )->get_full_buffer_info( b );
+	if ( info )
+	{
+		unsigned glenum = buffer_type_to_enum( info->type );
+		glBindBuffer( glenum, info->glid );
+		glBufferData( glenum, GLsizeiptr( size ), source, buffer_hint_to_enum( info->hint ) );
+		glBindBuffer( glenum, 0 );
+	}
+}
+
 void nv::gl_context::set_draw_buffers( uint32 count, const output_slot* slots )
 {
Index: trunk/src/gl/gl_device.cc
===================================================================
--- trunk/src/gl/gl_device.cc	(revision 500)
+++ trunk/src/gl/gl_device.cc	(revision 501)
@@ -94,88 +94,6 @@
 }
 
-nv::texture nv::gl_device::create_texture( texture_type type, ivec2 size, image_format aformat, sampler asampler, const void* data /*= nullptr */ )
-{
-	NV_ASSERT_ALWAYS( type != TEXTURE_1D_BUFFER && type != TEXTURE_3D && type != TEXTURE_2D_ARRAY, "2D texture type expected!" );
-	unsigned glid = 0;
-	unsigned gl_type = texture_type_to_enum( type );
-	GLenum gl_internal = GLenum( nv::image_format_to_internal_enum( aformat.format ) );
-	unsigned gl_enum = nv::image_format_to_enum( aformat.format );
-
-	bool is_depth = aformat.format == DEPTH16 || aformat.format == DEPTH24 || aformat.format == DEPTH32;
-
-	glGenTextures( 1, &glid );
-
-	glBindTexture( gl_type, glid );
-
-	// Detect if mipmapping was requested
-// 	if ( gl_type == GL_TEXTURE_2D && gl_enum != GL_RED_INTEGER && asampler.filter_min != sampler::LINEAR && asampler.filter_min != sampler::NEAREST )
-// 	{
-// 		// TODO: This should not be done if we use framebuffers!
-// 		glTexParameteri( gl_type, GL_GENERATE_MIPMAP, GL_TRUE);
-// 	}
-
-	if ( asampler.filter_max != sampler::NEAREST )
-	{
-		asampler.filter_max = sampler::LINEAR;
-	}
-
-	if ( gl_type != GL_TEXTURE_2D_MULTISAMPLE )
-	{
-		glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_min ) ) );
-		glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_max ) ) );
-	}
-	
-	if ( gl_type != GL_TEXTURE_2D_MULTISAMPLE && gl_enum != GL_RED_INTEGER )
-	{
-		glTexParameteri( gl_type, GL_TEXTURE_WRAP_S, GLint( nv::sampler_wrap_to_enum( asampler.wrap_s ) ) );
-		glTexParameteri( gl_type, GL_TEXTURE_WRAP_T, GLint( nv::sampler_wrap_to_enum( asampler.wrap_t ) ) );
-	}
-
-	if ( is_depth )
-	{
-//		glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
-//		glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-
-		// This is to allow usage of shadow2DProj function in the shader
-		glTexParameteri( gl_type, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE );
-		glTexParameteri( gl_type, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL );
-	}
-
-// #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
-// #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
-// 
-// 	float aniso = 0.0f;
-// 	glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &aniso );
-// 	NV_LOG_INFO( "Anisotropy at ", aniso, " (", int( aniso ), " ) " );
-// 	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso );
-
-	if ( gl_type != GL_TEXTURE_2D_MULTISAMPLE )
-		glTexImage2D( gl_type, 0, gl_internal, size.x, size.y, 0, gl_enum, nv::datatype_to_gl_enum(aformat.type), data );
-	else
-		glTexImage2DMultisample( gl_type, 4, gl_internal, size.x, size.y, 1 );
-
-	if ( gl_type == GL_TEXTURE_2D && gl_enum != GL_RED_INTEGER && asampler.filter_min != sampler::LINEAR && asampler.filter_min != sampler::NEAREST )
-	{
-		// TODO: This should not be done if we use framebuffers!
-		glGenerateMipmap( gl_type );
-	}
-
-
-	glBindTexture( gl_type, 0 );
-
-	texture result = m_textures.create();
-	gl_texture_info* info = m_textures.get( result );
-	info->type     = type;
-	info->format   = aformat;
-	info->tsampler = asampler;
-	info->size     = ivec3( size.x, size.y, 1 );
-	info->glid     = glid;
-	return result;
-}
-
-
 nv::texture nv::gl_device::create_texture( texture_type type, pixel_format format )
 {
-	NV_ASSERT_ALWAYS( type == TEXTURE_1D_BUFFER, "create_texture not texture buffer!" );
 	unsigned glid = 0;
 
@@ -193,51 +111,4 @@
 }
 
-nv::texture nv::gl_device::create_texture( texture_type type, ivec3 size, image_format aformat, sampler asampler, const void* data /*= nullptr */ )
-{
-	NV_ASSERT_ALWAYS( type == TEXTURE_3D || type == TEXTURE_2D_ARRAY, "3D texture type expected!" );
-	unsigned glid = 0;
-	unsigned gl_type = texture_type_to_enum( type );
-
-	bool is_depth = aformat.format == DEPTH16 || aformat.format == DEPTH24 || aformat.format == DEPTH32;
-
-	glGenTextures( 1, &glid );
-	glBindTexture( gl_type, glid );
-
-	if ( asampler.filter_max != sampler::NEAREST )
-	{
-		asampler.filter_max = sampler::LINEAR;
-	}
-
-	glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_min ) ) );
-	glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GLint( nv::sampler_filter_to_enum( asampler.filter_max ) ) );
-	glTexParameteri( gl_type, GL_TEXTURE_WRAP_S, GLint( nv::sampler_wrap_to_enum( asampler.wrap_s ) ) );
-	glTexParameteri( gl_type, GL_TEXTURE_WRAP_T, GLint( nv::sampler_wrap_to_enum( asampler.wrap_t ) ) );
-
-	if ( is_depth )
-	{
-		glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
-		glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-
-		// This is to allow usage of shadow2DProj function in the shader
-		glTexParameteri( gl_type, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE );
-		glTexParameteri( gl_type, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL );
-	}
-
-	//glTexStorage3D( GL_TEXTURE_2D_ARRAY, mipLevelCount, GL_RGBA8, width, height, layerCount );
-	glTexImage3D( gl_type, 0, GLint( nv::image_format_to_internal_enum( aformat.format ) ), size.x, size.y, size.z, 0, nv::image_format_to_enum( aformat.format ), nv::datatype_to_gl_enum( aformat.type ), data );
-	glBindTexture( gl_type, 0 );
-
-	texture result = m_textures.create();
-	gl_texture_info* info = m_textures.get( result );
-	info->type = type;
-	info->format = aformat;
-	info->tsampler = asampler;
-	info->size = size;
-	info->glid = glid;
-	return result;
-}
-
-
-
 void nv::gl_device::release( texture t )
 {
@@ -271,16 +142,9 @@
 }
 
-nv::buffer nv::gl_device::create_buffer( buffer_type type, buffer_hint hint, size_t size, const void* source /*= nullptr */ )
+nv::buffer nv::gl_device::create_buffer( buffer_type type, buffer_hint hint )
 {
 	unsigned glid = 0;
 	unsigned glenum = buffer_type_to_enum( type );
 	glGenBuffers( 1, &glid );
-
-	if ( size > 0 )
-	{
-		glBindBuffer( glenum, glid );
-		glBufferData( glenum, GLsizeiptr( size ), source, buffer_hint_to_enum( hint ) );
-		glBindBuffer( glenum, 0 );
-	}
 
 	buffer result = m_buffers.create();
@@ -288,19 +152,7 @@
 	info->type = type;
 	info->hint = hint;
-	info->size = size;
+	info->size = 0;
 	info->glid = glid;
 	return result;
-}
-
-void nv::gl_device::create_buffer( buffer b, size_t size, const void* source )
-{
-	gl_buffer_info* info = m_buffers.get( b );
-	if ( info )
-	{
-		unsigned glenum = buffer_type_to_enum( info->type );
-		glBindBuffer( glenum, info->glid );
-		glBufferData( glenum, GLsizeiptr( size ), source, buffer_hint_to_enum( info->hint ) );
-		glBindBuffer( glenum, 0 );
-	}
 }
 
@@ -330,4 +182,15 @@
 		m_programs.destroy( p );
 	}
+}
+
+nv::gl_texture_info* nv::gl_device::get_full_texture_info( texture t )
+{
+	return m_textures.get( t );
+
+}
+
+nv::gl_buffer_info* nv::gl_device::get_full_buffer_info( buffer t )
+{
+	return m_buffers.get( t );
 }
 
Index: trunk/src/gui/gui_gfx_renderer.cc
===================================================================
--- trunk/src/gui/gui_gfx_renderer.cc	(revision 500)
+++ trunk/src/gui/gui_gfx_renderer.cc	(revision 501)
@@ -116,5 +116,5 @@
 	~screen_render_data()
 	{
-		ctx->get_device()->release( shader );
+		ctx->release( shader );
 		ctx->release( varray );
 	}
@@ -157,5 +157,5 @@
 	screen_render_data* sr = new screen_render_data( w->get_context(), 1024 );
 	m_render_data = sr;
-	sr->shader = m_window->get_device()->create_program( nv_gui_vertex_shader, nv_gui_fragment_shader );
+	sr->shader = m_window->get_context()->create_program( nv_gui_vertex_shader, nv_gui_fragment_shader );
 	m_scene_state.get_camera().set_ortho( 0.0f, float( m_window->get_width() ), float( m_window->get_height() ), 0.0f );
 
@@ -166,5 +166,5 @@
 
 	nv::sampler sampler( nv::sampler::LINEAR, nv::sampler::CLAMP_TO_EDGE );
-	sr->tex = m_window->get_device()->create_texture( m_atlas.get_size(), image_format( nv::RGBA, nv::UBYTE ), sampler, nullptr );
+	sr->tex = m_window->get_context()->create_texture( m_atlas.get_size(), image_format( nv::RGBA, nv::UBYTE ), sampler, nullptr );
 
 	m_render_state.depth_test.enabled = false;
@@ -395,5 +395,5 @@
 	if ( m_render_data )
 	{
-		m_context->get_device()->release( reinterpret_cast< screen_render_data* >( m_render_data )->tex );
+		m_context->release( reinterpret_cast< screen_render_data* >( m_render_data )->tex );
 		delete m_render_data;
 	}
Index: trunk/src/lib/gl.cc
===================================================================
--- trunk/src/lib/gl.cc	(revision 500)
+++ trunk/src/lib/gl.cc	(revision 501)
@@ -55,28 +55,28 @@
 
 
-static void* load_gl_ext_symbol_impl( const nv::string_view& name, nv::log_level fail_level = nv::LOG_DEBUG )
-{
-	void* result = gl_ext_loader( name.data() );
-	NV_LOG( ( result ? nv::LOG_DEBUG : fail_level ), "load_gl_ext_symbol : ", name, ( result ? " succeded." : "failed." ) );
-	return result;
-}
-
-static void* load_gl_ext_symbol( const nv::string_view& name, bool iterate, const nv::string_view& ext )
-{
-	void * result        = nullptr;
-	nv::string128 test_name = name + ext;
-	result = load_gl_ext_symbol_impl( !ext.empty() ? test_name : name );
-	if ( result ) return result;
-	if ( iterate )
-	{
-		test_name = name + "ARB"_ls;
-		result = gl_ext_loader( test_name.data() );
-		if ( result ) return result;
-		test_name = name + "EXT"_ls;
-		result = gl_ext_loader( test_name.data() );
-		if ( result ) return result;
-	}
-	return result;
-}
+// static void* load_gl_ext_symbol_impl( const nv::string_view& name, nv::log_level fail_level = nv::LOG_DEBUG )
+// {
+// 	void* result = gl_ext_loader( name.data() );
+// 	NV_LOG( ( result ? nv::LOG_DEBUG : fail_level ), "load_gl_ext_symbol : ", name, ( result ? " succeded." : "failed." ) );
+// 	return result;
+// }
+
+// static void* load_gl_ext_symbol( const nv::string_view& name, bool iterate, const nv::string_view& ext )
+// {
+// 	void * result        = nullptr;
+// 	nv::string128 test_name = name + ext;
+// 	result = load_gl_ext_symbol_impl( !ext.empty() ? test_name : name );
+// 	if ( result ) return result;
+// 	if ( iterate )
+// 	{
+// 		test_name = name + "ARB"_ls;
+// 		result = gl_ext_loader( test_name.data() );
+// 		if ( result ) return result;
+// 		test_name = name + "EXT"_ls;
+// 		result = gl_ext_loader( test_name.data() );
+// 		if ( result ) return result;
+// 	}
+// 	return result;
+// }
 
 bool nv::load_gl_library( const char* path, bool force_reload )
