Index: trunk/src/gl/gl_context.cc
===================================================================
--- trunk/src/gl/gl_context.cc	(revision 491)
+++ trunk/src/gl/gl_context.cc	(revision 492)
@@ -74,8 +74,8 @@
 	}
 
-	for ( uint32 i = 0; i < info->count; ++i )
-	{
-		glDisableVertexAttribArray( static_cast<uint32>( info->attr[i].location ) );
-	}
+// 	for ( uint32 i = 0; i < info->count; ++i )
+// 	{
+// 		glDisableVertexAttribArray( static_cast<uint32>( info->attr[i].location ) );
+// 	}
 
 
@@ -83,5 +83,5 @@
 }
 
-nv::framebuffer nv::gl_context::create_framebuffer()
+nv::framebuffer nv::gl_context::create_framebuffer( uint32 temp_samples )
 {
 	unsigned glid   = 0;
@@ -92,4 +92,5 @@
 	info->depth_rb_glid = 0;
 	info->color_attachment_count = 0;
+	info->sample_count = temp_samples;
 	return result;
 }
@@ -192,5 +193,8 @@
 		glGenRenderbuffers( 1, &(info->depth_rb_glid) );
 		glBindRenderbuffer( GL_RENDERBUFFER, info->depth_rb_glid );
-		glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.x, size.y );
+		if ( info->sample_count > 1 )
+			glRenderbufferStorageMultisample( GL_RENDERBUFFER, info->sample_count, GL_DEPTH_COMPONENT16, size.x, size.y );
+		else
+			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 );
@@ -211,4 +215,21 @@
 
 
+void nv::gl_context::blit( framebuffer from, framebuffer to, clear_state::buffers_type mask, ivec2 src1, ivec2 src2, ivec2 dst1, ivec2 dst2 )
+{
+	gl_framebuffer_info* finfo = m_framebuffers.get( from );
+	gl_framebuffer_info* tinfo = m_framebuffers.get( to );
+	if ( finfo )
+	{
+		glBindFramebuffer( GL_READ_FRAMEBUFFER, finfo->glid );
+		glBindFramebuffer( GL_DRAW_FRAMEBUFFER, tinfo ? tinfo->glid : 0 );
+		unsigned filter = mask == clear_state::COLOR_BUFFER ? GL_LINEAR : GL_NEAREST;
+		int remove_below;
+		filter = 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 );
+		glBindFramebuffer( GL_READ_FRAMEBUFFER, 0 );
+		if ( tinfo ) glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
+	}
+}
+
 bool nv::gl_context::check( framebuffer_slot ft )
 {
@@ -220,4 +241,7 @@
 	switch ( result )
 	{
+	case GL_FRAMEBUFFER_UNDEFINED                     : NV_LOG_ERROR( "gl_context::check : Framebuffer undefined!" ); break;
+	case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE        : NV_LOG_ERROR( "gl_context::check : Incomplete multisample!" ); break;
+	case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS      : NV_LOG_ERROR( "gl_context::check : Incomplete layer targets!" ); break;
 	case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT         : NV_LOG_ERROR( "gl_context::check : Framebuffer incomplete attachment!" ); break;
 	case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : NV_LOG_ERROR( "gl_context::check : Framebuffer missing attachment!" ); break;
@@ -255,8 +279,6 @@
 	{
 		NV_ASSERT_ALWAYS( binfo->type == TEXTURE_BUFFER && tinfo->type == TEXTURE_1D_BUFFER, "bad texture or buffer type!" );
-		glActiveTexture( GL_TEXTURE0 );
-		glBindTexture( GL_TEXTURE_BUFFER, tinfo->glid );
+		bind( t, TEXTURE_0 );
 		glTexBuffer( GL_TEXTURE_BUFFER, image_format_to_internal_enum( tinfo->format.format ), binfo->glid );
-		glBindTexture( GL_TEXTURE_BUFFER, 0 );
 	}
 }
@@ -276,9 +298,12 @@
 void gl_context::bind( texture t, texture_slot slot )
 {
-	const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
-	if ( info )
-	{
-		glActiveTexture( GL_TEXTURE0 + static_cast< GLenum >( slot ) );
-		glBindTexture( texture_type_to_enum( info->type ), info->glid );
+	if ( m_bound_textures[ slot ] != t )
+	{
+		const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
+		if ( info )
+		{
+			set_active_texture( slot );
+			glBindTexture( texture_type_to_enum( info->type ), info->glid );
+		}
 	}
 }
@@ -318,4 +343,10 @@
 }
 
+void nv::gl_context::set_active_texture( texture_slot slot )
+{
+	if ( slot != m_active_slot )
+		glActiveTexture( GL_TEXTURE0 + static_cast<GLenum>( slot ) );
+}
+
 // void nv::gl_context::unbind( buffer b )
 // {
@@ -352,4 +383,5 @@
 	const gl_texture_info* info = static_cast< const gl_texture_info* >( m_device->get_texture_info( t ) );
 	NV_ASSERT_ALWAYS( info->type != TEXTURE_1D_BUFFER, "Buffer texture passed to update!" );
+	NV_ASSERT_ALWAYS( info->type != TEXTURE_2D_MULTISAMPLE, "Multisample texture passed to update!" );
 	if ( info )
 	{
@@ -358,5 +390,6 @@
 		unsigned     gl_type = texture_type_to_enum( info->type );
 
-		glBindTexture( gl_type, info->glid );
+		if ( m_bound_textures[ m_active_slot ] != t )
+			glBindTexture( gl_type, info->glid );
 		int this_should_be_subTexImage;
 		if ( info->type == TEXTURE_3D || info->type == TEXTURE_2D_ARRAY )
@@ -543,4 +576,13 @@
 		glDepthMask( mask );
 		m_render_state.depth_mask = mask;
+	}
+}
+
+void gl_context::apply_multisample( bool multisample )
+{
+	if ( m_render_state.multisample != multisample )
+	{
+		glDepthMask( multisample );
+		m_render_state.multisample = multisample;
 	}
 }
@@ -727,4 +769,5 @@
 	apply_color_mask( state.color_mask );
 	apply_depth_mask( state.depth_mask );
+	apply_multisample( state.multisample );
 	apply_polygon_mode( state.polygon_mode );
 }
@@ -736,4 +779,5 @@
 	// TODO: configurable:
 //	load_gl_extensions( GL_EXT_FRAMEBUFFER_BLIT | GL_EXT_FRAMEBUFFER_OBJECT | GL_EXT_TEXTURE_ARRAY );
+	m_active_slot = texture_slot( -1 );
 	force_apply_render_state( m_render_state );
 }
