Index: /trunk/nv/gfx/debug_draw.hh
===================================================================
--- /trunk/nv/gfx/debug_draw.hh	(revision 312)
+++ /trunk/nv/gfx/debug_draw.hh	(revision 313)
@@ -26,5 +26,5 @@
 	{
 	public:
-		debug_data( device* a_device );
+		debug_data( context* a_context );
 		void update();
 		void reset();
@@ -37,5 +37,5 @@
 		~debug_data();
 	private:
-		device*                  m_device;
+		context*                 m_context;
 		program                  m_program;
 		vertex_array             m_va;
Index: /trunk/nv/gfx/skeletal_mesh.hh
===================================================================
--- /trunk/nv/gfx/skeletal_mesh.hh	(revision 312)
+++ /trunk/nv/gfx/skeletal_mesh.hh	(revision 313)
@@ -27,5 +27,5 @@
 		~skeletal_mesh()
 		{
-			m_context->get_device()->release( m_va );
+			m_context->release( m_va );
 		}
 	protected:
Index: /trunk/nv/gl/gl_context.hh
===================================================================
--- /trunk/nv/gl/gl_context.hh	(revision 312)
+++ /trunk/nv/gl/gl_context.hh	(revision 313)
@@ -17,4 +17,9 @@
 namespace nv
 {
+	struct gl_framebuffer_info : public framebuffer_info
+	{
+		unsigned glid;
+	};
+
 	class gl_context : public context
 	{
@@ -23,11 +28,13 @@
 	public:
 		~gl_context();
+
+		virtual vertex_array create_vertex_array();
+		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;
+
 		virtual void bind( texture t, texture_slot slot );
-		virtual void bind( program p );
-		virtual void bind( buffer b );
-		virtual void bind( vertex_array va );
-		virtual void unbind( program p );
-		virtual void unbind( buffer b );
-		virtual void unbind( vertex_array va );
 
 		virtual void update( texture t, void* data );
@@ -43,6 +50,17 @@
 
 	protected:
+		void bind( program p );
+//		void bind( buffer b );
+		void bind( vertex_array va );
+		void bind( framebuffer va );
+		void unbind( program p );
+//		void unbind( buffer b );
+		void unbind( vertex_array va );
+		void unbind( framebuffer va );
+
 		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 );
@@ -57,9 +75,11 @@
 		void apply_polygon_mode( const polygon_mode& mode );
 		void enable( unsigned int what, bool value );
-
 	private:
 		vec4  m_clear_color;
 		float m_clear_depth;
 		int   m_clear_stencil;
+
+		entity_store< vertex_array_info, vertex_array >  m_vertex_arrays;
+		entity_store< gl_framebuffer_info, framebuffer > m_framebuffers;
 	};
 
Index: /trunk/nv/gl/gl_device.hh
===================================================================
--- /trunk/nv/gl/gl_device.hh	(revision 312)
+++ /trunk/nv/gl/gl_device.hh	(revision 313)
@@ -45,5 +45,4 @@
 
 		virtual program create_program( const string& vs_source, const string& fs_source );
-		virtual vertex_array create_vertex_array();
 		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 );
@@ -53,9 +52,7 @@
 		virtual void release( buffer b );
 		virtual void release( texture t );
-		virtual void release( vertex_array va );
 		virtual void release( program p );
 		virtual const texture_info* get_texture_info( texture t ) const;
 		virtual const buffer_info* get_buffer_info( buffer t ) const;
-		virtual const vertex_array_info* get_vertex_array_info( vertex_array va ) const;
 
 		virtual int get_attribute_location( program p, const string& name, bool fatal = true ) const;
@@ -65,6 +62,4 @@
 		uniform_base* get_uniform( program p, const string& name, bool fatal = true ) const;
 
-		// TODO: remove
-		virtual vertex_array_info* get_vertex_array_info_mutable( vertex_array );
 	
 	private:
@@ -75,11 +70,8 @@
 		bool compile( uint32 sh_type, const std::string& shader_code, unsigned& glid );
 
-
-
 		const void* m_info;
