Index: trunk/nv/gfx/debug_draw.hh
===================================================================
--- trunk/nv/gfx/debug_draw.hh	(revision 301)
+++ trunk/nv/gfx/debug_draw.hh	(revision 302)
@@ -31,5 +31,5 @@
 		void reset();
 		program*      get_program()      { return m_program; }
-		vertex_array* get_vertex_array() { return m_va; }
+		vertex_array  get_vertex_array() { return m_va; }
 		uint32        get_count()        { return m_data.size(); }
 
@@ -40,5 +40,5 @@
 		device*                  m_device;
 		program*                 m_program;
-		vertex_array*            m_va;
+		vertex_array             m_va;
 		std::vector< debug_vtx > m_data;
 	};
Index: trunk/nv/gfx/keyframed_mesh.hh
===================================================================
--- trunk/nv/gfx/keyframed_mesh.hh	(revision 301)
+++ trunk/nv/gfx/keyframed_mesh.hh	(revision 302)
@@ -19,5 +19,6 @@
 	{
 	public:
-		keyframed_mesh( const mesh_data* a_data, const mesh_nodes_data* a_tag_map );
+		keyframed_mesh( context* a_context, const mesh_data* a_data, const mesh_nodes_data* a_tag_map );
+		virtual vertex_array get_vertex_array() const { return m_va; }
 		virtual size_t get_index_count() const { return m_index_count; }
 		virtual void run_animation( animation_entry* a_anim );
@@ -50,4 +51,8 @@
 		const mesh_nodes_data*  m_tag_map;
 		const mesh_raw_channel* m_vchannel;
+
+		context*     m_context;
+		buffer       m_pbuffer;
+		vertex_array m_va;
 
 		uint32 m_last_frame;
@@ -86,8 +91,5 @@
 		~keyframed_mesh_cpu();
 	private:
-		context* m_context;
-
-		uint8*         m_data;
-		vertex_buffer* m_vb;
+		uint8*  m_data;
 	};
 
Index: trunk/nv/gfx/skeletal_mesh.hh
===================================================================
--- trunk/nv/gfx/skeletal_mesh.hh	(revision 301)
+++ trunk/nv/gfx/skeletal_mesh.hh	(revision 302)
@@ -19,9 +19,17 @@
 	{
 	public:
-		skeletal_mesh() : animated_mesh() {}
+		skeletal_mesh( context* a_context ) : animated_mesh(), m_context( a_context ) {}
+		virtual vertex_array get_vertex_array() const { return m_va; }
 		virtual void run_animation( animation_entry* a_anim )
 		{
 			update_animation( a_anim, 0 );
 		}
+		~skeletal_mesh()
+		{
+			m_context->get_device()->release( m_va );
+		}
+	protected:
+		vertex_array m_va;
+		context*     m_context;
 	};
 
@@ -44,7 +52,6 @@
 		virtual size_t get_index_count() const { return m_indices; }
 		virtual void update_animation( animation_entry* a_anim, uint32 a_anim_time );
-		virtual ~skeletal_mesh_cpu();
 	protected:
-		context*                     m_context;
+		buffer                       m_pbuffer;
 		uint32                       m_indices;
 		dynamic_array< md5_vtx_pnt > m_pntdata;
Index: trunk/nv/gfx/sliced_buffer.hh
===================================================================
--- trunk/nv/gfx/sliced_buffer.hh	(revision 301)
+++ trunk/nv/gfx/sliced_buffer.hh	(revision 302)
@@ -93,11 +93,12 @@
 		static const size_t value_type_size = sizeof(T);
 
-		sliced_buffer( context* ctx, buffer_hint hint, size_t initial_size, bool is_vertex = true ) 
+		sliced_buffer( context* ctx, buffer_type type, buffer_hint hint, size_t initial_size ) 
 			: m_context( ctx )
-			, m_buffer( nullptr )
+			, m_buffer()
+			, m_type( type )
 			, m_hint( hint )
 			, m_full_update( true )
-			, m_is_vertex( is_vertex )
 			, m_data()
+			, m_capacity(0)
 			, m_min(0)
 			, m_max(0)
@@ -168,8 +169,5 @@
 				size_t offset = m_min * value_type_size;
 				size_t size   = (m_max-m_min) * value_type_size;
-				if ( m_is_vertex )
-					m_context->update( (vertex_buffer*)m_buffer, m_data.data() + m_min, offset, size );
-				else
-					m_context->update( (index_buffer*)m_buffer, m_data.data() + m_min, offset, size );
+				m_context->update( m_buffer, m_data.data() + m_min, offset, size );
 			}
 			m_full_update = false;
@@ -181,5 +179,5 @@
 		size_t get_max_size() const
 		{ 
-			return m_buffer->get_size() / value_type_size;
+			return m_capacity;
 		}
 
@@ -189,5 +187,5 @@
 		}
 
-		buffer* get_buffer()
+		buffer get_buffer()
 		{ 
 			return m_buffer; 
@@ -196,22 +194,21 @@
 		virtual ~sliced_buffer() 
 		{
-			delete m_buffer;
+			m_context->get_device()->release( m_buffer );
 		}
 	private:
 		void create_buffer( size_t size )
 		{
-			delete m_buffer;
-			if ( m_is_vertex )
-				m_buffer = m_context->get_device()->create_vertex_buffer( m_hint, size * value_type_size, nullptr );
-			else
-				m_buffer = m_context->get_device()->create_index_buffer( m_hint, size * value_type_size, nullptr );
+			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 );
 		}
 	private:
 		context*    m_context;
-		buffer*     m_buffer;
+		buffer      m_buffer;
 		buffer_hint m_hint;
+		buffer_type m_type;
 		bool        m_full_update;
-		bool        m_is_vertex;
 		vector      m_data;
+		uint32      m_capacity;
 
 		size_t      m_min;
@@ -275,6 +272,6 @@
 
 		indexed_sliced_buffer( device* dev, buffer_hint hint, int initial_size, int initial_index_size )
-			: m_vertex_buffer( dev, hint, initial_size, true )
-			, m_index_buffer( dev, hint, initial_index_size, false )
+			: m_vertex_buffer( dev, VERTEX_BUFFER, hint, initial_size )
+			, m_index_buffer( dev, INDEX_BUFFER, hint, initial_index_size )
 		{
 
@@ -298,6 +295,5 @@
 		int get_vertex_size()     const { return m_vertex_buffer.get_size(); }
 		int get_index_size()      const { return m_index_buffer.get_size(); }
-		vertex_buffer* get_vertex_buffer() { return static_cast<vertex_buffer*>( m_vertex_buffer.get_buffer() ); }
-		index_buffer*  get_index_buffer()  { return static_cast<index_buffer*>( m_index_buffer.get_buffer() ); }
+		buffer* get_buffer() { return m_vertex_buffer.get_buffer(); }
 		sliced_vertex_buffer& get_vertex_cache() { return m_vertex_buffer; }
 		sliced_index_buffer&  get_index_cache()  { return m_index_buffer; }
Index: trunk/nv/gl/gl_context.hh
===================================================================
--- trunk/nv/gl/gl_context.hh	(revision 301)
+++ trunk/nv/gl/gl_context.hh	(revision 302)
@@ -25,19 +25,16 @@
 		virtual void bind( texture t, texture_slot slot );
 		virtual void bind( program* p );
-		virtual void bind( vertex_buffer* b );
-		virtual void bind( index_buffer* b );
-		virtual void bind( vertex_array* va );
+		virtual void bind( buffer b );
+		virtual void bind( vertex_array va );
 		virtual void unbind( program* p );
-		virtual void unbind( index_buffer* b );
-		virtual void unbind( vertex_buffer* b );
-		virtual void unbind( vertex_array* va );
+		virtual void unbind( buffer b );
+		virtual void unbind( vertex_array va );
 
 		virtual void update( texture t, void* data );
-		virtual void update( index_buffer* b, const void* data, size_t offset, size_t size );
-		virtual void update( vertex_buffer* b, const void* data, size_t offset, size_t size );
+		virtual void update( buffer b, const void* data, size_t offset, size_t size );
 
 		virtual void clear( const clear_state& cs );
 		// temporary
-		virtual void draw( primitive prim, const render_state& rs, program* p, vertex_array* va, size_t count );
+		virtual void draw( primitive prim, const render_state& rs, program* p, vertex_array va, size_t count );
 		virtual const ivec4& get_viewport();
 		virtual void set_viewport( const ivec4& viewport );
Index: trunk/nv/gl/gl_device.hh
===================================================================
--- trunk/nv/gl/gl_device.hh	(revision 301)
+++ trunk/nv/gl/gl_device.hh	(revision 302)
@@ -22,4 +22,9 @@
 	};
 
