Index: /trunk/nv/gfx/skeleton_instance.hh
===================================================================
--- /trunk/nv/gfx/skeleton_instance.hh	(revision 490)
+++ /trunk/nv/gfx/skeleton_instance.hh	(revision 491)
@@ -70,6 +70,7 @@
 
 		uint32 size() const { return m_offsets.size(); }
+//	protected:
+		dynamic_array< value_type >   m_offsets;
 	protected:
-		dynamic_array< value_type >   m_offsets;
 
 		template < typename T >
@@ -86,6 +87,7 @@
 		uint32 size() const { return m_indices.size(); }
 		uint32 skeleton_size() const { return m_bone_count; }
+//	protected:
+		dynamic_array< sint16 > m_indices;
 	protected:
-		dynamic_array< sint16 > m_indices;
 		data_descriptor         m_key;
 		uint32                  m_bone_count;
@@ -170,4 +172,26 @@
 			if ( bones.size() != m_matrix.size() ) m_matrix.resize( bones.size() );
 		}
+
+		void resize( uint32 new_size )
+		{
+			m_matrix.resize( new_size );
+		}
+
+		void assign( const skeleton_transforms& skeleton, const skeleton_binding& binding, const bone_transforms< value_type >& bones, uint32 offset )
+		{
+			uint32 sz = bones.size();
+			if ( m_matrix.size() < offset + sz ) m_matrix.resize( offset + sz );
+			const transform* transforms = skeleton.xforms();
+			for ( uint32 n = 0; n < skeleton.size(); ++n )
+			{
+				sint16 bone_id = binding.m_indices[n];
+				if ( bone_id >= 0 )
+				{
+					m_matrix[offset + bone_id] = ( transforms[n] * bones.m_offsets[bone_id] ).extract();
+				}
+			}
+		}
+
+
 	protected:
 
Index: /trunk/nv/gfx/sliced_buffer.hh
===================================================================
--- /trunk/nv/gfx/sliced_buffer.hh	(revision 490)
+++ /trunk/nv/gfx/sliced_buffer.hh	(revision 491)
@@ -202,7 +202,9 @@
 		void create_buffer( size_t size )
 		{
-			m_context->get_device()->release( m_buffer );
 			m_capacity = size;
-			m_buffer   = m_context->get_device()->create_buffer( m_type, m_hint, size * value_type_size, nullptr );
+			if ( m_buffer )
+				m_context->get_device()->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 );
 		}
 	private:
Index: /trunk/nv/gl/gl_context.hh
===================================================================
--- /trunk/nv/gl/gl_context.hh	(revision 490)
+++ /trunk/nv/gl/gl_context.hh	(revision 491)
@@ -24,4 +24,10 @@
 	};
 
+	struct gl_vertex_array_info : public vertex_array_info
+	{
+		unsigned glid;
+	};
+
+
 	class gl_context : public context
 	{
@@ -30,9 +36,8 @@
 		virtual ~gl_context();
 
-		virtual vertex_array create_vertex_array();
+		virtual vertex_array create_vertex_array( const vertex_array_desc& desc );
 		virtual framebuffer create_framebuffer();
 		virtual void release( vertex_array va );
 		virtual void release( framebuffer f );
-		virtual const vertex_array_info* get_vertex_array_info( vertex_array va ) const;
 		virtual const framebuffer_info* get_framebuffer_info( framebuffer f ) const;
 
@@ -49,8 +54,10 @@
 		virtual void bind( texture t, texture_slot slot );
 		virtual void bind( buffer b, uint32 index, size_t offset = 0, size_t size = 0 );
+		virtual void bind( buffer b, texture t );
+
 
 		virtual void update( texture t, const void* data );
 		virtual void update( buffer b, const void* data, size_t offset, size_t size );
-//		virtual void update( buffer b, uint32 index, const void* data, size_t offset, size_t size );
+		//		virtual void update( buffer b, uint32 index, const void* data, size_t offset, size_t size );
 
 		virtual void clear( const clear_state& cs );
@@ -75,6 +82,4 @@
 		void force_apply_render_state( const render_state& state );
 		void force_apply_stencil_face( unsigned face, const stencil_test_face& stencil );
-		// TODO: remove
-		virtual vertex_array_info* get_vertex_array_info_mutable( vertex_array );
 	private:
 		void apply_stencil_test( const stencil_test& stencil );
@@ -95,6 +100,6 @@
 		void* m_handle;
 
-		handle_store< vertex_array_info, vertex_array >  m_vertex_arrays;
-		handle_store< gl_framebuffer_info, framebuffer > m_framebuffers;
+		handle_store< gl_vertex_array_info, vertex_array > m_vertex_arrays;
+		handle_store< gl_framebuffer_info, framebuffer >   m_framebuffers;
 	};
 
Index: /trunk/nv/gl/gl_device.hh
===================================================================
--- /trunk/nv/gl/gl_device.hh	(revision 490)
+++ /trunk/nv/gl/gl_device.hh	(revision 491)
@@ -48,4 +48,6 @@
 		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 void release( buffer b );
Index: /trunk/nv/gui/gui_environment.hh
===================================================================
--- /trunk/nv/gui/gui_environment.hh	(revision 490)
+++ /trunk/nv/gui/gui_environment.hh	(revision 491)
@@ -40,4 +40,5 @@
 			void destroy_element( handle e );
 			bool process_io_event( const io_event& ev );
+			renderer* get_renderer() { return m_renderer; }
 			string_view get_string( shash64 h );
 			virtual ~environment();
Index: /trunk/nv/gui/gui_gfx_renderer.hh
===================================================================
--- /trunk/nv/gui/gui_gfx_renderer.hh	(revision 490)
+++ /trunk/nv/gui/gui_gfx_renderer.hh	(revision 491)
@@ -52,4 +52,5 @@
 			virtual void on_select_change( element* e );
 			virtual rectangle get_area() const { return m_area; }
+			virtual void set_shader( program p );
 			virtual ~gfx_renderer();
 		private:
Index: /trunk/nv/interface/context.hh
===================================================================
--- /trunk/nv/interface/context.hh	(revision 490)
+++ /trunk/nv/interface/context.hh	(revision 491)
@@ -47,5 +47,5 @@
 	struct vertex_array_info
 	{
-		static const int MAX_ATTRIBUTES = 24;
+		static const int MAX_ATTRIBUTES = 16;
 
 		uint32        count;
@@ -63,4 +63,84 @@
 	};
 
