Index: trunk/src/gl/gl_context.cc
===================================================================
--- trunk/src/gl/gl_context.cc	(revision 326)
+++ trunk/src/gl/gl_context.cc	(revision 331)
@@ -24,5 +24,5 @@
 nv::framebuffer nv::gl_context::create_framebuffer()
 {
-	if ( is_gl_extension_loaded( GL_EXT_FRAMEBUFFER_OBJECT ) )
+	if ( is_gl_extension_loaded( GL_EXT_FRAMEBUFFER_OBJECT ) && is_gl_extension_loaded( GL_EXT_FRAMEBUFFER_BLIT ) )
 	{
 		unsigned glid   = 0;
@@ -31,4 +31,5 @@
 		gl_framebuffer_info* info = m_framebuffers.get( result );
 		info->glid = glid;
+		info->depth_rb_glid = 0;
 		info->color_attachment_count = 0;
 		return result;
@@ -57,6 +58,9 @@
 	{
 		// TODO: release textures?
-		glBindFramebuffer(GL_FRAMEBUFFER, 0);
-		glDeleteFramebuffers(1, &info->glid);
+		glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+		glBindRenderbuffer( GL_RENDERBUFFER, 0 );
+		if ( info->depth_rb_glid == 0 )
+			glDeleteRenderbuffers( 1, &info->depth_rb_glid );
+		glDeleteFramebuffers( 1, &info->glid );
 	}
 }
@@ -77,4 +81,119 @@
 }
 
+void nv::gl_context::attach( framebuffer f, output_slot slot, texture t )
+{
+	// TODO: framebuffer variable, so no re-binding?
+	// TODO: support 1d, 3d textures, cubemaps or layers?
+	// TODO: support GL_READ_FRAMEBUFFER?
+	const gl_framebuffer_info* info  = m_framebuffers.get( f );
+	const gl_texture_info*     tinfo = (gl_texture_info*)m_device->get_texture_info( t );
+	if ( info )
+	{
+		glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
+		unsigned gl_type = texture_type_to_enum( tinfo->type );
+
+		if ( tinfo )
+		{
+			//		if ( tinfo->size.y == 0 )
+				//			glFramebufferTexture1D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+(unsigned)slot, GL_TEXTURE_1D, tinfo->glid, 0 );
+			glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+(unsigned)slot, gl_type, tinfo->glid, 0 );
+		}
+		else
+		{
+			glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+(unsigned)slot, gl_type, 0, 0 );
+		}
+
+	}
+}
+
+void nv::gl_context::attach( framebuffer f, texture depth )
+{
+	// TODO: framebuffer variable, so no re-binding?
+	// TODO: support GL_READ_FRAMEBUFFER?
+	const gl_framebuffer_info* info  = m_framebuffers.get( f );
+	const gl_texture_info*     tinfo = (gl_texture_info*)m_device->get_texture_info( depth );
+	if ( info )
+	{
+		glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
+		unsigned gl_type = texture_type_to_enum( tinfo->type );
+
+		if ( tinfo )
+		{
+			glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, gl_type, tinfo->glid, 0 );
+		}
+		else
+		{
+			glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, gl_type, 0, 0 );
+		}
+	}
+}
+
+void nv::gl_context::attach( framebuffer f, ivec2 size )
+{
+	// TODO: framebuffer variable, so no re-binding?
+	// TODO: support GL_READ_FRAMEBUFFER?
+	gl_framebuffer_info* info  = m_framebuffers.get( f );
+	if ( info )
+	{
+		glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
+		if ( info->depth_rb_glid ) glDeleteRenderbuffers( 1, &(info->depth_rb_glid) );
+		glGenRenderbuffers( 1, &(info->depth_rb_glid) );
+		glBindRenderbuffer( GL_RENDERBUFFER, info->depth_rb_glid );
+		glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.x, size.y );
+		glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, info->depth_rb_glid );
+		glBindRenderbuffer( GL_RENDERBUFFER, 0 );
+	}
+
+}
+
+void nv::gl_context::blit( framebuffer f, clear_state::buffers_type mask, ivec2 src1, ivec2 src2, ivec2 dst1, ivec2 dst2 )
+{
+	gl_framebuffer_info* info  = m_framebuffers.get( f );
+	if ( info )
+	{
+		glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
+		unsigned filter = mask == clear_state::COLOR_BUFFER ? GL_LINEAR : GL_NEAREST;
+		glBlitFramebuffer( src1.x, src1.y, src2.x, src2.y, dst1.x, dst1.y, dst2.x, dst2.y, clear_state_buffers_to_mask( mask ), filter );
+	}
+}
+
+
+bool nv::gl_context::check( framebuffer_slot ft )
+{
+	if ( is_gl_extension_loaded( GL_EXT_FRAMEBUFFER_OBJECT ) && is_gl_extension_loaded( GL_EXT_FRAMEBUFFER_BLIT ) )
+	{
+		unsigned result = glCheckFramebufferStatus( framebuffer_slot_to_enum(ft) );
+		if ( result == GL_FRAMEBUFFER_COMPLETE ) return true;
+		switch ( result )
+		{
+		case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT         : NV_LOG( LOG_ERROR, "gl_context::check : Framebuffer incomplete attachment!" ); break;
+		case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : NV_LOG( LOG_ERROR, "gl_context::check : Framebuffer missing attachment!" ); break;
+		case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS         : NV_LOG( LOG_ERROR, "gl_context::check : Framebuffer incomplete dimensions!" ); break;
+		case GL_FRAMEBUFFER_INCOMPLETE_FORMATS            : NV_LOG( LOG_ERROR, "gl_context::check : Framebuffer incomplete formats!" ); break;
+		case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER        : NV_LOG( LOG_ERROR, "gl_context::check : Framebuffer incomplete draw buffer!" ); break;
+		case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER        : NV_LOG( LOG_ERROR, "gl_context::check : Framebuffer incomplete read buffer!" ); break;
+		case GL_FRAMEBUFFER_UNSUPPORTED                   : NV_LOG( LOG_ERROR, "gl_context::check : Framebuffer format combination unsupported!" ); break;
+		default : NV_LOG( LOG_ERROR, "gl_context::check : Unknown Framebuffer error! (" << result << ")" ); break;
+		}
+	}
+	else
+	{
+		NV_LOG( LOG_ERROR, "gl_context::check : Framebuffer extensions not loaded!" );
+	}
+	return false;
+}
+
+void nv::gl_context::bind( framebuffer f, framebuffer_slot ft /*= FRAMEBUFFER_BOTH */ )
+{
+	const gl_framebuffer_info* info = m_framebuffers.get( f );
+	if ( info )
+	{
+		glBindFramebuffer( framebuffer_slot_to_enum(ft), info->glid );
+	}
+	else
+	{
+		glBindFramebuffer( framebuffer_slot_to_enum(ft), 0 );
+	}
+}
 
 void gl_context::bind( texture t, texture_slot slot )