+	struct gl_buffer_info : public buffer_info
+	{
+		unsigned glid;
+	};
+
 	class gl_device : public device
 	{
@@ -28,15 +33,16 @@
 		virtual window* create_window( uint16 width, uint16 height, bool fullscreen );
 		virtual window* adopt_window( void* sys_w_handle, void* sys_dc );
+		virtual image_data* create_image_data( const std::string& filename ); // temporary
+
 		virtual program* create_program( const string& vs_source, const string& fs_source );
-		virtual vertex_buffer* create_vertex_buffer( buffer_hint hint, size_t size, const void* source = nullptr );
-		virtual index_buffer* create_index_buffer( buffer_hint hint, size_t size, const void* source = nullptr );
-		virtual vertex_array* create_vertex_array();
-		virtual image_data* create_image_data( const std::string& filename ); // temporary
+		virtual buffer create_buffer( buffer_type type, buffer_hint hint, size_t size, const void* source = nullptr );
+		virtual texture create_texture( ivec2 size, image_format aformat, sampler asampler, void* data = nullptr );
 		virtual uint32 get_ticks();
 		virtual void delay( uint32 ms );
 
-		virtual texture create_texture( ivec2 size, image_format aformat, sampler asampler, void* data = nullptr );
-		virtual void release_texture( texture t );
+		virtual void release( buffer b );
+		virtual void release( texture t );
 		virtual const texture_info* get_texture_info( texture t );
+		virtual const buffer_info* get_buffer_info( buffer t );
 
 		virtual ~gl_device();
@@ -44,4 +50,5 @@
 		const void* m_info;
 		entity_store< gl_texture_info, texture > m_textures;
+		entity_store< gl_buffer_info,  buffer >  m_buffers;
 	};
 
Index: trunk/nv/gl/gl_enum.hh
===================================================================
--- trunk/nv/gl/gl_enum.hh	(revision 301)
+++ trunk/nv/gl/gl_enum.hh	(revision 302)
@@ -33,4 +33,5 @@
 	unsigned int stencil_operation_to_enum( stencil_test_face::operation type );
 	unsigned int buffer_hint_to_enum( buffer_hint hint );
+	unsigned int buffer_type_to_enum( buffer_type type );
 	unsigned int image_format_to_enum( pixel_format format );
 	unsigned int sampler_filter_to_enum( sampler::filter filter );
Index: trunk/nv/gl/gl_vertex_buffer.hh
===================================================================
--- trunk/nv/gl/gl_vertex_buffer.hh	(revision 301)
+++ 	(revision )
@@ -1,44 +1,0 @@
-// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
-// http://chaosforge.org/
-//
-// This file is part of NV Libraries.
-// For conditions of distribution and use, see copyright notice in nv.hh
-/**
- * @file gl_vertex_buffer.hh
- * @author Kornel Kisielewicz epyon@chaosforge.org
- * @brief Vertex buffer implementation
- */
-
-#ifndef NV_GL_VERTEX_BUFFER_HH
-#define NV_GL_VERTEX_BUFFER_HH
-
-#include <nv/interface/vertex_buffer.hh>
-
-namespace nv
-{
-
-	class gl_vertex_buffer : public vertex_buffer
-	{
-	public:
-		friend class gl_context;
-
-		gl_vertex_buffer( buffer_hint hint, size_t size, const void* data = nullptr );
-		~gl_vertex_buffer();
-	private:
-		unsigned glid;
-	};
-
-	class gl_index_buffer : public index_buffer
-	{
-	public:
-		friend class gl_context;
-
-		gl_index_buffer( buffer_hint hint, size_t size, const void* data = nullptr );
-		~gl_index_buffer();
-	private:
-		unsigned glid;
-	};
-
-} // namespace nv
-
-#endif // NV_GL_VERTEX_BUFFER_HH
Index: trunk/nv/gui/gui_renderer.hh
===================================================================
--- trunk/nv/gui/gui_renderer.hh	(revision 301)
+++ trunk/nv/gui/gui_renderer.hh	(revision 302)
@@ -33,10 +33,10 @@
 		struct vertex
 		{
-			ivec2 coord;
-			vec2  tcoord;
+			ivec2 position;
+			vec2  texcoord;
 			vec4  color;
 			vertex() {}
 			vertex( const nv::ivec2& cr, const nv::vec2& tc, const nv::vec4& c )
-				: coord( cr ), tcoord( tc ), color( c ) {}
+				: position( cr ), texcoord( tc ), color( c ) {}
 		};
 
Index: trunk/nv/interface/context.hh
===================================================================
--- trunk/nv/interface/context.hh	(revision 301)
+++ trunk/nv/interface/context.hh	(revision 302)
@@ -37,18 +37,13 @@
 	{
 	public:
-		mesh_interface() : m_va( nullptr ) {}
-		explicit mesh_interface( vertex_array* array ) : m_va( array ) {}
+		mesh_interface() {}
 		virtual void update( uint32 ) {}
 		virtual void update( program* ) {}
-		virtual nv::vertex_array* get_vertex_array() const { return m_va; }
-		virtual size_t get_index_count() const { return 0; }
+		virtual nv::vertex_array get_vertex_array() const = 0;
+		virtual size_t get_index_count() const = 0;
 		virtual nv::primitive get_primitive_type() const { return nv::TRIANGLES; }
 		virtual ~mesh_interface() {}
-	protected:
-		vertex_array* m_va;
 	};
 
-	class device;
-	class texture2d;
 	class context
 	{
@@ -61,19 +56,16 @@
 		}
 		virtual void bind( texture, texture_slot ) = 0;
-		virtual void bind( vertex_buffer* ) = 0;
-		virtual void bind( index_buffer* ) = 0;
+		virtual void bind( buffer ) = 0;
 		virtual void bind( program* ) = 0;
-		virtual void bind( vertex_array* ) = 0;
-		virtual void unbind( vertex_buffer* ) = 0;
-		virtual void unbind( index_buffer* ) = 0;
+		virtual void bind( vertex_array ) = 0;
+		virtual void unbind( buffer ) = 0;
 		virtual void unbind( program* ) = 0;
-		virtual void unbind( vertex_array* ) = 0;
+		virtual void unbind( vertex_array ) = 0;
 		virtual void update( texture, void* ) = 0;
-		virtual void update( index_buffer*, const void*, size_t /*offset*/, size_t /*size*/ ) = 0;
-		virtual void update( vertex_buffer*, const void*, size_t /*offset*/, size_t /*size*/ ) = 0;
+		virtual void update( buffer, const void*, size_t /*offset*/, size_t /*size*/ ) = 0;
 
 		virtual void clear( const clear_state& cs ) = 0;
 		// temporary
-		virtual void draw( primitive prim, const render_state& rs, program* p, vertex_array* va, size_t count ) = 0;
+		virtual void draw( primitive prim, const render_state& rs, program* p, vertex_array va, size_t count ) = 0;
 
 		virtual void draw( const render_state& rs, program* p, const mesh_interface* mesh )
@@ -86,5 +78,5 @@
 			draw( rs, p, mesh );
 		}
-		virtual void draw( primitive prim, const render_state& rs, const scene_state& s, program* p, vertex_array* va, size_t count )
+		virtual void draw( primitive prim, const render_state& rs, const scene_state& s, program* p, vertex_array va, size_t count )
 		{
 			p->apply_engine_uniforms( this, &s );
@@ -102,4 +94,9 @@
 		}
 	protected:
+		vertex_array_info* get_vertex_array_info( vertex_array va )
+		{
+			return m_device->m_vertex_arrays.get( va );
+		}
+
 		device*      m_device;
 		clear_state  m_clear_state;
