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 )
 {
Index: trunk/src/gl/gl_device.cc
===================================================================
--- trunk/src/gl/gl_device.cc	(revision 326)
+++ trunk/src/gl/gl_device.cc	(revision 331)
@@ -62,32 +62,36 @@
 }
 
-nv::texture nv::gl_device::create_texture( ivec2 size, image_format aformat, sampler asampler, void* data /*= nullptr */ )
+nv::texture nv::gl_device::create_texture( texture_type type, ivec2 size, image_format aformat, sampler asampler, void* data /*= nullptr */ )
 {
 	unsigned glid = 0;
+	unsigned gl_type = texture_type_to_enum( type );
 	glGenTextures( 1, &glid );
 
-	glBindTexture( GL_TEXTURE_2D, glid );
+	glBindTexture( gl_type, glid );
 
 	// Detect if mipmapping was requested
-	if (( asampler.filter_min != sampler::LINEAR && asampler.filter_min != sampler::NEAREST ) ||
-		( asampler.filter_max != sampler::LINEAR && asampler.filter_max != sampler::NEAREST ))
-	{
-		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
-	}
-
-	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (int)nv::sampler_filter_to_enum( asampler.filter_min ) );
-	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (int)nv::sampler_filter_to_enum( asampler.filter_max ) );
-	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (int)nv::sampler_wrap_to_enum( asampler.wrap_s) );
-	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (int)nv::sampler_wrap_to_enum( asampler.wrap_t) );
-
-	if (data)
-	{
-		glTexImage2D( GL_TEXTURE_2D, 0, (GLint)nv::image_format_to_enum(aformat.format), size.x, size.y, 0, nv::image_format_to_enum(aformat.format), nv::datatype_to_gl_enum(aformat.type), data );
-	}
-
-	glBindTexture( GL_TEXTURE_2D, 0 );
+	if ( gl_type == GL_TEXTURE_2D && asampler.filter_min != sampler::LINEAR && asampler.filter_min != sampler::NEAREST )
+	{
+		// TODO: This should not be done if we use framebuffers!
+		glTexParameteri( gl_type, GL_GENERATE_MIPMAP, GL_TRUE);
+	}
+
+	if ( asampler.filter_max != sampler::NEAREST )
+	{
+		asampler.filter_max = sampler::LINEAR;
+	}
+
+	glTexParameteri( gl_type, GL_TEXTURE_MIN_FILTER, (int)nv::sampler_filter_to_enum( asampler.filter_min ) );
+	glTexParameteri( gl_type, GL_TEXTURE_MAG_FILTER, (int)nv::sampler_filter_to_enum( asampler.filter_max ) );
+	glTexParameteri( gl_type, GL_TEXTURE_WRAP_S, (int)nv::sampler_wrap_to_enum( asampler.wrap_s) );
+	glTexParameteri( gl_type, GL_TEXTURE_WRAP_T, (int)nv::sampler_wrap_to_enum( asampler.wrap_t) );
+
+	glTexImage2D( gl_type, 0, (GLint)nv::image_format_to_internal_enum(aformat.format), size.x, size.y, 0, nv::image_format_to_enum(aformat.format), nv::datatype_to_gl_enum(aformat.type), data );
+
+	glBindTexture( gl_type, 0 );
 
 	texture result = m_textures.create();
 	gl_texture_info* info = m_textures.get( result );
+	info->type     = type;
 	info->format   = aformat;
 	info->tsampler = asampler;
Index: trunk/src/gl/gl_enum.cc
===================================================================
--- trunk/src/gl/gl_enum.cc	(revision 326)
+++ trunk/src/gl/gl_enum.cc	(revision 331)
@@ -8,4 +8,17 @@
 
 using namespace nv;
+
+unsigned int nv::texture_type_to_enum( texture_type type )
+{
+	switch( type )
+	{
+	case TEXTURE_1D   : return GL_TEXTURE_1D;
+	case TEXTURE_2D   : return GL_TEXTURE_2D;
+	case TEXTURE_RECT : return GL_TEXTURE_RECTANGLE;
+	case TEXTURE_3D   : return GL_TEXTURE_3D;
+	case TEXTURE_CUBE : return GL_TEXTURE_CUBE_MAP;
+	NV_RETURN_COVERED_DEFAULT( 0 );
+	}
+}
 
 unsigned int nv::clear_state_buffers_to_mask( clear_state::buffers_type type )
@@ -167,4 +180,15 @@
 }
 
+unsigned int nv::image_format_to_internal_enum( pixel_format format )
+{
+	switch( format )
+	{
+	case RGB  : return GL_RGB8;
+	case RGBA : return GL_RGBA8;
+		NV_RETURN_COVERED_DEFAULT( 0 );
+	}
+}
+
+
 unsigned int nv::sampler_filter_to_enum( sampler::filter filter )
 {
@@ -207,4 +231,36 @@
 	}
 }
+
+unsigned int nv::framebuffer_slot_to_enum( framebuffer_slot slot )
+{
+	switch( slot )
+	{
+	case READ_FRAMEBUFFER : return GL_READ_FRAMEBUFFER;
+	case DRAW_FRAMEBUFFER : return GL_DRAW_FRAMEBUFFER;
+	case FRAMEBUFFER      : return GL_FRAMEBUFFER;
+	NV_RETURN_COVERED_DEFAULT( 0 );
+	}
+}
+
+
+unsigned int nv::output_slot_to_enum( output_slot slot )
+{
+	switch( slot )
+	{
+	case OUTPUT_0 : return GL_COLOR_ATTACHMENT0;
+	case OUTPUT_1 : return GL_COLOR_ATTACHMENT1;
+	case OUTPUT_2 : return GL_COLOR_ATTACHMENT2;
+	case OUTPUT_3 : return GL_COLOR_ATTACHMENT3;
+	case OUTPUT_4 : return GL_COLOR_ATTACHMENT4;
+	case OUTPUT_5 : return GL_COLOR_ATTACHMENT5;
+	case OUTPUT_6 : return GL_COLOR_ATTACHMENT6;
+	case OUTPUT_7 : return GL_COLOR_ATTACHMENT7;
+	case OUTPUT_NONE  : return 0;
+	case OUTPUT_FRONT : return GL_FRONT;
+	case OUTPUT_BACK  : return GL_BACK;
+		NV_RETURN_COVERED_DEFAULT( 0 );
+	}
+}
+
 
 unsigned int nv::datatype_to_gl_enum( datatype type )
@@ -257,10 +313,12 @@
 	case GL_INT_VEC4       : return INT_VECTOR_4;
 // TODO: separate types?
-	case GL_SAMPLER_1D         : return INT;
-	case GL_SAMPLER_2D         : return INT;
-	case GL_SAMPLER_3D         : return INT;
-	case GL_SAMPLER_CUBE       : return INT;
-	case GL_SAMPLER_1D_SHADOW  : return INT;	
-	case GL_SAMPLER_2D_SHADOW  : return INT;
+	case GL_SAMPLER_1D             : return INT;
+	case GL_SAMPLER_2D             : return INT;
+	case GL_SAMPLER_3D             : return INT;
+	case GL_SAMPLER_2D_RECT        : return INT;
+	case GL_SAMPLER_2D_RECT_SHADOW : return INT;
+	case GL_SAMPLER_CUBE           : return INT;
+	case GL_SAMPLER_1D_SHADOW      : return INT;	
+	case GL_SAMPLER_2D_SHADOW      : return INT;
 // TODO: implement?
 //	case GL_BOOL	