@@ -84,5 +203,5 @@
 	{
 		glActiveTexture( GL_TEXTURE0 + static_cast< GLenum >( slot ) );
-		glBindTexture( GL_TEXTURE_2D, info->glid );
+		glBindTexture( texture_type_to_enum( info->type ), info->glid );
 	}
 }
@@ -151,13 +270,4 @@
 }
 
-void nv::gl_context::bind( framebuffer f )
-{
-	const gl_framebuffer_info* info = m_framebuffers.get( f );
-	if ( info )
-	{
-		glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
-	}
-}
-
 void nv::gl_context::unbind( program )
 {
@@ -199,4 +309,6 @@
 		glBindFramebuffer( GL_FRAMEBUFFER, 0 );
 	}
+	glDrawBuffer( GL_BACK );
+	glReadBuffer( GL_BACK );
 }
 
@@ -206,9 +318,10 @@
 	if ( info )
 	{
-		image_format format = info->format;
-		ivec2        size   = info->size;
-
-		glBindTexture( GL_TEXTURE_2D, info->glid );
-		glTexImage2D( GL_TEXTURE_2D, 0, (GLint)nv::image_format_to_enum(format.format), size.x, size.y, 0, nv::image_format_to_enum(format.format), nv::datatype_to_gl_enum(format.type), data );
+		image_format format  = info->format;
+		ivec2        size    = info->size;
+		unsigned     gl_type = texture_type_to_enum( info->type );
+
+		glBindTexture( gl_type, info->glid );
+		glTexImage2D( gl_type, 0, (GLint)nv::image_format_to_internal_enum(format.format), size.x, size.y, 0, nv::image_format_to_enum(format.format), nv::datatype_to_gl_enum(format.type), data );
 	}
 }
@@ -290,5 +403,5 @@
 		m_render_state.stencil_test.enabled = stencil.enabled;
 	}
-
+	
 	if ( stencil.enabled )
 	{
@@ -579,4 +692,6 @@
 	: context( a_device ), m_handle( a_handle )
 {
+	// TODO: configurable:
+	load_gl_extensions( GL_EXT_FRAMEBUFFER_BLIT | GL_EXT_FRAMEBUFFER_OBJECT );
 	force_apply_render_state( m_render_state );
 }
@@ -603,4 +718,26 @@
 }
 
+void nv::gl_context::set_draw_buffers( uint32 count, output_slot* slots )
+{
+	unsigned int buffers[8];
+	count = glm::min<uint32>( count, 8 );
+	for ( uint32 i = 0; i < count; ++i )
+	{
+		buffers[i] = output_slot_to_enum( slots[i] );
+		if ( slots[i] > OUTPUT_7 ) buffers[i] = 0;
+	}
+	glDrawBuffers( count, buffers );
+}
+
+void nv::gl_context::set_draw_buffer( output_slot slot )
+{
+	glDrawBuffer( output_slot_to_enum(slot) );
+}
+
+void nv::gl_context::set_read_buffer( output_slot slot )
+{
+	glReadBuffer( output_slot_to_enum(slot) );
+}
+
 void gl_context::draw( primitive prim, const render_state& rs, program p, vertex_array va, size_t count )
 {