Index: trunk/nv/interface/device.hh
===================================================================
--- trunk/nv/interface/device.hh	(revision 301)
+++ trunk/nv/interface/device.hh	(revision 302)
@@ -25,4 +25,12 @@
 	class program;
 
+	struct texture_tag {};
+	struct vertex_array_tag {};
+	struct buffer_tag {};
+	typedef handle< uint32, 16, 16, buffer_tag >       buffer;
+	typedef handle< uint32, 16, 16, texture_tag >      texture;
+	typedef handle< uint32, 16, 16, vertex_array_tag > vertex_array;
+
+
 	struct sampler
 	{
@@ -57,4 +65,12 @@
 	};
 
+	struct buffer_info
+	{
+		buffer_type type;
+		buffer_hint hint;
+		size_t      size;
+	};
+
+
 	struct texture_info
 	{
@@ -64,24 +80,42 @@
 	};
 
-
-	struct texture_tag {};
-	typedef handle< uint32, 16, 16, texture_tag > texture;
+	struct vertex_buffer_attribute
+	{
+		buffer   vbuffer;
+		datatype dtype;
+		size_t   components;
+		size_t   offset;
+		size_t   stride;
+		slot     location;
+		bool     owner;
+	};
+
+	struct vertex_array_info
+	{
+		static const int MAX_ATTRIBUTES = 24;
+
+		uint32        count;
+		buffer        index;
+		bool          index_owner;
+		datatype      index_type;
+		vertex_buffer_attribute attr[MAX_ATTRIBUTES];
+	};
 
 	class device
 	{
+		friend class context;
 	public:
 		virtual window* create_window( uint16 width, uint16 height, bool fullscreen ) = 0;
 		virtual window* adopt_window( void* sys_w_handle, void* sys_dc ) = 0;
 		virtual program* create_program( const string& vs_source, const string& fs_source ) = 0;
-		virtual vertex_buffer* create_vertex_buffer( buffer_hint hint, size_t size, const void* source = nullptr ) = 0;
-		virtual index_buffer* create_index_buffer( buffer_hint hint, size_t size, const void* source = nullptr ) = 0;
-		virtual vertex_array* create_vertex_array() = 0;
+		virtual buffer create_buffer( buffer_type type, buffer_hint hint, size_t size, const void* source = nullptr ) = 0;
 		virtual image_data* create_image_data( const std::string& filename ) = 0; // temporary
 		virtual texture create_texture( ivec2 size, image_format aformat, sampler asampler, void* data = nullptr ) = 0;
-		virtual void release_texture( texture ) = 0;
+		virtual void release( texture ) = 0;
+		virtual void release( buffer ) = 0;
 		virtual const texture_info* get_texture_info( texture ) = 0;
+		virtual const buffer_info* get_buffer_info( buffer ) = 0;
 		virtual uint32 get_ticks() = 0;
 		virtual void delay( uint32 ms ) = 0;
-
 		virtual texture create_texture( image_data* data, sampler asampler ) 
 		{
@@ -89,30 +123,51 @@
 		}
 
+		virtual vertex_array create_vertex_array()
+		{
+			vertex_array result = m_vertex_arrays.create();
+			vertex_array_info* info = m_vertex_arrays.get( result );
+			info->count       = 0;
+			info->index       = buffer();
+			info->index_owner = false;
+			info->index_type  = USHORT;
+			return result;
+		}
+
+		virtual void release( vertex_array va )
+		{
+			vertex_array_info* info = m_vertex_arrays.get( va );
+			if ( info )
+			{
+				for ( uint32 i = 0; i < info->count; ++i )
+				{
+					if ( info->attr[i].owner ) release( info->attr[i].vbuffer );
+				}
+				if ( info->index.is_valid() && info->index_owner) release( info->index );
+				m_vertex_arrays.destroy( va );
+			}
+		};
+
 		template < typename VTX, slot SLOT >
-		void add_vertex_buffer_impl( vertex_array*, vertex_buffer*, const std::false_type& )
+		void add_vertex_buffer_impl( vertex_array, buffer, const std::false_type& )
 		{
 		}
 
 		template < typename VTX, slot SLOT >
-		void add_vertex_buffer_impl( vertex_array* va, vertex_buffer* vb, const std::true_type& )
+		void add_vertex_buffer_impl( vertex_array va, buffer vb, const std::true_type& )
 		{
 			typedef vertex_slot_info< VTX, SLOT > vinfo;
 			typedef datatype_traits< typename vinfo::value_type > dt_traits;
-			va->add_vertex_buffer( SLOT, vb, type_to_enum< dt_traits::base_type >::type, dt_traits::size, vinfo::offset, sizeof( VTX ), false );
+			add_vertex_buffer( va, SLOT, vb, type_to_enum< dt_traits::base_type >::type, dt_traits::size, vinfo::offset, sizeof( VTX ), false );
 		}
 
 		template < typename VTX, slot SLOT >
-		void add_vertex_buffer( vertex_array* va, vertex_buffer* vb )
+		void add_vertex_buffer( vertex_array va, buffer vb )
 		{
 			add_vertex_buffer_impl< VTX, SLOT >( va, vb, std::integral_constant< bool, vertex_has_slot< VTX, SLOT >::value >() );
 		}
 
-
 		template < typename VTX >
-		vertex_array* create_vertex_array( const VTX* v, size_t count, buffer_hint hint )
-		{
-			// TODO: vb will not be owned or freed!
-			vertex_array*  va = create_vertex_array();
-			vertex_buffer* vb = create_vertex_buffer( hint, count * sizeof( VTX ), v );
+		void add_vertex_buffers( vertex_array va, buffer vb )
+		{
 			add_vertex_buffer< VTX, slot::POSITION >  ( va, vb );
 			add_vertex_buffer< VTX, slot::TEXCOORD >  ( va, vb );
@@ -122,9 +177,28 @@
 			add_vertex_buffer< VTX, slot::BONEWEIGHT >( va, vb );
 			add_vertex_buffer< VTX, slot::COLOR >     ( va, vb );
+		}
+
+		void add_vertex_buffers( vertex_array va, buffer buf, const mesh_raw_channel* channel )
+		{
+			for ( uint32 s = 0; s < channel->desc.count; ++s )
+			{
+				const vertex_descriptor_slot& slot = channel->desc.slots[s];
+				const datatype_info& info = get_datatype_info(slot.etype);
+				add_vertex_buffer( va, slot.vslot, buf, info.base , info.elements, slot.offset, channel->desc.size, false );
+			}
+		}
+
+		template < typename VTX >
+		vertex_array create_vertex_array( const VTX* v, size_t count, buffer_hint hint )
+		{
+			// TODO: vb will not be owned or freed!
+			vertex_array va = create_vertex_array();
+			buffer       vb = create_buffer( VERTEX_BUFFER, hint, count * sizeof( VTX ), v );
+			add_vertex_buffers< VTX >( va, vb );
 			return va;
 		}
 
 		template < typename VTX >
-		vertex_array* create_vertex_array( const std::vector< VTX >& data, buffer_hint hint )
+		vertex_array create_vertex_array( const std::vector< VTX >& data, buffer_hint hint )
 		{
 			return create_vertex_array( data.data(), data.size(), hint );
@@ -132,8 +206,8 @@
 
 		template < typename VTX, typename IDX >
-		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 );
-			index_buffer* ib = create_index_buffer( hint, icount * sizeof( IDX ), i );
+		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       ib = create_buffer( INDEX_BUFFER, hint, icount * sizeof( IDX ), i );
 			va->set_index_buffer( ib, type_to_enum< IDX >::type, true );
 			return va;
@@ -141,13 +215,111 @@
 
 		template < typename VTX, typename IDX >
-		vertex_array* create_vertex_array( const std::vector< VTX >& data, const std::vector< IDX >& idata, buffer_hint hint )
+		vertex_array create_vertex_array( const std::vector< VTX >& data, const std::vector< IDX >& idata, buffer_hint hint )
 		{
 			return create_vertex_array( data.data(), data.size(), idata.data(), idata.size(), hint );
 		}
 
+		void replace_vertex_buffer( vertex_array va, buffer vb, bool owner )
+		{
+			vertex_array_info* info = m_vertex_arrays.get( va );
+			if ( info )
+			{
+				for ( uint32 i = 0; i < info->count; ++i )
+				{
+					vertex_buffer_attribute& vba = info->attr[i];
+					if ( vba.owner ) 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 = m_vertex_arrays.get( 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 ) 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 = m_vertex_arrays.get( 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 = m_vertex_arrays.get( va );
+			if ( info )
+			{
+				if ( get_buffer_info( b )->type == INDEX_BUFFER )
+				{
+					if (info->index.is_valid() && info->index_owner) release( info->index ); 
+
+					info->index       = b; 
+					info->index_owner = owner; 
+					info->index_type  = datatype;
+				}
+			}
+		}
+
+		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 = m_vertex_arrays.get( va );
+			if ( info )
+			{
+				NV_ASSERT( info->count < 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 )
+		{
+			vertex_array_info* info = m_vertex_arrays.get( va );
+			if ( info )
+			{
+				for ( uint32 i = 0; i < info->count; ++i )
+				{
+					if ( info->attr[i].location == location )
+					{
+						return info->attr[i].vbuffer;
+					}
+				}
+			}
+			return buffer();
+		}
+
 		// TODO: HINTS ARE DIFFERENT!
-		vertex_array* create_vertex_array( const mesh_data* data, buffer_hint hint )
-		{
-			vertex_array*  va = create_vertex_array();
+		vertex_array create_vertex_array( const mesh_data* data, buffer_hint hint )
+		{
+			vertex_array  va = create_vertex_array();
 			const std::vector< mesh_raw_channel* >& channels = data->get_raw_channels();
 			for ( uint32 ch = 0; ch < channels.size(); ++ch )
@@ -156,13 +328,14 @@
 				if ( channel->count > 0 )
 				{
-					if ( channel->is_index() )
-					{
-						index_buffer* ib = create_index_buffer( hint, channel->size(), channel->data );
-						va->set_index_buffer( ib, channel->desc.slots[0].etype, true );
+					buffer_type type = channel->get_buffer_type();
+					buffer b = create_buffer( type, hint, channel->size(), channel->data );
+					// TODO: no if switch
+					if ( type == INDEX_BUFFER )
+					{
+						set_index_buffer( va, b, channel->desc.slots[0].etype, true );
 					}
 					else
 					{
-						vertex_buffer* vb = create_vertex_buffer( hint, channel->size(), channel->data );
-						va->add_vertex_buffers( vb, channel );
+						add_vertex_buffers( va, b, channel );
 					}
 				}
@@ -172,5 +345,12 @@
 
 
-		virtual ~device() {}
+		virtual ~device()
+		{
+			// TODO: releases buffers via gl_context which is destoryed!
+			while ( m_vertex_arrays.size() > 0 )
+				release( m_vertex_arrays.get_handle(0) );
+		}
+	protected:
+		entity_store< vertex_array_info, vertex_array > m_vertex_arrays;
 	};
 
Index: trunk/nv/interface/mesh_data.hh
===================================================================
--- trunk/nv/interface/mesh_data.hh	(revision 301)
+++ trunk/nv/interface/mesh_data.hh	(revision 302)
@@ -36,5 +36,13 @@
 		}
 
-		bool is_index() const { return count > 0 && desc.slots[0].vslot == slot::INDEX; }
+		// TODO: this could have more options if stored!
+		buffer_type get_buffer_type() const
+		{
+			if ( count > 0 && desc.slots[0].vslot == slot::INDEX )
+			{
+				return INDEX_BUFFER;
+			}
+			return VERTEX_BUFFER;
+		}
 
 		uint32 size() const { return count * desc.size; }
@@ -92,5 +100,5 @@
 			NV_ASSERT( channel, "nullptr passed to add_channel!" );
 			m_channels.push_back( channel );
-			if ( channel->is_index() )
+			if ( channel->get_buffer_type() == INDEX_BUFFER )
 			{
 				NV_ASSERT( !m_index_channel, "second index channel!" );
Index: trunk/nv/interface/vertex.hh
===================================================================
--- trunk/nv/interface/vertex.hh	(revision 301)
+++ trunk/nv/interface/vertex.hh	(revision 302)
@@ -31,4 +31,18 @@
 		SLOT_MAX_STORE = 8,
 	};
+
+	enum buffer_hint
+	{
+		STATIC_DRAW,
+		STREAM_DRAW,
+		DYNAMIC_DRAW
+	};
+
+	enum buffer_type
+	{
+		VERTEX_BUFFER,
+		INDEX_BUFFER,
+	};
+
 
 	namespace detail
Index: trunk/nv/interface/vertex_buffer.hh
===================================================================
--- trunk/nv/interface/vertex_buffer.hh	(revision 301)
+++ trunk/nv/interface/vertex_buffer.hh	(revision 302)
@@ -21,158 +21,4 @@
 namespace nv
 {
-	class vertex_array;
-
-	enum buffer_hint
-	{
-		STATIC_DRAW,
-		STREAM_DRAW,
-		DYNAMIC_DRAW
-	};
-
-	class buffer
-	{
-	public:
-		buffer( buffer_hint hint, size_t size ) { m_size = size; m_hint = hint; }
-		size_t get_size() const { return m_size; }
-		buffer_hint get_hint() const { return m_hint; }
-        virtual ~buffer() {}
-	protected:
-		size_t      m_size;
-		buffer_hint m_hint;
-	};
-
-	class vertex_buffer : public buffer
-	{
-	public:
-		vertex_buffer( buffer_hint hint, size_t size ) : buffer( hint, size ) {}
-	};
-
-	class index_buffer  : public buffer 
-	{
-	public:
-		index_buffer( buffer_hint hint, size_t size ) : buffer( hint, size ) {}
-	};
-
-	class vertex_buffer_attribute
-	{
-	public:
-		vertex_buffer_attribute( vertex_buffer* buffer, datatype datatype, size_t components, size_t offset = 0, size_t stride = 0, bool owner = true )
-			: m_buffer( buffer ), m_datatype( datatype ), m_components( components ), m_offset( offset ), m_stride( stride ), m_owner( owner ) {}
-
-		vertex_buffer* get_buffer() const { return m_buffer; }
-		void set_buffer( vertex_buffer* b, bool owner ) { if (m_owner) delete m_buffer; m_buffer = b; m_owner = owner; }
-		datatype get_datatype() const { return m_datatype; }
-		size_t get_components() const { return m_components; }
-		size_t get_offset() const { return m_offset; }
-		size_t get_stride() const { return m_stride; }
-
-		~vertex_buffer_attribute()
-		{
-			if (m_owner)
-			{
-				delete m_buffer;
-			}
-		}
-	protected:
-		friend class vertex_array;
-
-		vertex_buffer* m_buffer;
-		datatype       m_datatype;
-		size_t  m_components;
-		size_t  m_offset;
-		size_t  m_stride;
-		bool    m_owner;
-	};
-
-	typedef std::unordered_map< int, vertex_buffer_attribute* > vertex_buffer_attribute_map;
-
-	class vertex_array
-	{
-	public:
-		friend class context;
-		friend class gl_context; // TODO: HACK, remove
-
-		vertex_array() : m_map(), m_index( nullptr ), m_index_owner( false ), m_index_type(USHORT) {}
-		void add_vertex_buffer( int location, vertex_buffer* buffer, datatype datatype, size_t components, size_t offset = 0, size_t stride = 0, bool owner = true ) 
-		{
-			auto p = new vertex_buffer_attribute( buffer, datatype, components, offset, stride, owner );
-			m_map[ location ] = p;
-		}
-		void add_vertex_buffer( slot location, vertex_buffer* buffer, datatype datatype, size_t components, size_t offset = 0, size_t stride = 0, bool owner = true ) 
-		{
-			add_vertex_buffer( (int)location, buffer, datatype, components, offset, stride, owner );
-		}
-
-		void add_vertex_buffers( vertex_buffer* buffer, const mesh_raw_channel* channel )
-		{
-			for ( uint32 s = 0; s < channel->desc.count; ++s )
-			{
-				add_vertex_buffer( buffer, channel->desc.slots[s], channel->desc.size );
-			}
-		}
-
-		void add_vertex_buffer( vertex_buffer* buffer, const vertex_descriptor_slot& slot, size_t vtx_size )
-		{
-			const datatype_info& info = get_datatype_info(slot.etype);
-			add_vertex_buffer( slot.vslot, buffer, info.base , info.elements, slot.offset, vtx_size, false );
-		}
-
-		void update_vertex_buffer( int location, vertex_buffer* b, bool owner ) 
-		{
-			auto i = m_map.find( location );
-			if ( i != m_map.end() )
-			{
-				i->second->set_buffer( b, owner );
-			}
-		}
-		void update_vertex_buffer( int location, size_t offset ) 
-		{
-			auto i = m_map.find( location );
-			if ( i != m_map.end() )
-			{
-				i->second->m_offset = offset;
-			}
-		}
-		void update_vertex_buffer( slot location, vertex_buffer* b, bool owner ) 
-		{update_vertex_buffer( (int)location, b, owner ); }
-		void update_vertex_buffer( slot location, size_t offset ) {update_vertex_buffer( (int)location, offset );	}
-		void set_index_buffer( index_buffer* buffer, datatype datatype, bool owner ) 
-		{ 
-			if (m_index && m_index_owner) delete m_index; 
-			m_index       = buffer; 
-			m_index_owner = owner; 
-			m_index_type  = datatype;
-		}
-		void set_index_buffer( index_buffer* buffer ) 
-		{ 
-			if (m_index && m_index_owner) delete m_index; 
-			m_index       = buffer; 
-		}
-		vertex_buffer* find_buffer( int location )
-		{
-			auto i = m_map.find( location );
-			if ( i != m_map.end() )
-			{
-				return i->second->get_buffer();
-			}
-			return nullptr;
-		}
-		vertex_buffer* find_buffer( slot location ) { return find_buffer((int)location); }
-		bool has_index_buffer() const { return m_index != nullptr; }
-		datatype get_index_buffer_type() const { return m_index_type; }
-		virtual ~vertex_array() { 
-			for ( vertex_buffer_attribute_map::iterator i = m_map.begin(); 	i != m_map.end(); ++i ) 
-			{
-				delete i->second;
-			}
-			if (m_index && m_index_owner) delete m_index; 
-		}
-	protected:
-		vertex_buffer_attribute_map m_map;
-		index_buffer* m_index;
-		bool          m_index_owner;
-		datatype      m_index_type;
-	};
-
 
 } // namespace nv
Index: trunk/src/formats/assimp_loader.cc
===================================================================
--- trunk/src/formats/assimp_loader.cc	(revision 301)
+++ trunk/src/formats/assimp_loader.cc	(revision 302)
@@ -317,5 +317,4 @@
 			{
 				mesh_raw_channel* channel = meshes[m].get_raw_channels()[0];
-				NV_ASSERT( !channel->is_index(), "index channel in release_merged!" );
 				assimp_skinned_vtx* va = (assimp_skinned_vtx*)channel->data;
 				for ( unsigned v = 0; v < channel->count; ++v )
Index: trunk/src/gfx/debug_draw.cc
===================================================================
--- trunk/src/gfx/debug_draw.cc	(revision 301)
+++ trunk/src/gfx/debug_draw.cc	(revision 302)
@@ -29,5 +29,5 @@
 
 nv::debug_data::debug_data( device* a_device )
-	: m_device( a_device ), m_program( nullptr ), m_va( nullptr )
+	: m_device( a_device ), m_program( nullptr ), m_va()
 {
 	m_program = m_device->create_program( nv_debug_draw_vertex_shader, nv_debug_draw_fragment_shader );
@@ -36,5 +36,5 @@
 void nv::debug_data::update()
 {
-	delete m_va;
+	m_device->release( m_va );
 	m_va = m_device->create_vertex_array( m_data, nv::STATIC_DRAW );
 }
@@ -75,5 +75,5 @@
 nv::debug_data::~debug_data()
 {
-	delete m_va;
+	m_device->release( m_va );
 	delete m_program;
 }
Index: trunk/src/gfx/keyframed_mesh.cc
===================================================================
--- trunk/src/gfx/keyframed_mesh.cc	(revision 301)
+++ trunk/src/gfx/keyframed_mesh.cc	(revision 302)
@@ -15,6 +15,7 @@
 using namespace nv;
 
-nv::keyframed_mesh::keyframed_mesh( const mesh_data* a_data, const mesh_nodes_data* a_tag_map )
+nv::keyframed_mesh::keyframed_mesh( context* a_context, const mesh_data* a_data, const mesh_nodes_data* a_tag_map )
 	: animated_mesh()
+	, m_context( a_context )
 	, m_mesh_data( a_data )
 	, m_tag_map( a_tag_map )
@@ -36,4 +37,5 @@
 	}
 	m_frame_count  = m_vchannel->count / m_vertex_count;
+	m_pbuffer      = buffer();
 }
 
@@ -103,5 +105,5 @@
 nv::keyframed_mesh::~keyframed_mesh()
 {
-	delete m_va;
+	m_context->get_device()->release( m_va );
 }
 
@@ -122,5 +124,5 @@
 
 nv::keyframed_mesh_gpu::keyframed_mesh_gpu( context* a_context, const mesh_data* a_data, const mesh_nodes_data* a_tag_map )
-	: keyframed_mesh( a_data, a_tag_map )
+	: keyframed_mesh( a_context, a_data, a_tag_map )
 	, m_loc_next_position( -1 )
 	, m_loc_next_normal( -1 )
@@ -129,5 +131,6 @@
 	, m_gpu_next_frame( 0xFFFFFFFF )
 {
-	m_va = a_context->get_device()->create_vertex_array( a_data, STATIC_DRAW );
+	m_va      = a_context->get_device()->create_vertex_array( a_data, STATIC_DRAW );
+	m_pbuffer = a_context->get_device()->find_buffer( m_va, slot::POSITION );
 }
 
@@ -137,12 +140,13 @@
 	if ( m_loc_next_position == -1 ) return;
 	animated_mesh::update( ms );
-
+	device* dev = m_context->get_device();
 	if ( m_gpu_last_frame != m_last_frame )
 	{
-		m_va->update_vertex_buffer( slot::POSITION, m_last_frame * m_vertex_count * m_vsize );
-		m_va->update_vertex_buffer( slot::NORMAL,   m_last_frame * m_vertex_count * m_vsize + sizeof( vec3 ) );
+		uint32 base_offset = m_last_frame * m_vertex_count * m_vsize; 
+		dev->update_attribute_offset( m_va, slot::POSITION, base_offset );
+		dev->update_attribute_offset( m_va, slot::NORMAL,   base_offset + sizeof( vec3 ) );
 		if ( m_has_tangent && m_loc_next_tangent != -1 )
 		{
-			m_va->update_vertex_buffer( slot::TANGENT,   m_last_frame * m_vertex_count * m_vsize + 2*sizeof( vec3 ) );
+			dev->update_attribute_offset( m_va, slot::TANGENT, base_offset + 2*sizeof( vec3 ) );
 		}
 		m_gpu_last_frame = m_last_frame;
@@ -150,7 +154,11 @@
 	if ( m_loc_next_position != -1 && m_gpu_next_frame != m_next_frame )
 	{
-		m_va->update_vertex_buffer( m_loc_next_position, m_next_frame * m_vertex_count * m_vsize );
-		m_va->update_vertex_buffer( m_loc_next_normal,   m_next_frame * m_vertex_count * m_vsize + sizeof( vec3 ) );
-		m_va->update_vertex_buffer( m_loc_next_tangent,   m_next_frame * m_vertex_count * m_vsize + 2*sizeof( vec3 ) );
+		uint32 base_offset = m_next_frame * m_vertex_count * m_vsize; 
+		dev->update_attribute_offset( m_va, (slot)m_loc_next_position, base_offset );
+		dev->update_attribute_offset( m_va, (slot)m_loc_next_normal, base_offset + sizeof( vec3 ) );
+		if ( m_has_tangent && m_loc_next_tangent != -1 )
+		{
+			dev->update_attribute_offset( m_va, (slot)m_loc_next_tangent, base_offset + 2*sizeof( vec3 ) );
+		}
 		m_gpu_next_frame = m_next_frame;
 	}
@@ -166,9 +174,9 @@
 			m_loc_next_tangent  = a_program->get_attribute( "nv_next_tangent" )->get_location();
 
-		vertex_buffer* vb = m_va->find_buffer( slot::POSITION );
-		m_va->add_vertex_buffer( m_loc_next_position, vb, FLOAT, 3, 0, m_vsize, false );
-		m_va->add_vertex_buffer( m_loc_next_normal,   vb, FLOAT, 3, sizeof( vec3 ), m_vsize, false );
+		device* dev = m_context->get_device();
+		dev->add_vertex_buffer( m_va, (slot)m_loc_next_position, m_pbuffer, FLOAT, 3, 0, m_vsize, false );
+		dev->add_vertex_buffer( m_va, (slot)m_loc_next_normal,   m_pbuffer, FLOAT, 3, sizeof( vec3 ), m_vsize, false );
 		if ( m_has_tangent )
-			m_va->add_vertex_buffer( m_loc_next_tangent, vb, FLOAT, 4, 2*sizeof( vec3 ), m_vsize, false );
+			dev->add_vertex_buffer( m_va, (slot)m_loc_next_tangent, m_pbuffer, FLOAT, 4, 2*sizeof( vec3 ), m_vsize, false );
 	}
 	keyframed_mesh::update( a_program );
@@ -176,16 +184,16 @@
 
 nv::keyframed_mesh_cpu::keyframed_mesh_cpu( context* a_context, const mesh_data* a_data, const mesh_nodes_data* a_tag_map )
-	: keyframed_mesh( a_data, a_tag_map )
-	, m_context( a_context )
-{
-	m_va = m_context->get_device()->create_vertex_array();
-	m_vb = m_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_vertex_count * m_vsize, (void*)m_vchannel->data );
-	m_va->add_vertex_buffers( m_vb, m_vchannel );
-
-	nv::vertex_buffer* vb = m_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_vertex_count * sizeof( nv::vec2 ), (void*)m_mesh_data->get_channel<vertex_t>()->data );
-	m_va->add_vertex_buffers( vb, m_mesh_data->get_channel<vertex_t>() );
-
-	nv::index_buffer* ib = m_context->get_device()->create_index_buffer( nv::STATIC_DRAW, m_mesh_data->get_index_channel()->size(), (void*)m_mesh_data->get_index_channel()->data );
-	m_va->set_index_buffer( ib, m_mesh_data->get_index_channel()->desc.slots[0].etype, true );
+	: keyframed_mesh( a_context, a_data, a_tag_map )
+{
+	m_va      = m_context->get_device()->create_vertex_array();
+	m_pbuffer = m_context->get_device()->create_buffer( VERTEX_BUFFER, STATIC_DRAW, m_vertex_count * m_vsize, (void*)m_vchannel->data );
+	m_context->get_device()->add_vertex_buffers( m_va, m_pbuffer, m_vchannel );
+
+	buffer  vb = m_context->get_device()->create_buffer( VERTEX_BUFFER, STATIC_DRAW, m_vertex_count * sizeof( vec2 ), (void*)m_mesh_data->get_channel<vertex_t>()->data );
+	m_context->get_device()->add_vertex_buffers( m_va, vb, m_mesh_data->get_channel<vertex_t>() );
+
+	buffer  ib = m_context->get_device()->create_buffer( INDEX_BUFFER, STATIC_DRAW, m_mesh_data->get_index_channel()->size(), (void*)m_mesh_data->get_index_channel()->data );
+
+	m_context->get_device()->set_index_buffer( m_va, ib, m_mesh_data->get_index_channel()->desc.slots[0].etype, true );
 
 	m_data = new uint8[ m_vertex_count * m_vsize ];
@@ -224,5 +232,5 @@
 	}
 
-	m_context->update( m_vb, m_data, 0, m_vertex_count * m_vsize );
+	m_context->update( m_pbuffer, m_data, 0, m_vertex_count * m_vsize );
 }
 
Index: trunk/src/gfx/mesh_creator.cc
===================================================================
--- trunk/src/gfx/mesh_creator.cc	(revision 301)
+++ trunk/src/gfx/mesh_creator.cc	(revision 302)
@@ -430,8 +430,8 @@
 	{
 		mesh_raw_channel* old = m_data->m_channels[c];
-		size_t frame_count = ( old->is_index() ? 1 : old->count / size );
+		size_t frame_count = ( old->get_buffer_type() == INDEX_BUFFER ? 1 : old->count / size );
 		m_data->m_channels[c] = append_channels( old, other->m_channels[c], frame_count );
 		NV_ASSERT( m_data->m_channels[c], "Merge problem!" );
-		if ( old->is_index() )
+		if ( old->get_buffer_type() == INDEX_BUFFER )
 		{
 			switch ( old->desc.slots[0].etype )
Index: trunk/src/gfx/skeletal_mesh.cc
===================================================================
--- trunk/src/gfx/skeletal_mesh.cc	(revision 301)
+++ trunk/src/gfx/skeletal_mesh.cc	(revision 302)
@@ -12,6 +12,5 @@
 
 nv::skeletal_mesh_cpu::skeletal_mesh_cpu( context* a_context, const mesh_data* a_mesh_data, const mesh_nodes_data* bones )
-	: skeletal_mesh()
-	, m_context( a_context )
+	: skeletal_mesh( a_context )
 	, m_data( a_mesh_data )
 {
@@ -27,5 +26,7 @@
 	m_vtx_data  = a_mesh_data->get_channel_data<md5_vtx_pntiw>();
 	m_indices   = a_mesh_data->get_count();
-	m_va        = a_context->get_device()->create_vertex_array( a_mesh_data, nv::STREAM_DRAW );
+	m_va        = a_context->get_device()->create_vertex_array( a_mesh_data, 
+STREAM_DRAW );
+	m_pbuffer   = a_context->get_device()->find_buffer( m_va, slot::POSITION );
 }
 
@@ -63,6 +64,5 @@
 		}
 
-		vertex_buffer* vb = m_va->find_buffer( nv::slot::POSITION );
-		m_context->update( vb, m_pntdata.data(), 0, m_pntdata.raw_size() );
+		m_context->update( m_pbuffer, m_pntdata.data(), 0, m_pntdata.raw_size() );
 	}
 }
@@ -80,11 +80,4 @@
 		skeleton[i] = m_node_data->get_node(i)->data->get_transform( frame_num );
 	}
-}
-
-
-
-nv::skeletal_mesh_cpu::~skeletal_mesh_cpu()
-{
-	delete m_va;
 }
 
@@ -200,5 +193,5 @@
 
 nv::skeletal_mesh_gpu::skeletal_mesh_gpu( context* a_context, const mesh_data* a_mesh, const mesh_nodes_data* a_bone_data )
-	: skeletal_mesh(), m_bone_data( a_bone_data ), m_transform( nullptr )
+	: skeletal_mesh( a_context ), m_bone_data( a_bone_data ), m_transform( nullptr )
 {
 	m_va          = a_context->get_device()->create_vertex_array( a_mesh, nv::STATIC_DRAW );
Index: trunk/src/gl/gl_context.cc
===================================================================
--- trunk/src/gl/gl_context.cc	(revision 301)
+++ trunk/src/gl/gl_context.cc	(revision 302)
@@ -10,5 +10,4 @@
 #include "nv/gl/gl_device.hh"
 #include "nv/gl/gl_program.hh"
-#include "nv/gl/gl_vertex_buffer.hh"
 
 using namespace nv;
@@ -31,39 +30,39 @@
 }
 
-void nv::gl_context::bind( vertex_buffer* b )
-{
-	GLuint id = static_cast< gl_vertex_buffer* >( b )->glid;
-	glBindBuffer( GL_ARRAY_BUFFER, id );
-}
-
-void nv::gl_context::bind( index_buffer* b )
-{
-	GLuint id = static_cast< gl_index_buffer* >( b )->glid;
-	glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, id );
-}
-
-void nv::gl_context::bind( vertex_array* va )
-{
-	for ( vertex_buffer_attribute_map::iterator i = va->m_map.begin(); 	i != va->m_map.end(); ++i ) 
-	{
-		uint32 location             = static_cast<uint32>( i->first );
-		vertex_buffer_attribute* va = i->second;
-		vertex_buffer*           vb = va->get_buffer();
-		glEnableVertexAttribArray( location );
-		bind( vb );
-		glVertexAttribPointer( 
-			location, 
-			static_cast<GLint>( va->get_components() ), 
-			nv::datatype_to_gl_enum( va->get_datatype() ),
-			GL_FALSE,
-			static_cast<GLsizei>( va->get_stride() ),
-			(void*)va->get_offset()
-			);
-		unbind( vb );
-	}
-
-	if ( va->m_index )
-	{
-		bind( va->m_index );
+void nv::gl_context::bind( buffer b )
+{
+	const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
+	if ( info )
+	{
+		glBindBuffer( buffer_type_to_enum( info->type ), info->glid );
+	}
+}
+
+void nv::gl_context::bind( vertex_array va )
+{
+	vertex_array_info* info = get_vertex_array_info( 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 );
+			bind( vba.vbuffer );
+			glVertexAttribPointer( 
+				location, 
+				static_cast<GLint>( vba.components ), 
+				nv::datatype_to_gl_enum( vba.dtype ),
+				GL_FALSE,
+				static_cast<GLsizei>( vba.stride ),
+				(void*)vba.offset
+				);
+			unbind( vba.vbuffer );
+		}
+
+		if ( info->index.is_valid() )
+		{
+			bind( info->index );
+		}
 	}
 }
@@ -74,24 +73,27 @@
 }
 