-		entity_store< gl_texture_info, texture >        m_textures;
-		entity_store< gl_buffer_info,  buffer >         m_buffers;
-		entity_store< vertex_array_info, vertex_array > m_vertex_arrays;
-		entity_store< gl_program_info, program >        m_programs;
+		entity_store< gl_texture_info, texture >         m_textures;
+		entity_store< gl_buffer_info,  buffer >          m_buffers;
+		entity_store< gl_program_info, program >         m_programs;
 	};
 
Index: /trunk/nv/interface/context.hh
===================================================================
--- /trunk/nv/interface/context.hh	(revision 312)
+++ /trunk/nv/interface/context.hh	(revision 313)
@@ -22,4 +22,9 @@
 namespace nv
 {
+	struct vertex_array_tag {};
+	struct framebuffer_tag {};
+	typedef handle< uint32, 16, 16, vertex_array_tag > vertex_array;
+	typedef handle< uint32, 16, 16, framebuffer_tag >  framebuffer;
+
 	enum primitive
 	{
@@ -45,4 +50,23 @@
 	};
 
+	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];
+	};
+
+	struct framebuffer_info
+	{
+		texture color_attachments[8];
+		uint32  color_attachment_count;
+		texture depth_attachment;
+		texture depth_stencil_attachment;
+	};
+
 	class context
 	{
@@ -52,10 +76,14 @@
 			m_device = a_device; 
 		}
+
+		virtual vertex_array create_vertex_array() = 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;
+
 		virtual void bind( texture, texture_slot ) = 0;
-		virtual void bind( buffer ) = 0;
-		virtual void bind( program ) = 0;
-		virtual void bind( vertex_array ) = 0;
-		virtual void unbind( buffer ) = 0;
-		virtual void unbind( program ) = 0;
 		virtual void update( texture, void* ) = 0;
 		virtual void update( buffer, const void*, size_t /*offset*/, size_t /*size*/ ) = 0;
@@ -88,5 +116,204 @@
 		{
 		}
+
+		template < typename VTX, slot SLOT >
+		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, buffer vb, const std::true_type& )
+		{
+			typedef vertex_slot_info< VTX, SLOT > vinfo;
+			typedef datatype_traits< typename vinfo::value_type > dt_traits;
+			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, buffer vb )
+		{
+			add_vertex_buffer_impl< VTX, SLOT >( va, vb, std::integral_constant< bool, vertex_has_slot< VTX, SLOT >::value >() );
+		}
+
+		template < typename VTX >
+		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 );
+			add_vertex_buffer< VTX, slot::NORMAL   >  ( va, vb );
+			add_vertex_buffer< VTX, slot::TANGENT >   ( va, vb );
+			add_vertex_buffer< VTX, slot::BONEINDEX > ( va, vb );
+			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 = m_device->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 )
+		{
+			return create_vertex_array( data.data(), data.size(), hint );
+		}
+
+		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 );
+			buffer       ib = create_buffer( INDEX_BUFFER, hint, icount * sizeof( IDX ), i );
+			va->set_index_buffer( ib, type_to_enum< IDX >::type, true );
+			return va;
+		}
+
+		template < typename VTX, typename IDX >
+		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 = 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 < 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();
+		}
+
+		// TODO: HINTS ARE DIFFERENT!
+		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 )
+			{
+				const mesh_raw_channel* channel = channels[ch];
+				if ( channel->count > 0 )
+				{
+					buffer_type type = channel->get_buffer_type();
+					buffer b = m_device->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
+					{
+						add_vertex_buffers( va, b, channel );
+					}
+				}
+			}
+			return va;
+		}
+
 	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 312)
+++ /trunk/nv/interface/device.hh	(revision 313)
@@ -52,10 +52,8 @@
 
 	struct texture_tag {};
-	struct vertex_array_tag {};
 	struct buffer_tag {};
 	struct program_tag {};
 	typedef handle< uint32, 16, 16, buffer_tag >       buffer;
 	typedef handle< uint32, 16, 16, texture_tag >      texture;
-	typedef handle< uint32, 16, 16, vertex_array_tag > vertex_array;
 	typedef handle< uint32, 16, 16, program_tag >      program;
 
@@ -118,15 +116,4 @@
 	};
 