+	class vertex_array_desc : private vertex_array_info
+	{
+	private:
+		friend class context;
+		friend class gl_context;
+	public:
+		vertex_array_desc()
+		{
+			count = 0;
+			index = buffer();
+			index_owner = false;
+			index_type = USHORT;
+		}
+
+		template < typename VTX, slot SLOT >
+		void add_vertex_buffer( buffer vb, bool owned )
+		{
+			add_vertex_buffer_impl< VTX, SLOT >( vb, owned, has_slot< VTX, SLOT >() );
+		}
+
+		template < typename VTX >
+		void add_vertex_buffers( buffer vb, bool owned )
+		{
+			add_vertex_buffer< VTX, slot::POSITION >( vb, owned );
+			add_vertex_buffer< VTX, slot::TEXCOORD >( vb, owned );
+			add_vertex_buffer< VTX, slot::NORMAL   >( vb, owned );
+			add_vertex_buffer< VTX, slot::TANGENT >( vb, owned );
+			add_vertex_buffer< VTX, slot::BONEINDEX >( vb, owned );
+			add_vertex_buffer< VTX, slot::BONEWEIGHT >( vb, owned );
+			add_vertex_buffer< VTX, slot::COLOR >( vb, owned );
+		}
+
+		void add_vertex_buffers( buffer buf, const data_descriptor& descriptor )
+		{
+			for ( const auto& cslot : descriptor )
+			{
+				const datatype_info& info = get_datatype_info( cslot.etype );
+				add_vertex_buffer( cslot.vslot, buf, info.base, info.elements, cslot.offset, descriptor.element_size(), false );
+			}
+		}
+
+
+		// TODO: should be private
+		void add_vertex_buffer( slot location, buffer buf, datatype datatype, size_t components, size_t offset = 0, size_t stride = 0, bool owner = true )
+		{
+			NV_ASSERT( count < uint16( MAX_ATTRIBUTES ), "MAX_ATTRIBUTES reached!" );
+			vertex_buffer_attribute& p = attr[count];
+			p.vbuffer    = buf;
+			p.dtype      = datatype;
+			p.components = components;
+			p.offset     = offset;
+			p.stride     = stride;
+			p.owner      = owner;
+			p.location   = location;
+			count++;
+		}
+
+		// TODO: should be private
+		void set_index_buffer( buffer b, datatype datatype, bool owner )
+		{
+			index = b;
+			index_owner = owner;
+			index_type = datatype;
+		}
+	private:
+		template < typename VTX, slot SLOT >
+		void add_vertex_buffer_impl( buffer, bool, const false_type& )
+		{
+		}
+
+		template < typename VTX, slot SLOT >
+		void add_vertex_buffer_impl( buffer vb, bool owned, const true_type& )
+		{
+			typedef slot_info< VTX, SLOT > vinfo;
+			typedef datatype_traits< typename vinfo::value_type > dt_traits;
+			add_vertex_buffer( SLOT, vb, type_to_enum< typename dt_traits::base_type >::type, dt_traits::size, vinfo::offset, sizeof( VTX ), owned );
+		}
+
+	};
+
 	class context
 	{
@@ -71,10 +151,9 @@
 		}
 
-		virtual vertex_array create_vertex_array() = 0;
+		virtual vertex_array create_vertex_array( const vertex_array_desc& desc ) = 0;
 		virtual framebuffer create_framebuffer() = 0;
 		virtual void release( vertex_array ) = 0;
 		virtual void release( framebuffer ) = 0;
 
-		virtual const vertex_array_info* get_vertex_array_info( vertex_array ) const = 0;
 		virtual const framebuffer_info* get_framebuffer_info( framebuffer ) const = 0;
 
@@ -92,7 +171,9 @@
 		virtual void bind( texture, texture_slot ) = 0;
 		virtual void bind( buffer, uint32 /*index*/, size_t /*offset*/ = 0, size_t /*size */= 0 ) = 0;
+		virtual void bind( buffer, texture ) = 0;
 
 		virtual void update( texture, const void* ) = 0;
 		virtual void update( buffer, const void*, size_t /*offset*/, size_t /*size*/ ) = 0;
+
 //		virtual void update( buffer, uint32 /*index*/, const void* , size_t /*offset*/, size_t /*size*/ ) = 0;
 
@@ -116,45 +197,4 @@
 		}
 
-		template < typename VTX, slot SLOT >
-		void add_vertex_buffer_impl( vertex_array, buffer, bool, const false_type& )
-		{
-		}
-
-		template < typename VTX, slot SLOT >
-		void add_vertex_buffer_impl( vertex_array va, buffer vb, bool owned, const true_type& )
-		{
-			typedef slot_info< VTX, SLOT > vinfo;
-			typedef datatype_traits< typename vinfo::value_type > dt_traits;
-			add_vertex_buffer( va, SLOT, vb, type_to_enum< typename dt_traits::base_type >::type, dt_traits::size, vinfo::offset, sizeof( VTX ), owned );
-		}
-
-		template < typename VTX, slot SLOT >
-		void add_vertex_buffer( vertex_array va, buffer vb, bool owned )
-		{
-			add_vertex_buffer_impl< VTX, SLOT >( va, vb, owned, has_slot< VTX, SLOT >() );
-		}
-
-		template < typename VTX >
-		void add_vertex_buffers( vertex_array va, buffer vb, bool owned )
-		{
-			add_vertex_buffer< VTX, slot::POSITION >  ( va, vb, owned );
-			add_vertex_buffer< VTX, slot::TEXCOORD >  ( va, vb, owned );
-			add_vertex_buffer< VTX, slot::NORMAL   >  ( va, vb, owned );
-			add_vertex_buffer< VTX, slot::TANGENT >   ( va, vb, owned );
-			add_vertex_buffer< VTX, slot::BONEINDEX > ( va, vb, owned );
-			add_vertex_buffer< VTX, slot::BONEWEIGHT >( va, vb, owned );
-			add_vertex_buffer< VTX, slot::COLOR >     ( va, vb, owned );
-		}
-
-		void add_vertex_buffers( vertex_array va, buffer buf, const data_descriptor& descriptor )
-		{
-			for ( const auto& cslot : descriptor )
-			{
-				const datatype_info& info = get_datatype_info( cslot.etype );
-				add_vertex_buffer( va, cslot.vslot, buf, info.base, info.elements, cslot.offset, descriptor.element_size(), false );
-			}
-		}
-
-
 		template < typename VTXDATA >
 		enable_if_t< is_class< VTXDATA >::value, vertex_array >
@@ -174,8 +214,8 @@
 		vertex_array create_vertex_array( const VTX* v, size_t count, buffer_hint hint )
 		{
-			vertex_array va = create_vertex_array();
 			buffer       vb = m_device->create_buffer( VERTEX_BUFFER, hint, count * sizeof( VTX ), v );
-			add_vertex_buffers< VTX >( va, vb, true );
-			return va;
+			vertex_array_desc desc;
+			desc.add_vertex_buffers< VTX >( vb, true );
+			return create_vertex_array( desc );
 		}
 