-void nv::gl_context::unbind( vertex_buffer* )
-{
-	glBindBuffer( GL_ARRAY_BUFFER, 0 );
-}
-
-void nv::gl_context::unbind( index_buffer* )
-{
-	glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
-}
-
-void nv::gl_context::unbind( vertex_array* va )
-{
-	if ( va->m_index )
-	{
-		unbind( va->m_index );
-	}
-
-	for ( vertex_buffer_attribute_map::iterator i = va->m_map.begin(); 	i != va->m_map.end(); ++i ) 
-	{
-		glDisableVertexAttribArray( static_cast<uint32>( i->first ) );
+void nv::gl_context::unbind( buffer b )
+{
+	const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
+	if ( info )
+	{
+		glBindBuffer( buffer_type_to_enum( info->type ), 0 );
+	}
+}
+
+void nv::gl_context::unbind( vertex_array va )
+{
+	vertex_array_info* info = get_vertex_array_info( va );
+	if ( info )
+	{
+		if ( info->index.is_valid() )
+		{
+			unbind( info->index );
+		}
+
+		for ( uint32 i = 0; i < info->count; ++i ) 
+		{
+			glDisableVertexAttribArray( static_cast<uint32>( info->attr[i].location ) );
+		}
 	}
 }
@@ -110,14 +112,12 @@
 }
 
-void gl_context::update( vertex_buffer* b, const void* data, size_t offset, size_t size )
-{
-	bind( b );
-	glBufferSubData( GL_ARRAY_BUFFER, (GLintptr)offset, (GLsizeiptr)size, data );
-}
-
-void gl_context::update( index_buffer* b, const void* data, size_t offset, size_t size )
-{
-	bind( b );
-	glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, (GLintptr)offset, (GLsizeiptr)size, data );
+void gl_context::update( buffer b, const void* data, size_t offset, size_t size )
+{
+	const gl_buffer_info* info = static_cast< const gl_buffer_info* >( m_device->get_buffer_info( b ) );
+	if ( info )
+	{
+		bind( b );
+		glBufferSubData( buffer_type_to_enum( info->type ), (GLintptr)offset, (GLsizeiptr)size, data );
+	}
 }
 
@@ -483,14 +483,15 @@
 }
 
