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 );