@@ -183,106 +223,10 @@
 		vertex_array create_vertex_array( const VTX* v, size_t vcount, const IDX* i, size_t icount, buffer_hint hint )
 		{
-			vertex_array va = create_vertex_array( v, vcount, 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 );
-			set_index_buffer( va, ib, type_to_enum< IDX >::type, true );
-			return va;
-		}
-
-		void replace_vertex_buffer( vertex_array va, buffer vb, bool owner )
-		{
-			vertex_array_info* info = get_vertex_array_info_mutable( va );
-			if ( info )
-			{
-				for ( uint32 i = 0; i < info->count; ++i )
-				{
-					vertex_buffer_attribute& vba = info->attr[i];
-					if ( vba.owner ) m_device->release( vba.vbuffer );
-					vba.vbuffer = vb;
-					vba.owner   = owner;
-				}
-			}
-		}
-
-		void replace_vertex_buffer( vertex_array va, buffer vb, slot location, bool owner )
-		{
-			vertex_array_info* info = get_vertex_array_info_mutable( va );
-			if ( info )
-			{
-				for ( uint32 i = 0; i < info->count; ++i )
-				{
-					if ( info->attr[i].location == location )
-					{
-						vertex_buffer_attribute& vba = info->attr[i];
-						if ( vba.owner ) m_device->release( vba.vbuffer );
-						vba.vbuffer = vb;
-						vba.owner   = owner;
-					}
-				}
-			}
-		}
-
-		void update_attribute_offset( vertex_array va, slot location, size_t offset ) 
-		{
-			vertex_array_info* info = get_vertex_array_info_mutable( va );
-			if ( info )
-			{
-				for ( uint32 i = 0; i < info->count; ++i )
-				{
-					if ( info->attr[i].location == location )
-					{
-						info->attr[i].offset = offset;
-					}
-				}
-			}
-		}
-
-		void set_index_buffer( vertex_array va, buffer b, datatype datatype, bool owner ) 
-		{
-			vertex_array_info* info = get_vertex_array_info_mutable( va );
-			if ( info )
-			{
-				if ( m_device->get_buffer_info( b )->type == INDEX_BUFFER )
-				{
-					if (info->index.is_valid() && info->index_owner) m_device->release( info->index ); 
-
-					info->index       = b; 
-					info->index_owner = owner; 
-					info->index_type  = datatype;
-				}
-			}
-		}
-
-		virtual void add_vertex_buffer( vertex_array va, slot location, buffer buf, datatype datatype, size_t components, size_t offset = 0, size_t stride = 0, bool owner = true )
-		{
-			vertex_array_info* info = get_vertex_array_info_mutable( va );
-			if ( info )
-			{
-				NV_ASSERT( info->count < uint16( vertex_array_info::MAX_ATTRIBUTES ), "MAX_ATTRIBUTES reached!" );
-				vertex_buffer_attribute& p = info->attr[ info->count ];
-				p.vbuffer    = buf;
-				p.dtype      = datatype;
-				p.components = components;
-				p.offset     = offset;
-				p.stride     = stride;
-				p.owner      = owner;
-				p.location   = location;
-				info->count++;
-			}
-		}
-
-		buffer find_buffer( vertex_array va, slot location )
-		{
-			const vertex_array_info* info = get_vertex_array_info( va );
-			if ( info )
-			{
-				for ( uint32 i = 0; i < info->count; ++i )
-				{
-					if ( info->attr[i].location == location )
-					{
-						return info->attr[i].vbuffer;
-					}
-				}
-			}
-			return buffer();
+			vertex_array_desc desc;
+			desc.add_vertex_buffers< VTX >( vb, true );
+			desc.set_index_buffer( ib, type_to_enum< IDX >::type, true );
+			return create_vertex_array( desc );
 		}
 
@@ -290,5 +234,5 @@
 		vertex_array create_vertex_array( const data_channel_set* data, buffer_hint hint )
 		{
-			vertex_array  va = create_vertex_array();
+			vertex_array_desc va_desc;
 			for ( auto& channel : *data )
 			{
@@ -300,19 +244,18 @@
 					{
 						buffer b = m_device->create_buffer( INDEX_BUFFER, hint, channel.raw_size(), channel.raw_data() );
-						set_index_buffer( va, b, desc[0].etype, true );
+						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() );
-						add_vertex_buffers( va, b, desc );
+						va_desc.add_vertex_buffers( b, desc );
 					}
 				}
 			}
-			return va;
+			return create_vertex_array( va_desc );
 		}
 
 	protected:
-		// TODO: remove
-		virtual vertex_array_info* get_vertex_array_info_mutable( vertex_array ) = 0;
+
 
 		device*      m_device;
Index: /trunk/nv/interface/device.hh
===================================================================
--- /trunk/nv/interface/device.hh	(revision 490)
+++ /trunk/nv/interface/device.hh	(revision 491)
@@ -51,21 +51,32 @@
 		TEXTURE_1D_ARRAY,
 		TEXTURE_2D_ARRAY,
+		TEXTURE_1D_BUFFER,
 	};
 
 	enum texture_slot
 	{
-		TEX_DIFFUSE  = 0,
-		TEX_SPECULAR = 1,
-		TEX_NORMAL   = 2,
-		TEX_GLOSS    = 3,
-		TEX_EMISSIVE = 4,
-		TEXTURE_0    = 0,
-		TEXTURE_1    = 1,
-		TEXTURE_2    = 2,
-		TEXTURE_3    = 3,
-		TEXTURE_4    = 4,
-		TEXTURE_5    = 5,
-		TEXTURE_6    = 6,
-		TEXTURE_7    = 7,
+		TEX_DIFFUSE   = 0,
+		TEX_NORMAL    = 1,
+		TEX_METALLIC  = 2,
+		TEX_SPECULAR  = 2, // obsolete
+		TEX_ROUGHNESS = 3,
+		TEX_GLOSS     = 3, // obsolete
+		TEX_EMISSIVE  = 4,
+		TEXTURE_0     = 0,
+		TEXTURE_1     = 1,
+		TEXTURE_2     = 2,
+		TEXTURE_3     = 3,
+		TEXTURE_4     = 4,
+		TEXTURE_5     = 5,
+		TEXTURE_6     = 6,
+		TEXTURE_7     = 7,
+		TEXTURE_8     = 8,
+		TEXTURE_9     = 9,
+		TEXTURE_10    = 10,
+		TEXTURE_11    = 11,
+		TEXTURE_12    = 12,
+		TEXTURE_13    = 13,
+		TEXTURE_14    = 14,
+		TEXTURE_15    = 15,
 	};
 
@@ -136,4 +147,5 @@
 		INDEX_BUFFER,
 		UNIFORM_BUFFER,
+		TEXTURE_BUFFER,
 	};
 
@@ -184,6 +196,12 @@
 		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 ) = 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
@@ -307,17 +325,19 @@
 
 			engine_link_uniform_factory_map& factory_link_map = get_link_uniform_factory();