-void gl_context::draw( primitive prim, const render_state& rs, program* p, vertex_array* va, size_t count )
+void gl_context::draw( primitive prim, const render_state& rs, program* p, vertex_array va, size_t count )
 {
 	apply_render_state( rs );
-	if ( count > 0 )
+	vertex_array_info* info = get_vertex_array_info( va );
+	if ( count > 0 && info )
 	{
 		bind( p );
 		bind( va );
-		if ( va->has_index_buffer() )
-		{
-			glDrawElements( primitive_to_enum(prim), static_cast<GLsizei>( count ), datatype_to_gl_enum( va->get_index_buffer_type() ), 0 );
+		if ( info->index.is_valid() )
+		{
+			glDrawElements( primitive_to_enum(prim), static_cast<GLsizei>( count ), datatype_to_gl_enum( info->index_type ), 0 );
 		}
 		else
Index: trunk/src/gl/gl_device.cc
===================================================================
--- trunk/src/gl/gl_device.cc	(revision 301)
+++ trunk/src/gl/gl_device.cc	(revision 302)
@@ -7,5 +7,4 @@
 #include "nv/gl/gl_window.hh"
 #include "nv/gl/gl_program.hh"
-#include "nv/gl/gl_vertex_buffer.hh"
 #include "nv/logging.hh"
 #include "nv/lib/sdl.hh"
@@ -56,19 +55,4 @@
 }
 
-vertex_buffer* gl_device::create_vertex_buffer( buffer_hint hint, size_t size, const void* source /*= nullptr */ )
-{
-	return new gl_vertex_buffer( hint, size, source );
-}
-
-index_buffer* gl_device::create_index_buffer( buffer_hint hint, size_t size, const void* source /*= nullptr */ )
-{
-	return new gl_index_buffer( hint, size, source );
-}
-
-vertex_array* gl_device::create_vertex_array()
-{
-	return new vertex_array();
-}
-
 // this is a temporary function that will be removed once we find a way to 
 // pass binary file data around
@@ -101,6 +85,8 @@
 gl_device::~gl_device()
 {
-	// TODO: better use release_texture
-	for ( auto& t : m_textures ) glDeleteTextures( 1, &t.glid );
+	while ( m_textures.size() > 0 )
+		release( m_textures.get_handle(0) );
+	while ( m_buffers.size() > 0 )
+		release( m_buffers.get_handle(0) );
 
 	SDL_Quit();
@@ -142,11 +128,27 @@
 }
 
-void nv::gl_device::release_texture( texture t )
+void nv::gl_device::release( texture t )
 {
 	gl_texture_info* info = m_textures.get( t );
 	if ( info )
 	{
-		glDeleteTextures( 1, &(info->glid) );
+		if ( info->glid != 0 )
+		{
+			glDeleteTextures( 1, &(info->glid) );
+		}
 		m_textures.destroy( t );
+	}
+}
+
+void nv::gl_device::release( buffer b )
+{
+	gl_buffer_info* info = m_buffers.get( b );
+	if ( info )
+	{
+		if ( info->glid != 0 )
+		{
+			glDeleteBuffers( 1, &(info->glid) );
+		}
+		m_buffers.destroy( b );
 	}
 }
@@ -157,2 +159,25 @@
 }
 
+nv::buffer nv::gl_device::create_buffer( buffer_type type, buffer_hint hint, size_t size, const void* source /*= nullptr */ )
+{
+	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 );
+
+	buffer result = m_buffers.create();
+	gl_buffer_info* info = m_buffers.get( result );
+	info->type = type;
+	info->hint = hint;
+	info->size = size;
+	info->glid = glid;
+	return result;
+}
+
+const buffer_info* nv::gl_device::get_buffer_info( buffer t )
+{
+	return m_buffers.get( t );
+}
Index: trunk/src/gl/gl_enum.cc
===================================================================
--- trunk/src/gl/gl_enum.cc	(revision 301)
+++ trunk/src/gl/gl_enum.cc	(revision 302)
@@ -144,4 +144,14 @@
 	case DYNAMIC_DRAW  : return GL_DYNAMIC_DRAW;
 	NV_RETURN_COVERED_DEFAULT( 0 );