-	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];
-	};
-
 	struct program_info
 	{
@@ -150,12 +137,9 @@
 		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 vertex_array create_vertex_array() = 0;
 		virtual void release( texture ) = 0;
 		virtual void release( buffer ) = 0;
-		virtual void release( vertex_array ) = 0;
 		virtual void release( program ) = 0;
 		virtual const texture_info* get_texture_info( texture ) const = 0;
 		virtual const buffer_info* get_buffer_info( buffer ) const = 0;
-		virtual const vertex_array_info* get_vertex_array_info( vertex_array ) const = 0;
 		virtual uint32 get_ticks() = 0;
 		virtual void delay( uint32 ms ) = 0;
@@ -164,200 +148,4 @@
 		{
 			return create_texture( data->get_size(), data->get_format(), asampler, (void*)data->get_data() );
-		}
-
-		template < typename VTX, slot SLOT >
-		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, buffer vb, const std::true_type& )
-		{
-			typedef vertex_slot_info< VTX, SLOT > vinfo;
-			typedef datatype_traits< typename vinfo::value_type > dt_traits;
-			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, buffer vb )
-		{
-			add_vertex_buffer_impl< VTX, SLOT >( va, vb, std::integral_constant< bool, vertex_has_slot< VTX, SLOT >::value >() );
-		}
-
-		template < typename VTX >
-		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 );
-			add_vertex_buffer< VTX, slot::NORMAL   >  ( va, vb );
-			add_vertex_buffer< VTX, slot::TANGENT >   ( va, vb );
-			add_vertex_buffer< VTX, slot::BONEINDEX > ( va, vb );
-			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 )
-		{
-			return create_vertex_array( data.data(), data.size(), hint );
-		}
-
-		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 );
-			buffer       ib = create_buffer( INDEX_BUFFER, hint, icount * sizeof( IDX ), i );
-			va->set_index_buffer( ib, type_to_enum< IDX >::type, true );
-			return va;
-		}
-
-		template < typename VTX, typename IDX >
-		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 = 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 ) 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 ) 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 ( 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;
-				}
-			}
-		}
-
-		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 < 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();
-		}
-
-		// TODO: HINTS ARE DIFFERENT!
-		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 )
-			{
-				const mesh_raw_channel* channel = channels[ch];
-				if ( channel->count > 0 )
-				{
-					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
-					{
-						add_vertex_buffers( va, b, channel );
-					}
-				}
-			}
-			return va;
 		}
 
@@ -445,7 +233,4 @@
 	protected:
 		virtual uniform_base* get_uniform( program p, const string& name, bool fatal = true ) const = 0;
-
-		// TODO: remove
-		virtual vertex_array_info* get_vertex_array_info_mutable( vertex_array ) = 0;
 
 		void initialize_engine_uniforms()
Index: /trunk/src/gfx/debug_draw.cc
===================================================================
--- /trunk/src/gfx/debug_draw.cc	(revision 312)
+++ /trunk/src/gfx/debug_draw.cc	(revision 313)
@@ -28,14 +28,14 @@
 	"}\n";
 
-nv::debug_data::debug_data( device* a_device )
-	: m_device( a_device ), m_program(), m_va()
+nv::debug_data::debug_data( context* a_context )
+	: m_context( a_context ), m_program(), m_va()
 {
-	m_program = m_device->create_program( nv_debug_draw_vertex_shader, nv_debug_draw_fragment_shader );
+	m_program = m_context->get_device()->create_program( nv_debug_draw_vertex_shader, nv_debug_draw_fragment_shader );
 }
 
 void nv::debug_data::update()
 {
-	m_device->release( m_va );
-	m_va = m_device->create_vertex_array( m_data, nv::STATIC_DRAW );
+	m_context->release( m_va );
+	m_va = m_context->create_vertex_array( m_data, nv::STATIC_DRAW );
 }
 
@@ -75,5 +75,5 @@
 nv::debug_data::~debug_data()
 {
-	m_device->release( m_va );
-	m_device->release( m_program );
+	m_context->release( m_va );
+	m_context->get_device()->release( m_program );
 }