-			factory_link_map[ "nv_texture_0" ] = new engine_link_uniform_int<0>();
-			factory_link_map[ "nv_texture_1" ] = new engine_link_uniform_int<1>();
-			factory_link_map[ "nv_texture_2" ] = new engine_link_uniform_int<2>();
-			factory_link_map[ "nv_texture_3" ] = new engine_link_uniform_int<3>();
-			factory_link_map[ "nv_texture_4" ] = new engine_link_uniform_int<4>();
-			factory_link_map[ "nv_texture_5" ] = new engine_link_uniform_int<5>();
-			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_t_diffuse" ] = new engine_link_uniform_int<0>();
-			factory_link_map[ "nv_t_specular"] = new engine_link_uniform_int<1>();
-			factory_link_map[ "nv_t_normal"  ] = new engine_link_uniform_int<2>();
-			factory_link_map[ "nv_t_gloss"   ] = new engine_link_uniform_int<3>();
-			factory_link_map[ "nv_t_emissive"] = new engine_link_uniform_int<4>();
+			factory_link_map[ "nv_texture_0"  ] = new engine_link_uniform_int<0>();
+			factory_link_map[ "nv_texture_1"  ] = new engine_link_uniform_int<1>();
+			factory_link_map[ "nv_texture_2"  ] = new engine_link_uniform_int<2>();
+			factory_link_map[ "nv_texture_3"  ] = new engine_link_uniform_int<3>();
+			factory_link_map[ "nv_texture_4"  ] = new engine_link_uniform_int<4>();
+			factory_link_map[ "nv_texture_5"  ] = new engine_link_uniform_int<5>();
+			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_t_diffuse"  ] = new engine_link_uniform_int<int( TEX_DIFFUSE )>();
+			factory_link_map[ "nv_t_normal"   ] = new engine_link_uniform_int<int( TEX_NORMAL )>();
+			factory_link_map[ "nv_t_metallic" ] = new engine_link_uniform_int<int( TEX_METALLIC )>();
+			factory_link_map[ "nv_t_specular" ] = new engine_link_uniform_int<int( TEX_METALLIC )>();
+			factory_link_map[ "nv_t_roughness"] = new engine_link_uniform_int<int( TEX_ROUGHNESS )>();
+			factory_link_map[ "nv_t_gloss"    ] = new engine_link_uniform_int<int( TEX_ROUGHNESS )>();
+			factory_link_map[ "nv_t_emissive" ] = new engine_link_uniform_int<int( TEX_EMISSIVE )>();
 		}
 		void destroy_engine_uniforms()
Index: /trunk/nv/interface/image_data.hh
===================================================================
--- /trunk/nv/interface/image_data.hh	(revision 490)
+++ /trunk/nv/interface/image_data.hh	(revision 491)
@@ -36,4 +36,10 @@
 		DEPTH24,
 		DEPTH32,
+		R8I,
+		R8UI,
+		R16I,
+		R16UI,
+		R32I,
+		R32UI,
 	};
 	
Index: /trunk/nv/lib/gl.hh
===================================================================
--- /trunk/nv/lib/gl.hh	(revision 490)
+++ /trunk/nv/lib/gl.hh	(revision 491)
@@ -89,9 +89,9 @@
 	};
 
-	const char* get_gl_extension_name( gl_extensions extension );
-	bool load_gl_extension( gl_extensions extension );
-	gl_extensions load_gl_extensions( uint32 extensions );
-	bool is_gl_extension_loaded( gl_extensions extensions );
-	bool are_gl_extensions_loaded( uint32 extensions );
+//	const char* get_gl_extension_name( gl_extensions extension );
+//	bool load_gl_extension( gl_extensions extension );
+//	gl_extensions load_gl_extensions( uint32 extensions );
+//	bool is_gl_extension_loaded( gl_extensions extensions );
+//	bool are_gl_extensions_loaded( uint32 extensions );
 	bool load_gl_no_context( const char* path = NV_GL_PATH );
 	/* Dynamic load support */
Index: /trunk/nv/lua/lua_values.hh
===================================================================
--- /trunk/nv/lua/lua_values.hh	(revision 490)
+++ /trunk/nv/lua/lua_values.hh	(revision 491)
@@ -140,4 +140,12 @@
 
 		template <>
+		struct pass_traits<float>
+		{
+			static void push( lua_State *L, float s ) { detail::push_number( L, static_cast<double>( s ) ); }
+			static float to( lua_State *L, int index ) { return static_cast<float>( detail::to_number( L, index ) ); }
+			static float to( lua_State *L, int index, lnumber def ) { return static_cast<float>( detail::to_number( L, index, def ) ); }
+		};
+
+		template <>
 		struct pass_traits<bool>
 		{
@@ -202,5 +210,5 @@
 			struct lua_type_impl< T, enable_if_t< is_floating_point< T >::value > >
 			{
-				typedef lnumber type;
+				typedef T type;
 			};
 
Index: /trunk/src/engine/material_manager.cc
===================================================================
--- /trunk/src/engine/material_manager.cc	(revision 490)
+++ /trunk/src/engine/material_manager.cc	(revision 491)
@@ -39,5 +39,5 @@
 
 		// HACK
- 		for ( uint32 i = 0; i < 5; ++i )
+ 		for ( uint32 i = 0; i < 8; ++i )
  			if ( result->textures[i].is_nil() )
  				result->textures[i] = m_default;
@@ -59,11 +59,37 @@
 bool material_manager::load_resource( nv::lua::table_guard& table, nv::shash64 id )
 {
+	c_file_system fs;
 	material* m = new material;
-	m->paths[ TEX_DIFFUSE ]  = table.get_string128( "diffuse" );
-	m->paths[ TEX_SPECULAR ] = table.get_string128( "specular" );
-	m->paths[ TEX_NORMAL ]   = table.get_string128( "normal" );
-	m->paths[ TEX_EMISSIVE ] = table.get_string128( "emissive" );
-	m->paths[ TEX_GLOSS ]    = table.get_string128( "gloss" );
+
+	if ( table.is_string( "path" ) )
+	{
+		string128 path = table.get_string128( "path" );
+		for ( uint32 i = 0; i < 5; ++i )
+			m->paths[i] = path;
+		m->paths[TEX_DIFFUSE].append( "_diffuse.png" );
+		m->paths[TEX_NORMAL].append( "_normal.png" );
+		m->paths[TEX_METALLIC].append( "_metallic.png" );
+		m->paths[TEX_ROUGHNESS].append( "_roughness.png" );
+		m->paths[TEX_EMISSIVE].append( "_emissive.png" );
+		for ( uint32 i = 0; i < 5; ++i )
+		{
+			if ( !fs.exists( m->paths[i] ) )
+			{
+				if ( i != TEX_EMISSIVE )
+					NV_LOG_ERROR( "Texture file not found! : ", m->paths[i] );
+				m->paths[i].clear();
+			}
+		}
+	}
+	else
+	{
+		m->paths[ TEX_DIFFUSE ]  = table.get_string128( "diffuse" );
+		m->paths[ TEX_NORMAL ]   = table.get_string128( "normal" );
+		m->paths[ TEX_METALLIC]  = table.get_string128( "metallic" );
+		m->paths[ TEX_ROUGHNESS] = table.get_string128( "roughness" );
+		m->paths[ TEX_EMISSIVE ] = table.get_string128( "emissive" );
+	}
 	add( id, m );
 	return true;
 }
+
Index: /trunk/src/engine/particle_engine.cc
===================================================================
--- /trunk/src/engine/particle_engine.cc	(revision 490)
+++ /trunk/src/engine/particle_engine.cc	(revision 491)
@@ -497,6 +497,9 @@
 	info->particles = new particle[ data->quota ];
 	info->quads     = new particle_quad[ data->quota ];
-	info->vtx_array = m_context->create_vertex_array<particle_vtx>( info->quads[0].data, data->quota*6, STREAM_DRAW );
-	info->vtx_buffer = m_context->find_buffer( info->vtx_array, slot::POSITION );
+
+	vertex_array_desc desc;
+	info->vtx_buffer = m_device->create_buffer( VERTEX_BUFFER, STREAM_DRAW, data->quota * 6 * sizeof( particle_vtx ), info->quads[0].data );
+	desc.add_vertex_buffers< particle_vtx >( info->vtx_buffer, true );
+	info->vtx_array = m_context->create_vertex_array( desc );
 	info->last_update = m_last_update;
 	info->test = false;
Index: /trunk/src/formats/assimp_loader.cc
===================================================================
--- /trunk/src/formats/assimp_loader.cc	(revision 490)
+++ /trunk/src/formats/assimp_loader.cc	(revision 491)
@@ -188,5 +188,5 @@
 
 	uint8*  cdata   = maccess.add_channel( desc, mesh->mNumVertices ).raw_data();
-	uint16* indices = reinterpret_cast<uint16*>( maccess.add_channel< index_u16 >( mesh->mNumFaces * 3 ).raw_data() );
+	uint32* indices = reinterpret_cast<uint32*>( maccess.add_channel< index_u32 >( mesh->mNumFaces * 3 ).raw_data() );
 
 	if ( mesh->mTangents && mesh->mBitangents )
@@ -239,5 +239,5 @@
 		for (unsigned int j=0; j<face->mNumIndices; j++)
 		{
-			indices[ i*3 + j ] = uint16( face->mIndices[j] );
+			indices[ i*3 + j ] = uint32( face->mIndices[j] );
 		}
 	}