+	}
+}
+
+unsigned int nv::buffer_type_to_enum( buffer_type type )
+{
+	switch( type )
+	{
+	case VERTEX_BUFFER : return GL_ARRAY_BUFFER;
+	case INDEX_BUFFER  : return GL_ELEMENT_ARRAY_BUFFER;
+		NV_RETURN_COVERED_DEFAULT( 0 );
 	}
 }
Index: trunk/src/gl/gl_vertex_buffer.cc
===================================================================
--- trunk/src/gl/gl_vertex_buffer.cc	(revision 301)
+++ 	(revision )
@@ -1,45 +1,0 @@
-// Copyright (C) 2012-2013 Kornel Kisielewicz
-// This file is part of NV Libraries.
-// For conditions of distribution and use, see copyright notice in nv.hh
-
-#include "nv/gl/gl_vertex_buffer.hh"
-
-#include "nv/lib/gl.hh"
-#include "nv/gl/gl_enum.hh"
-
-using namespace nv;
-
-gl_vertex_buffer::gl_vertex_buffer( buffer_hint hint, size_t size, const void* data ) 
-	: vertex_buffer( hint, size )
-{
-	glGenBuffers( 1, &glid );
-	glBindBuffer( GL_ARRAY_BUFFER, glid );
-	glBufferData( GL_ARRAY_BUFFER, (GLsizeiptr)m_size, data, buffer_hint_to_enum( m_hint ) );
-	glBindBuffer( GL_ARRAY_BUFFER, 0 );
-}
-
-nv::gl_vertex_buffer::~gl_vertex_buffer()
-{
-	if ( glid != 0 )
-	{
-		glDeleteBuffers( 1, &glid );
-	}
-}
-
-gl_index_buffer::gl_index_buffer( buffer_hint hint, size_t size, const void* data ) 
-	: index_buffer( hint, size )
-{
-	glGenBuffers( 1, &glid );
-
-	glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, glid );
-	glBufferData( GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)m_size, data, buffer_hint_to_enum( m_hint ) );
-	glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
-}
-
-nv::gl_index_buffer::~gl_index_buffer()
-{
-	if ( glid != 0 )
-	{
-		glDeleteBuffers( 1, &glid );
-	}
-}
Index: trunk/src/gui/gui_renderer.cc
===================================================================
--- trunk/src/gui/gui_renderer.cc	(revision 301)
+++ trunk/src/gui/gui_renderer.cc	(revision 302)
@@ -21,36 +21,36 @@
 	{
 		set_color( color );
-		vtx[0].coord = coorda;
-		vtx[1].coord = nv::ivec2( coorda.x, coordb.y );
-		vtx[2].coord = coordb;
-		vtx[3].coord = coordb;
-		vtx[4].coord = nv::ivec2( coordb.x, coorda.y );
-		vtx[5].coord = coorda;
+		vtx[0].position = coorda;
+		vtx[1].position = nv::ivec2( coorda.x, coordb.y );
+		vtx[2].position = coordb;
+		vtx[3].position = coordb;
+		vtx[4].position = nv::ivec2( coordb.x, coorda.y );
+		vtx[5].position = coorda;
 	}
 	gui_quad( const nv::ivec2& coorda, const nv::ivec2& coordb, const nv::vec4& color, const nv::vec2& tcoorda, const nv::vec2& tcoordb )
 	{
 		set_color( color );
-		vtx[0].coord = coorda;
-		vtx[1].coord = nv::ivec2( coorda.x, coordb.y );
-		vtx[2].coord = coordb;
-		vtx[3].coord = coordb;
-		vtx[4].coord = nv::ivec2( coordb.x, coorda.y );
-		vtx[5].coord = coorda;
-		vtx[0].tcoord = tcoorda;
-		vtx[1].tcoord = nv::vec2( tcoorda.x, tcoordb.y );
-		vtx[2].tcoord = tcoordb;
-		vtx[3].tcoord = tcoordb;
-		vtx[4].tcoord = nv::vec2( tcoordb.x, tcoorda.y );
-		vtx[5].tcoord = tcoorda;
+		vtx[0].position = coorda;
+		vtx[1].position = nv::ivec2( coorda.x, coordb.y );
+		vtx[2].position = coordb;
+		vtx[3].position = coordb;
+		vtx[4].position = nv::ivec2( coordb.x, coorda.y );
+		vtx[5].position = coorda;
+		vtx[0].texcoord = tcoorda;
+		vtx[1].texcoord = nv::vec2( tcoorda.x, tcoordb.y );
+		vtx[2].texcoord = tcoordb;
+		vtx[3].texcoord = tcoordb;
+		vtx[4].texcoord = nv::vec2( tcoordb.x, tcoorda.y );
+		vtx[5].texcoord = tcoorda;
 	}
 	gui_quad( const nv::ivec2& coorda, const nv::ivec2& coordb, const nv::ivec2& coordc, const nv::ivec2& coordd, const nv::vec4& color )
 	{
 		set_color( color );
-		vtx[0].coord = coorda;
-		vtx[1].coord = coordb;
-		vtx[2].coord = coordc;
-		vtx[3].coord = coordc;
-		vtx[4].coord = coordd;
-		vtx[5].coord = coorda;
+		vtx[0].position = coorda;
+		vtx[1].position = coordb;
+		vtx[2].position = coordc;
+		vtx[3].position = coordc;
+		vtx[4].position = coordd;
+		vtx[5].position = coorda;
 	}
 	inline void set_color( const nv::vec4& color )