Index: /trunk/src/gfx/keyframed_mesh.cc
===================================================================
--- /trunk/src/gfx/keyframed_mesh.cc	(revision 312)
+++ /trunk/src/gfx/keyframed_mesh.cc	(revision 313)
@@ -105,5 +105,5 @@
 nv::keyframed_mesh::~keyframed_mesh()
 {
-	m_context->get_device()->release( m_va );
+	m_context->release( m_va );
 }
 
@@ -131,6 +131,6 @@
 	, m_gpu_next_frame( 0xFFFFFFFF )
 {
-	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 );
+	m_va      = a_context->create_vertex_array( a_data, STATIC_DRAW );
+	m_pbuffer = a_context->find_buffer( m_va, slot::POSITION );
 }
 
@@ -140,13 +140,12 @@
 	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 )
 	{
 		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 ) );
+		m_context->update_attribute_offset( m_va, slot::POSITION, base_offset );
+		m_context->update_attribute_offset( m_va, slot::NORMAL,   base_offset + sizeof( vec3 ) );
 		if ( m_has_tangent && m_loc_next_tangent != -1 )
 		{
-			dev->update_attribute_offset( m_va, slot::TANGENT, base_offset + 2*sizeof( vec3 ) );
+			m_context->update_attribute_offset( m_va, slot::TANGENT, base_offset + 2*sizeof( vec3 ) );
 		}
 		m_gpu_last_frame = m_last_frame;
@@ -155,9 +154,9 @@
 	{
 		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 ) );
+		m_context->update_attribute_offset( m_va, (slot)m_loc_next_position, base_offset );
+		m_context->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_context->update_attribute_offset( m_va, (slot)m_loc_next_tangent, base_offset + 2*sizeof( vec3 ) );
 		}
 		m_gpu_next_frame = m_next_frame;
@@ -175,8 +174,8 @@
 			m_loc_next_tangent  = dev->get_attribute_location( a_program, "nv_next_tangent" );
 
-		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 );
+		m_context->add_vertex_buffer( m_va, (slot)m_loc_next_position, m_pbuffer, FLOAT, 3, 0, m_vsize, false );
+		m_context->add_vertex_buffer( m_va, (slot)m_loc_next_normal,   m_pbuffer, FLOAT, 3, sizeof( vec3 ), m_vsize, false );
 		if ( m_has_tangent )
-			dev->add_vertex_buffer( m_va, (slot)m_loc_next_tangent, m_pbuffer, FLOAT, 4, 2*sizeof( vec3 ), m_vsize, false );
+			m_context->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 );
@@ -186,14 +185,14 @@
 	: keyframed_mesh( a_context, a_data, a_tag_map )
 {
-	m_va      = m_context->get_device()->create_vertex_array();
+	m_va      = m_context->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 );
+	m_context->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>() );
+	m_context->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_context->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 ];
Index: /trunk/src/gfx/particle_engine.cc
===================================================================
--- /trunk/src/gfx/particle_engine.cc	(revision 312)
+++ /trunk/src/gfx/particle_engine.cc	(revision 313)
@@ -485,7 +485,7 @@
 	info->particles = new particle[ data->quota ];
 	info->quads     = new particle_quad[ data->quota ];
-	info->vtx_array = m_device->create_vertex_array<particle_vtx>( 
+	info->vtx_array = m_context->create_vertex_array<particle_vtx>( 
 		(particle_vtx*)info->quads, data->quota*6, STREAM_DRAW );
-	info->vtx_buffer = m_device->find_buffer( info->vtx_array, slot::POSITION );
+	info->vtx_buffer = m_context->find_buffer( info->vtx_array, slot::POSITION );
 	info->last_update = 0;
 	info->test = false;
@@ -519,5 +519,5 @@
 		delete[] info->quads;
 		//if ( system->own_va ) 
-		m_device->release( info->vtx_array );
+		m_context->release( info->vtx_array );
 		m_systems.destroy( system );
 	}
Index: /trunk/src/gfx/skeletal_mesh.cc
===================================================================
--- /trunk/src/gfx/skeletal_mesh.cc	(revision 312)
+++ /trunk/src/gfx/skeletal_mesh.cc	(revision 313)
@@ -26,7 +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, 
+	m_va        = a_context->create_vertex_array( a_mesh_data, 
 STREAM_DRAW );