Index: /trunk/src/gfx/debug_draw.cc
===================================================================
--- /trunk/src/gfx/debug_draw.cc	(revision 490)
+++ /trunk/src/gfx/debug_draw.cc	(revision 491)
@@ -25,7 +25,8 @@
 #version 120
 varying vec3 v_color;
+out vec4 o_frag_color;
 void main(void)
 {
-	gl_FragColor = vec4( v_color, 1.0 );
+	o_frag_color = vec4( v_color, 1.0 );
 }
 )";
@@ -44,7 +45,8 @@
 		if ( m_va.is_valid() ) m_context->release( m_va );
 		m_buffer_size = nv::max( m_data.size(), 4096U, m_buffer_size );
-		m_va = m_context->create_vertex_array();
 		m_vb = m_context->get_device()->create_buffer( VERTEX_BUFFER, nv::STREAM_DRAW, m_buffer_size * sizeof( debug_vtx ), m_data.data() );
-		m_context->add_vertex_buffers< debug_vtx >( m_va, m_vb, true );
+		vertex_array_desc va_desc;
+		va_desc.add_vertex_buffers< debug_vtx >( m_vb, true );
+		m_va = m_context->create_vertex_array( va_desc );
 	}
 	else
Index: /trunk/src/gfx/mesh_creator.cc
===================================================================
--- /trunk/src/gfx/mesh_creator.cc	(revision 490)
+++ /trunk/src/gfx/mesh_creator.cc	(revision 491)
@@ -388,5 +388,5 @@
 	{
 	case USHORT: swap_culling_impl< uint16 >( m_idx_channel ); break;
-	case UINT: swap_culling_impl< uint16 >( m_idx_channel ); break;
+	case UINT: swap_culling_impl< uint32 >( m_idx_channel ); break;
 	default: NV_ASSERT( false, "Swap culling supports only unsigned and unsigned short indices!" ); break;
 	}
Index: /trunk/src/gl/gl_context.cc
===================================================================
--- /trunk/src/gl/gl_context.cc	(revision 490)
+++ /trunk/src/gl/gl_context.cc	(revision 491)
@@ -14,12 +14,70 @@
 using namespace nv;
 
-nv::vertex_array nv::gl_context::create_vertex_array()
+nv::vertex_array nv::gl_context::create_vertex_array( const vertex_array_desc& desc )
 {
 	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;
+	gl_vertex_array_info* info = m_vertex_arrays.get( result );
+
+	glGenVertexArrays( 1, &info->glid );
+	info->count       = desc.count;
+	info->index       = desc.index;
+	info->index_owner = desc.index_owner;
+	info->index_type  = desc.index_type;
+
+	for ( uint32 i = 0; i < desc.count; ++i )
+		info->attr[i] = desc.attr[i];
+
+	glBindVertexArray( info->glid );
+
+	for ( uint32 i = 0; i < info->count; ++i )
+	{
+		const vertex_buffer_attribute& vba = info->attr[i];
+		uint32 location = static_cast<uint32>( vba.location );
+		glEnableVertexAttribArray( location );
+		const gl_buffer_info* vinfo = static_cast<const gl_buffer_info*>( m_device->get_buffer_info( vba.vbuffer ) );
+		if ( vinfo && vinfo->type == VERTEX_BUFFER )
+			glBindBuffer( GL_ARRAY_BUFFER, vinfo->glid );
+		else
+		{
+			// TODO: report error
+		}
+
+		glVertexAttribPointer(
+			location,
+			static_cast<GLint>( vba.components ),
+			nv::datatype_to_gl_enum( vba.dtype ),
+			GL_FALSE,
+			static_cast<GLsizei>( vba.stride ),
+			reinterpret_cast<void*>( vba.offset )
+			);
+	}
+	glBindBuffer( GL_ARRAY_BUFFER, 0 );
+
+	if ( info->index.is_valid() )
+	{
+		const gl_buffer_info* iinfo = static_cast<const gl_buffer_info*>( m_device->get_buffer_info( info->index ) );
+		if ( iinfo && iinfo->type == INDEX_BUFFER )
+		{
+			glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, iinfo->glid );
+		}
+		else
+		{
+			// TODO: report error
+		}
+	}
+	glBindBuffer( GL_ARRAY_BUFFER, 0 );
+	glBindVertexArray( 0 );
+
+	if ( info->index.is_valid() )
+	{
+		glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
+	}
+
+	for ( uint32 i = 0; i < info->count; ++i )
+	{
+		glDisableVertexAttribArray( static_cast<uint32>( info->attr[i].location ) );
+	}
+
+
 	return result;
 }