@@ -66,5 +66,5 @@
 public:
 	screen_render_data( context* actx, size_t initial_size )
-		: buffer( actx, nv::DYNAMIC_DRAW, initial_size ), varray( nullptr ), shader(nullptr)
+		: buffer( actx, VERTEX_BUFFER, DYNAMIC_DRAW, initial_size ), ctx( actx ), varray(), shader(nullptr)
 	{
 
@@ -73,10 +73,11 @@
 	{ 
 		delete shader; 
-		delete varray; 
+		ctx->get_device()->release( varray ); 
 	}
 
 	nv::sliced_buffer<gui_quad> buffer;
+	nv::context*      ctx;
 	nv::texture       tex;
-	nv::vertex_array* varray;
+	nv::vertex_array  varray;
 	nv::program*      shader;
 };
@@ -110,12 +111,10 @@
 	m_render_data = sr;
 	// ** EXTREMELY TEMPORARY!
-	sr->varray     = m_window->get_device()->create_vertex_array();
 	sr->shader     = m_window->get_device()->create_program( nv::slurp( shader_path + ".vert" ), nv::slurp( shader_path + ".frag" ) );
 	m_scene_state.get_camera().set_ortho( 0.0f, float( m_window->get_width() ), float( m_window->get_height() ), 0.0f );
 