-	m_pbuffer   = a_context->get_device()->find_buffer( m_va, slot::POSITION );
+	m_pbuffer   = a_context->find_buffer( m_va, slot::POSITION );
 }
 
@@ -195,5 +195,5 @@
 	: 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 );
+	m_va          = a_context->create_vertex_array( a_mesh, nv::STATIC_DRAW );
 	m_index_count = a_mesh->get_count();
 	if ( m_bone_data )
Index: /trunk/src/gl/gl_context.cc
===================================================================
--- /trunk/src/gl/gl_context.cc	(revision 312)
+++ /trunk/src/gl/gl_context.cc	(revision 313)
@@ -12,4 +12,71 @@
 using namespace nv;
 
+nv::vertex_array nv::gl_context::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;
+}
+
+nv::framebuffer nv::gl_context::create_framebuffer()
+{
+	if ( is_gl_extension_loaded( GL_EXT_FRAMEBUFFER_OBJECT ) )
+	{
+		unsigned glid   = 0;
+		glGenFramebuffers( 1, &glid );
+		framebuffer result = m_framebuffers.create();
+		gl_framebuffer_info* info = m_framebuffers.get( result );
+		info->glid = glid;
+		info->color_attachment_count = 0;
+		return result;
+	}
+	else return framebuffer();
+}
+
+void nv::gl_context::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 ) m_device->release( info->attr[i].vbuffer );
+		}
+		if ( info->index.is_valid() && info->index_owner) m_device->release( info->index );
+		m_vertex_arrays.destroy( va );
+	}
+}
+
+void nv::gl_context::release( framebuffer f )
+{
+	gl_framebuffer_info* info = m_framebuffers.get( f );
+	if ( info )
+	{
+		// TODO: release textures?
+		glBindFramebuffer(GL_FRAMEBUFFER, 0);
+		glDeleteFramebuffers(1, &info->glid);
+	}
+}
+
+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 );
+}
+
+
 void gl_context::bind( texture t, texture_slot slot )
 {
@@ -32,16 +99,16 @@
 }
 
-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( 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 )
 {
-	const vertex_array_info* info = m_device->get_vertex_array_info( va );
+	const vertex_array_info* info = m_vertex_arrays.get( va );
 	if ( info )
 	{
@@ -51,5 +118,12 @@
 			uint32 location                    = static_cast<uint32>( vba.location );
 			glEnableVertexAttribArray( location );
-			bind( vba.vbuffer );
+			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, 
@@ -60,11 +134,28 @@
 				(void*)vba.offset
 				);
-			unbind( vba.vbuffer );
-		}
+		}
+		glBindBuffer( GL_ARRAY_BUFFER, 0 );
 
 		if ( info->index.is_valid() )
 		{
-			bind( info->index );
-		}
+			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
+			}
+		}
+	}
+}
+
+void nv::gl_context::bind( framebuffer f )
+{
+	const gl_framebuffer_info* info = m_framebuffers.get( f );
+	if ( info )
+	{
+		glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
 	}
 }
@@ -75,21 +166,21 @@
 }
 
-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( 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 )
 {
-	const vertex_array_info* info = m_device->get_vertex_array_info( va );
+	const vertex_array_info* info = m_vertex_arrays.get( va );
 	if ( info )
 	{
 		if ( info->index.is_valid() )
 		{
-			unbind( info->index );
+			glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
 		}
 
@@ -98,4 +189,14 @@
 			glDisableVertexAttribArray( static_cast<uint32>( info->attr[i].location ) );
 		}
+	}
+}
+
+void nv::gl_context::unbind( framebuffer f )
+{
+	// this way we are sure that the extension is loaded
+	const gl_framebuffer_info* info = m_framebuffers.get( f );
+	if ( info )
+	{
+		glBindFramebuffer( GL_FRAMEBUFFER, 0 );
 	}
 }
@@ -119,6 +220,7 @@
 	if ( info )
 	{
-		bind( b );
-		glBufferSubData( buffer_type_to_enum( info->type ), (GLintptr)offset, (GLsizeiptr)size, data );
+		GLenum glenum = buffer_type_to_enum( info->type );
+		glBindBuffer( glenum, info->glid );
+		glBufferSubData( glenum, (GLintptr)offset, (GLsizeiptr)size, data );
 	}
 }