@@ -27,21 +85,17 @@
 nv::framebuffer nv::gl_context::create_framebuffer()
 {
-	if ( is_gl_extension_loaded( GL_EXT_FRAMEBUFFER_OBJECT ) && is_gl_extension_loaded( GL_EXT_FRAMEBUFFER_BLIT ) )
-	{
-		unsigned glid   = 0;
-		glGenFramebuffers( 1, &glid );
-		framebuffer result = m_framebuffers.create();
-		gl_framebuffer_info* info = m_framebuffers.get( result );
-		info->glid = glid;
-		info->depth_rb_glid = 0;
-		info->color_attachment_count = 0;
-		return result;
-	}
-	else return framebuffer();
+	unsigned glid   = 0;
+	glGenFramebuffers( 1, &glid );
+	framebuffer result = m_framebuffers.create();
+	gl_framebuffer_info* info = m_framebuffers.get( result );
+	info->glid = glid;
+	info->depth_rb_glid = 0;
+	info->color_attachment_count = 0;
+	return result;
 }
 
 void nv::gl_context::release( vertex_array va )
 {
-	vertex_array_info* info = m_vertex_arrays.get( va );
+	gl_vertex_array_info* info = m_vertex_arrays.get( va );
 	if ( info )
 	{
@@ -52,4 +106,5 @@
 		}
 		if ( info->index.is_valid() && info->index_owner) m_device->release( info->index );
+		glDeleteVertexArrays( 1, &info->glid );
 		m_vertex_arrays.destroy( va );
 	}
@@ -71,17 +126,7 @@
 }
 
-const vertex_array_info* nv::gl_context::get_vertex_array_info( vertex_array va ) const 
-{
-	return m_vertex_arrays.get( va );
-}
-
 const framebuffer_info* nv::gl_context::get_framebuffer_info( framebuffer f ) const
 {
 	return m_framebuffers.get( f );
-}
-
-vertex_array_info* nv::gl_context::get_vertex_array_info_mutable( vertex_array va ) 
-{
-	return m_vertex_arrays.get( va );
 }
 
@@ -170,23 +215,17 @@
  	glDrawBuffer( 0 );
  	glReadBuffer( 0 );
-	if ( is_gl_extension_loaded( GL_EXT_FRAMEBUFFER_OBJECT ) && is_gl_extension_loaded( GL_EXT_FRAMEBUFFER_BLIT ) )
-	{
-		unsigned result = glCheckFramebufferStatus( framebuffer_slot_to_enum(ft) );
-		if ( result == GL_FRAMEBUFFER_COMPLETE ) return true;
-		switch ( result )
-		{
-		case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT         : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete attachment!" ); break;
-		case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : NV_LOG_ERROR( "gl_context::check : Framebuffer missing attachment!" ); break;
+
+	unsigned result = glCheckFramebufferStatus( framebuffer_slot_to_enum(ft) );
+	if ( result == GL_FRAMEBUFFER_COMPLETE ) return true;
+	switch ( result )
+	{
+	case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT         : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete attachment!" ); break;
+	case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : NV_LOG_ERROR( "gl_context::check : Framebuffer missing attachment!" ); break;
 //		case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS         : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete dimensions!" ); break;
 //		case GL_FRAMEBUFFER_INCOMPLETE_FORMATS            : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete formats!" ); break;
-		case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER        : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete draw buffer!" ); break;
-		case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER        : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete read buffer!" ); break;
-		case GL_FRAMEBUFFER_UNSUPPORTED                   : NV_LOG_ERROR( "gl_context::check : Framebuffer format combination unsupported!" ); break;
-		default: NV_LOG_ERROR( "gl_context::check : Unknown Framebuffer error! (", result, ")" ); break;
-		}
-	}
-	else
-	{
-		NV_LOG_ERROR( "gl_context::check : Framebuffer extensions not loaded!" );
+	case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER        : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete draw buffer!" ); break;
+	case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER        : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete read buffer!" ); break;
+	case GL_FRAMEBUFFER_UNSUPPORTED                   : NV_LOG_ERROR( "gl_context::check : Framebuffer format combination unsupported!" ); break;
+	default: NV_LOG_ERROR( "gl_context::check : Unknown Framebuffer error! (", result, ")" ); break;
 	}
 	glDrawBuffer( GL_BACK );
@@ -205,4 +244,19 @@
 	{
 		glBindFramebuffer( framebuffer_slot_to_enum(ft), 0 );
+	}
+}
+
+void nv::gl_context::bind( buffer b, texture t )
+{
+	const gl_buffer_info*  binfo = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
+	const gl_texture_info* tinfo = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
+	NV_ASSERT( binfo && tinfo, "Bad buffer or texture passed to create_texture" );
+	if ( binfo && tinfo )
+	{
+		NV_ASSERT_ALWAYS( binfo->type == TEXTURE_BUFFER && tinfo->type == TEXTURE_1D_BUFFER, "bad texture or buffer type!" );
+		glActiveTexture( GL_TEXTURE0 );
+		glBindTexture( GL_TEXTURE_BUFFER, tinfo->glid );
+		glTexBuffer( GL_TEXTURE_BUFFER, image_format_to_internal_enum( tinfo->format.format ), binfo->glid );
+		glBindTexture( GL_TEXTURE_BUFFER, 0 );
 	}
 }
@@ -252,43 +306,8 @@
 void nv::gl_context::bind( vertex_array va )
 {
-	const vertex_array_info* info = m_vertex_arrays.get( va );
-	if ( info )
-	{
-		for ( uint32 i = 0; i < info->count; ++i ) 
-		{
-			const vertex_buffer_attribute& vba = info->attr[i];
-			uint32 location                    = static_cast<uint32>( vba.location );
-			glEnableVertexAttribArray( location );
-			const gl_buffer_info* vinfo = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( vba.vbuffer ) );
-			if ( vinfo && vinfo->type == VERTEX_BUFFER )
-				glBindBuffer( GL_ARRAY_BUFFER, vinfo->glid );
-			else
-			{
-				// TODO: report error
-			}
-
-			glVertexAttribPointer(
-				location,
-				static_cast<GLint>( vba.components ),
-				nv::datatype_to_gl_enum( vba.dtype ),
-				GL_FALSE,
-				static_cast<GLsizei>( vba.stride ),
-				reinterpret_cast<void*>( vba.offset )
-				);
-		}
-		glBindBuffer( GL_ARRAY_BUFFER, 0 );
-
-		if ( info->index.is_valid() )
-		{
-			const gl_buffer_info* iinfo = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( info->index ) );
-			if ( iinfo && iinfo->type == INDEX_BUFFER )
-			{
-				glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, iinfo->glid );
-			}
-			else
-			{
-				// TODO: report error
-			}
-		}
+	gl_vertex_array_info* info = m_vertex_arrays.get( va );
+	if ( info )
+	{
+		glBindVertexArray( info->glid );
 	}
 }