-	vertex_buffer* vb = (vertex_buffer*)sr->buffer.get_buffer();
-	sr->varray->add_vertex_buffer( slot::POSITION, vb, nv::INT,   2, 0, sizeof( vertex ), false );
-	sr->varray->add_vertex_buffer( slot::TEXCOORD, vb, nv::FLOAT, 2, offset_of( &vertex::tcoord ), sizeof( vertex ), false );
-	sr->varray->add_vertex_buffer( slot::COLOR,    vb, nv::FLOAT, 4, offset_of( &vertex::color ), sizeof( vertex ), false );
+	sr->varray     = m_window->get_device()->create_vertex_array();
+	buffer vb      = sr->buffer.get_buffer();
+	m_window->get_device()->add_vertex_buffers< vertex >( sr->varray, vb );
 
 	nv::sampler sampler( nv::sampler::LINEAR, nv::sampler::CLAMP_TO_EDGE );
@@ -267,8 +266,6 @@
 	if ( sr->buffer.commit() )
 	{
-		nv::vertex_buffer* vb = (nv::vertex_buffer*)sr->buffer.get_buffer();
-		sr->varray->update_vertex_buffer( nv::slot::POSITION, vb, false );
-		sr->varray->update_vertex_buffer( nv::slot::TEXCOORD, vb, false );
-		sr->varray->update_vertex_buffer( nv::slot::COLOR,    vb, false );
+		buffer vb = sr->buffer.get_buffer();
+		m_context->get_device()->replace_vertex_buffer( sr->varray, vb, false );
 	}
 	m_context->bind( sr->tex, TEX_DIFFUSE );
@@ -284,5 +281,5 @@
 	if ( m_render_data )
 	{
-		m_context->get_device()->release_texture( ((screen_render_data*)m_render_data)->tex );
+		m_context->get_device()->release( ((screen_render_data*)m_render_data)->tex );
 		delete m_render_data;
 	}