@@ -483,4 +585,8 @@
 nv::gl_context::~gl_context()
 {
+	while ( m_framebuffers.size() > 0 )
+		release( m_framebuffers.get_handle(0) );
+	while ( m_vertex_arrays.size() > 0 )
+		release( m_vertex_arrays.get_handle(0) );
 }
 
@@ -500,5 +606,5 @@
 {
 	apply_render_state( rs );
-	const vertex_array_info* info = m_device->get_vertex_array_info( va );
+	const vertex_array_info* info = m_vertex_arrays.get( va );
 	if ( count > 0 && info )
 	{
Index: /trunk/src/gl/gl_device.cc
===================================================================
--- /trunk/src/gl/gl_device.cc	(revision 312)
+++ /trunk/src/gl/gl_device.cc	(revision 313)
@@ -90,6 +90,4 @@
 gl_device::~gl_device()
 {
-	while ( m_vertex_arrays.size() > 0 )
-		release( m_vertex_arrays.get_handle(0) );
 	while ( m_textures.size() > 0 )
 		release( m_textures.get_handle(0) );
@@ -98,5 +96,4 @@
 	while ( m_programs.size() > 0 )
 		release( m_programs.get_handle(0) );
-
 	SDL_Quit();
 }
@@ -192,29 +189,4 @@
 }
 
-nv::vertex_array nv::gl_device::create_vertex_array()
-{
-	vertex_array result = m_vertex_arrays.create();
-	vertex_array_info* info = m_vertex_arrays.get( result );
-	info->count       = 0;
-	info->index       = buffer();
-	info->index_owner = false;
-	info->index_type  = USHORT;
-	return result;
-}
-
-void nv::gl_device::release( vertex_array va )
-{
-	vertex_array_info* info = m_vertex_arrays.get( va );
-	if ( info )
-	{
-		for ( uint32 i = 0; i < info->count; ++i )
-		{
-			if ( info->attr[i].owner ) release( info->attr[i].vbuffer );
-		}
-		if ( info->index.is_valid() && info->index_owner) release( info->index );
-		m_vertex_arrays.destroy( va );
-	}
-}
-
 void nv::gl_device::release( program p )
 {
@@ -233,14 +205,4 @@
 		m_programs.destroy( p );
 	}
-}
-
-const vertex_array_info* nv::gl_device::get_vertex_array_info( vertex_array va ) const 
-{
-	return m_vertex_arrays.get( va );
-}
-
-vertex_array_info* nv::gl_device::get_vertex_array_info_mutable( vertex_array va ) 
-{
-	return m_vertex_arrays.get( va );
 }
 
@@ -485,3 +447,2 @@
 }
 
-
Index: /trunk/src/gui/gui_renderer.cc
===================================================================
--- /trunk/src/gui/gui_renderer.cc	(revision 312)
+++ /trunk/src/gui/gui_renderer.cc	(revision 313)
@@ -73,5 +73,5 @@
 	{ 
 		ctx->get_device()->release( shader ); 
-		ctx->get_device()->release( varray ); 
+		ctx->release( varray ); 
 	}
 
@@ -114,7 +114,7 @@
 	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_device()->create_vertex_array();
+	sr->varray     = m_window->get_context()->create_vertex_array();
 	buffer vb      = sr->buffer.get_buffer();
-	m_window->get_device()->add_vertex_buffers< vertex >( sr->varray, vb );
+	m_window->get_context()->add_vertex_buffers< vertex >( sr->varray, vb );
 
 	nv::sampler sampler( nv::sampler::LINEAR, nv::sampler::CLAMP_TO_EDGE );
@@ -267,5 +267,5 @@
 	{
 		buffer vb = sr->buffer.get_buffer();
-		m_context->get_device()->replace_vertex_buffer( sr->varray, vb, false );
+		m_context->replace_vertex_buffer( sr->varray, vb, false );
 	}
 	m_context->bind( sr->tex, TEX_DIFFUSE );