@@ -313,13 +332,5 @@
 	if ( info )
 	{
-		if ( info->index.is_valid() )
-		{
-			glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
-		}
-
-		for ( uint32 i = 0; i < info->count; ++i ) 
-		{
-			glDisableVertexAttribArray( static_cast<uint32>( info->attr[i].location ) );
-		}
+		glBindVertexArray( 0 );
 	}
 }
@@ -340,4 +351,5 @@
 {
 	const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
+	NV_ASSERT_ALWAYS( info->type != TEXTURE_1D_BUFFER, "Buffer texture passed to update!" );
 	if ( info )
 	{
@@ -347,4 +359,5 @@
 
 		glBindTexture( gl_type, info->glid );
+		int this_should_be_subTexImage;
 		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 );
@@ -722,7 +735,6 @@
 {
 	// TODO: configurable:
-	load_gl_extensions( GL_EXT_FRAMEBUFFER_BLIT | GL_EXT_FRAMEBUFFER_OBJECT | GL_EXT_TEXTURE_ARRAY );
+//	load_gl_extensions( GL_EXT_FRAMEBUFFER_BLIT | GL_EXT_FRAMEBUFFER_OBJECT | GL_EXT_TEXTURE_ARRAY );
 	force_apply_render_state( m_render_state );
-
 }
 
Index: /trunk/src/gl/gl_device.cc
===================================================================
--- /trunk/src/gl/gl_device.cc	(revision 490)
+++ /trunk/src/gl/gl_device.cc	(revision 491)
@@ -17,5 +17,5 @@
 gl_device::gl_device()
 {
-	m_shader_header.append( "#version 330\n" );
+	m_shader_header.append( "#version 330 core\n" );
 	for ( auto& i : get_uniform_factory() ) 
 		m_shader_header.append( "uniform "+datatype_to_glsl_type( i.second->get_datatype() )+" "+ i.first +";\n" );
@@ -95,7 +95,9 @@
 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_3D && type != TEXTURE_2D_ARRAY, "2D texture type expected!" );
+	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 );
+	GLint gl_internal = GLint( 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;
@@ -106,5 +108,5 @@
 
 	// Detect if mipmapping was requested
-	if ( gl_type == GL_TEXTURE_2D && asampler.filter_min != sampler::LINEAR && asampler.filter_min != sampler::NEAREST )
+	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!
@@ -119,6 +121,10 @@
 	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 ( 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 )
@@ -140,5 +146,5 @@
 // 	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso );
 
-	glTexImage2D( gl_type, 0, GLint( nv::image_format_to_internal_enum(aformat.format) ), size.x, size.y, 0, nv::image_format_to_enum(aformat.format), nv::datatype_to_gl_enum(aformat.type), data );
+	glTexImage2D( gl_type, 0, gl_internal, size.x, size.y, 0, gl_enum, nv::datatype_to_gl_enum(aformat.type), data );
 
 	glBindTexture( gl_type, 0 );
@@ -154,4 +160,24 @@
 }
 
+
+nv::texture nv::gl_device::create_texture( texture_type type, pixel_format format )
+{
+	NV_ASSERT_ALWAYS( type == TEXTURE_1D_BUFFER );
+	unsigned glid = 0;
+	unsigned gl_type = texture_type_to_enum( type );
+
+	glGenTextures( 1, &glid );
+
+	texture result = m_textures.create();
+	gl_texture_info* info = m_textures.get( result );
+	info->type = type;
+	info->format = format;
+	info->tsampler = sampler();
+	info->size = ivec3( 1, 1, 1 );
+	info->glid = glid;
+
+	return result;
+}
+
 nv::texture nv::gl_device::create_texture( texture_type type, ivec3 size, image_format aformat, sampler asampler, const void* data /*= nullptr */ )
 {
@@ -234,11 +260,14 @@
 nv::buffer nv::gl_device::create_buffer( buffer_type type, buffer_hint hint, size_t size, const void* source /*= nullptr */ )
 {
-	unsigned glid   = 0;
+	unsigned glid = 0;
 	unsigned glenum = buffer_type_to_enum( type );
 	glGenBuffers( 1, &glid );
 
-	glBindBuffer( glenum, glid );
-	glBufferData( glenum, GLsizeiptr( size ), source, buffer_hint_to_enum( hint ) );
-	glBindBuffer( glenum, 0 );
+	if ( size > 0 )
+	{
+		glBindBuffer( glenum, glid );
+		glBufferData( glenum, GLsizeiptr( size ), source, buffer_hint_to_enum( hint ) );
+		glBindBuffer( glenum, 0 );
+	}
 
 	buffer result = m_buffers.create();
@@ -249,4 +278,16 @@
 	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 );
+	}
 }
 
Index: /trunk/src/gl/gl_enum.cc
===================================================================
--- /trunk/src/gl/gl_enum.cc	(revision 490)
+++ /trunk/src/gl/gl_enum.cc	(revision 491)
@@ -15,11 +15,12 @@
 	switch( type )
 	{
-	case TEXTURE_1D      : return GL_TEXTURE_1D;
-	case TEXTURE_2D      : return GL_TEXTURE_2D;
-	case TEXTURE_RECT    : return GL_TEXTURE_RECTANGLE;
-	case TEXTURE_3D      : return GL_TEXTURE_3D;
-	case TEXTURE_CUBE    : return GL_TEXTURE_CUBE_MAP;
- 	case TEXTURE_1D_ARRAY: return GL_TEXTURE_1D_ARRAY;
- 	case TEXTURE_2D_ARRAY: return GL_TEXTURE_2D_ARRAY;
+	case TEXTURE_1D       : return GL_TEXTURE_1D;
+	case TEXTURE_2D       : return GL_TEXTURE_2D;
+	case TEXTURE_RECT     : return GL_TEXTURE_RECTANGLE;
+	case TEXTURE_3D       : return GL_TEXTURE_3D;
+	case TEXTURE_CUBE     : return GL_TEXTURE_CUBE_MAP;
+ 	case TEXTURE_1D_ARRAY : return GL_TEXTURE_1D_ARRAY;
+ 	case TEXTURE_2D_ARRAY : return GL_TEXTURE_2D_ARRAY;
+	case TEXTURE_1D_BUFFER: return GL_TEXTURE_BUFFER;
 	NV_RETURN_COVERED_DEFAULT( 0 );
 	}
@@ -171,4 +172,5 @@
 	case INDEX_BUFFER   : return GL_ELEMENT_ARRAY_BUFFER;
 	case UNIFORM_BUFFER : return GL_UNIFORM_BUFFER;
+	case TEXTURE_BUFFER : return GL_TEXTURE_BUFFER;
 		NV_RETURN_COVERED_DEFAULT( 0 );
 	}
@@ -193,4 +195,10 @@
 	case DEPTH24 : return GL_DEPTH_COMPONENT;
 	case DEPTH32 : return GL_DEPTH_COMPONENT;
+	case R8I     : return GL_RED_INTEGER;
+	case R8UI    : return GL_RED_INTEGER;
+	case R16I    : return GL_RED_INTEGER;
+	case R16UI   : return GL_RED_INTEGER;
+	case R32I    : return GL_RED_INTEGER;
+	case R32UI   : return GL_RED_INTEGER;
 	NV_RETURN_COVERED_DEFAULT( 0 );
 	}
@@ -215,4 +223,10 @@
 	case DEPTH24 : return GL_DEPTH_COMPONENT24;
 	case DEPTH32:  return GL_DEPTH_COMPONENT32;
+	case R8I     : return GL_R8I;
+	case R8UI    : return GL_R8UI;
+	case R16I    : return GL_R16I;
+	case R16UI   : return GL_R16UI;
+	case R32I    : return GL_R32I;
+	case R32UI   : return GL_R32UI;
 	NV_RETURN_COVERED_DEFAULT( 0 );
 	}
@@ -358,4 +372,22 @@
 	case GL_SAMPLER_1D_ARRAY_SHADOW: return INT;
 	case GL_SAMPLER_2D_ARRAY_SHADOW: return INT;
+	case GL_SAMPLER_BUFFER         : return INT;
+
+	case GL_INT_SAMPLER_1D                : return INT;
+	case GL_INT_SAMPLER_2D                : return INT;
+	case GL_INT_SAMPLER_3D                : return INT;
+	case GL_INT_SAMPLER_2D_RECT           : return INT;
+	case GL_INT_SAMPLER_CUBE              : return INT;
+	case GL_INT_SAMPLER_1D_ARRAY          : return INT;
+	case GL_INT_SAMPLER_2D_ARRAY          : return INT;
+	case GL_INT_SAMPLER_BUFFER            : return INT;
+	case GL_UNSIGNED_INT_SAMPLER_1D       : return INT;
+	case GL_UNSIGNED_INT_SAMPLER_2D       : return INT;
+	case GL_UNSIGNED_INT_SAMPLER_3D       : return INT;
+	case GL_UNSIGNED_INT_SAMPLER_2D_RECT  : return INT;
+	case GL_UNSIGNED_INT_SAMPLER_CUBE     : return INT;
+	case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY : return INT;
+	case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY : return INT;
+	case GL_UNSIGNED_INT_SAMPLER_BUFFER   : return INT;
 		// TODO: implement?
 //	case GL_BOOL	
Index: /trunk/src/gui/gui_gfx_renderer.cc
===================================================================
--- /trunk/src/gui/gui_gfx_renderer.cc	(revision 490)
+++ /trunk/src/gui/gui_gfx_renderer.cc	(revision 491)
@@ -12,5 +12,5 @@
 
 static const char *nv_gui_vertex_shader = R"(
-#version 130
+#version 330
 in vec2 nv_position;
 in vec2 nv_texcoord;
@@ -28,12 +28,14 @@
 
 static const char *nv_gui_fragment_shader = R"(
-#version 130
+#version 330
 in vec4 v_color;
 in vec2 v_texcoord;
 uniform sampler2D nv_t_diffuse;
+out vec4 o_frag_color;
+
 void main(void)
 {
 	vec4 tex_color = texture2D( nv_t_diffuse, v_texcoord );
-	gl_FragColor   = v_color * tex_color;
+	o_frag_color   = v_color * tex_color;
 }
 )";
@@ -158,7 +160,8 @@
 	m_scene_state.get_camera().set_ortho( 0.0f, float( m_window->get_width() ), float( m_window->get_height() ), 0.0f );
 
-	sr->varray = m_window->get_context()->create_vertex_array();
 	buffer vb = sr->buffer.get_buffer();
-	m_window->get_context()->add_vertex_buffers< vertex >( sr->varray, vb, false );
+	vertex_array_desc va_desc;
+	va_desc.add_vertex_buffers< vertex >( vb, true );
+	sr->varray = m_window->get_context()->create_vertex_array( va_desc );
 
 	nv::sampler sampler( nv::sampler::LINEAR, nv::sampler::CLAMP_TO_EDGE );
@@ -377,6 +380,6 @@
 	if ( sr->buffer.commit() )
 	{
-		buffer vb = sr->buffer.get_buffer();
-		m_context->replace_vertex_buffer( sr->varray, vb, false );
+// 		buffer vb = sr->buffer.get_buffer();
+// 		m_context->replace_vertex_buffer( sr->varray, vb, false );
 	}
 	m_context->bind( sr->tex, TEX_DIFFUSE );
@@ -401,2 +404,7 @@
 	m_style.load_flags( e );
 }
+
+void nv::gui::gfx_renderer::set_shader( program p )
+{
+	static_cast<screen_render_data*>( m_render_data )->shader = p;
+}
Index: /trunk/src/lib/gl.cc
===================================================================
--- /trunk/src/lib/gl.cc	(revision 490)
+++ /trunk/src/lib/gl.cc	(revision 491)
@@ -226,5 +226,5 @@
 #endif
 }
-
+/*
 const char* nv::get_gl_extension_name( gl_extensions extension )
 {
@@ -311,3 +311,5 @@
 	return true;
 }
-
+*/
+
+
Index: /trunk/src/lua/lua_area.cc
===================================================================
--- /trunk/src/lua/lua_area.cc	(revision 490)
+++ /trunk/src/lua/lua_area.cc	(revision 491)
@@ -161,5 +161,5 @@
 		}
 	}
-	if (c->y != a->ul.y && c->y != a->lr.y && c->x == a->ul.x + 1 ) c->x = a->ul.x;
+	if (c->y != a->ul.y && c->y != a->lr.y && c->x == a->ul.x + 1 ) c->x = a->lr.x;
 
 
@@ -313,5 +313,5 @@
 {
 	nv::ivec2 c = to_coord( L, 1 );
-	int amount = static_cast< int >( lua_tointeger( L, 1 ) );
+	int amount = static_cast< int >( lua_tointeger( L, 2 ) );
 	nv::ivec2 shift( amount, amount );
 	push_area( L, nv::rectangle( c - shift, c + shift ) );
Index: /trunk/src/sdl/sdl_window.cc
===================================================================
--- /trunk/src/sdl/sdl_window.cc	(revision 490)
+++ /trunk/src/sdl/sdl_window.cc	(revision 491)
@@ -30,6 +30,9 @@
 	//	SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, 4 );
 
-	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
-	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
+ 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
+
+	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE );
+
 	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
 
