[iortcw] 33/152: MP: Rend2: Direct State Access / Cubemap loading / Merge cvars into r_pbr

Simon McVittie smcv at debian.org
Fri Sep 8 10:39:54 UTC 2017


This is an automated email from the git hooks/post-receive script.

smcv pushed a commit to annotated tag 1.5a
in repository iortcw.

commit a383f6a3298469e22ed3e5794dd5a02200ea18e2
Author: MAN-AT-ARMS <M4N4T4RMS at gmail.com>
Date:   Thu Feb 11 20:12:50 2016 -0500

    MP: Rend2: Direct State Access / Cubemap loading / Merge cvars into r_pbr
    
    Merged cvars: r_glossIsRoughness, r_specularIsMetallic, r_framebufferGamma, r_tonemapGamma, r_materialGamma, r_lightGamma
---
 MP/Makefile                             |   1 +
 MP/code/rend2/glsl/calclevels4x_fp.glsl |   4 +-
 MP/code/rend2/glsl/lightall_fp.glsl     |  48 ++--
 MP/code/rend2/glsl/tonemap_fp.glsl      |   8 +-
 MP/code/rend2/qgl.h                     |  44 ++++
 MP/code/rend2/tr_animation.c            |   6 +-
 MP/code/rend2/tr_backend.c              | 212 +++++-------------
 MP/code/rend2/tr_bsp.c                  |  43 +++-
 MP/code/rend2/tr_dsa.c                  | 287 ++++++++++++++++++++++++
 MP/code/rend2/tr_dsa.h                  |  80 +++++++
 MP/code/rend2/tr_extensions.c           | 109 +++++++++
 MP/code/rend2/tr_fbo.c                  | 290 +++++-------------------
 MP/code/rend2/tr_fbo.h                  |   1 +
 MP/code/rend2/tr_glsl.c                 | 102 ++-------
 MP/code/rend2/tr_image.c                | 376 +++++++++++++++-----------------
 MP/code/rend2/tr_init.c                 |  37 +---
 MP/code/rend2/tr_local.h                |  27 +--
 MP/code/rend2/tr_main.c                 |   2 +-
 MP/code/rend2/tr_postprocess.c          | 105 ++++-----
 MP/code/rend2/tr_scene.c                |   2 +-
 MP/code/rend2/tr_shade.c                |  16 +-
 MP/code/rend2/tr_shader.c               |  60 +++--
 MP/code/rend2/tr_shadows.c              |   4 +-
 MP/code/rend2/tr_sky.c                  |   4 +-
 MP/code/rend2/tr_surface.c              |   4 +-
 MP/code/renderer/qgl.h                  |  56 ++++-
 MP/code/renderer/tr_image.c             |   6 +-
 MP/code/renderer/tr_local.h             |   1 -
 MP/rend2-readme.txt                     |  20 +-
 29 files changed, 1057 insertions(+), 898 deletions(-)

diff --git a/MP/Makefile b/MP/Makefile
index 403256d..423ae78 100644
--- a/MP/Makefile
+++ b/MP/Makefile
@@ -1735,6 +1735,7 @@ Q3R2OBJ = \
   $(B)/rend2/tr_bsp.o \
   $(B)/rend2/tr_cmds.o \
   $(B)/rend2/tr_curve.o \
+  $(B)/rend2/tr_dsa.o \
   $(B)/rend2/tr_extramath.o \
   $(B)/rend2/tr_extensions.o \
   $(B)/rend2/tr_fbo.o \
diff --git a/MP/code/rend2/glsl/calclevels4x_fp.glsl b/MP/code/rend2/glsl/calclevels4x_fp.glsl
index 1de59e9..0d298b6 100644
--- a/MP/code/rend2/glsl/calclevels4x_fp.glsl
+++ b/MP/code/rend2/glsl/calclevels4x_fp.glsl
@@ -14,8 +14,8 @@ vec3 GetValues(vec2 offset, vec3 current)
 
 #ifdef FIRST_PASS
 
-  #if defined(r_framebufferGamma)
-	minAvgMax = pow(minAvgMax, vec3(r_framebufferGamma));
+  #if defined(USE_PBR)
+	minAvgMax = pow(minAvgMax, vec3(2.2));
   #endif
 
 	float lumi = max(dot(LUMINANCE_VECTOR, minAvgMax), 0.000001);
diff --git a/MP/code/rend2/glsl/lightall_fp.glsl b/MP/code/rend2/glsl/lightall_fp.glsl
index b8f3985..eb8ba90 100644
--- a/MP/code/rend2/glsl/lightall_fp.glsl
+++ b/MP/code/rend2/glsl/lightall_fp.glsl
@@ -276,9 +276,9 @@ void main()
 	attenuation  = 1.0;
   #endif
 
-  #if defined(r_lightGamma)
-	lightColor   = pow(lightColor,   vec3(r_lightGamma));
-	ambientColor = pow(ambientColor, vec3(r_lightGamma));
+  #if defined(USE_PBR)
+	lightColor   = pow(lightColor,   vec3(2.2));
+	ambientColor = pow(ambientColor, vec3(2.2));
   #endif
 
   #if defined(USE_NORMALMAP)
@@ -319,7 +319,7 @@ void main()
 
 	// Recover any unused light as ambient, in case attenuation is over 4x or
 	// light is below the surface
-	ambientColor = clamp(ambientColor - lightColor * surfNL, 0.0, 1.0);
+	ambientColor = max(ambientColor - lightColor * surfNL, vec3(0.0));
   #endif
   
 	vec3 reflectance;
@@ -335,21 +335,18 @@ void main()
 
 	specular *= u_SpecularScale;
 
-  #if defined(r_materialGamma)
-	diffuse.rgb   = pow(diffuse.rgb,  vec3(r_materialGamma));
-    #if !defined(SPECULAR_IS_METALLIC)
-	specular.rgb  = pow(specular.rgb, vec3(r_materialGamma));
-    #endif
+  #if defined(USE_PBR)
+	diffuse.rgb = pow(diffuse.rgb, vec3(2.2));
   #endif
 
 	float gloss = specular.a;
-  #if defined(GLOSS_IS_ROUGHNESS)
-	float roughness = gloss;
+  #if defined(USE_PBR)
+	float roughness = 1.0 - specular.r;
   #else
 	float roughness = exp2(-3.0 * gloss);
   #endif
 
-  #if defined(SPECULAR_IS_METALLIC)
+  #if defined(USE_PBR)
 	// diffuse is actually base color, and green of specular is metallicness
 	float metallic = specular.g;
 
@@ -374,7 +371,7 @@ void main()
 	// from http://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
 	vec3 parallax = u_CubeMapInfo.xyz + u_CubeMapInfo.w * viewDir;
 
-    #if defined(GLOSS_IS_ROUGHNESS)
+    #if defined(USE_PBR)
 	vec3 cubeLightColor = textureCubeLod(u_CubeMap, R + parallax, 7.0 * roughness).rgb * u_EnableTextures.w;
     #else
 	vec3 cubeLightColor = textureCubeLod(u_CubeMap, R + parallax, 7.0 - gloss * 7.0).rgb * u_EnableTextures.w;
@@ -385,8 +382,8 @@ void main()
 	//vec3 cubeLightDiffuse = max(textureCubeLod(u_CubeMap, N, 6.0).rgb, 0.5 / 255.0);
 	//cubeLightColor /= dot(cubeLightDiffuse, vec3(0.2125, 0.7154, 0.0721));
 
-    #if defined(r_framebufferGamma)
-	cubeLightColor = pow(cubeLightColor, vec3(r_framebufferGamma));
+    #if defined(USE_PBR)
+	cubeLightColor = pow(cubeLightColor, vec3(2.2));
     #endif
 
 	// multiply cubemap values by lighting
@@ -421,8 +418,8 @@ void main()
 
 	lightColor = u_PrimaryLightColor;
 
-    #if defined(r_lightGamma)
-	lightColor = pow(lightColor, vec3(r_lightGamma));
+    #if defined(USE_PBR)
+	lightColor = pow(lightColor, vec3(2.2));
     #endif
 
     #if defined(USE_SHADOWMAP)
@@ -434,6 +431,11 @@ void main()
 
 	gl_FragColor.rgb += lightColor * reflectance * NL2;
   #endif
+
+  #if defined(USE_PBR)
+	gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0 / 2.2));
+  #endif
+
 #else
 	lightColor = var_Color.rgb;
 
@@ -441,21 +443,9 @@ void main()
 	lightColor *= lightmapColor.rgb;
   #endif
 
-  #if defined(r_lightGamma)
-	lightColor = pow(lightColor, vec3(r_lightGamma));
-  #endif
-
-  #if defined(r_materialGamma)
-	diffuse.rgb   = pow(diffuse.rgb,  vec3(r_materialGamma));
-  #endif
-
 	gl_FragColor.rgb = diffuse.rgb * lightColor;
 
 #endif
 
-#if defined(r_framebufferGamma)
-	gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0 / r_framebufferGamma));
-#endif
-
 	gl_FragColor.a = diffuse.a * var_Color.a;
 }
diff --git a/MP/code/rend2/glsl/tonemap_fp.glsl b/MP/code/rend2/glsl/tonemap_fp.glsl
index 1368c5b..5d8841d 100644
--- a/MP/code/rend2/glsl/tonemap_fp.glsl
+++ b/MP/code/rend2/glsl/tonemap_fp.glsl
@@ -28,8 +28,8 @@ void main()
 {
 	vec4 color = texture2D(u_TextureMap, var_TexCoords) * u_Color;
 
-#if defined(r_framebufferGamma)
-	color.rgb = pow(color.rgb, vec3(r_framebufferGamma));
+#if defined(USE_PBR)
+	color.rgb = pow(color.rgb, vec3(2.2));
 #endif
 
 	vec3 minAvgMax = texture2D(u_LevelsMap, var_TexCoords).rgb;
@@ -46,8 +46,8 @@ void main()
 
 	color.rgb = clamp(color.rgb * var_InvWhite, 0.0, 1.0);
 
-#if defined(r_tonemapGamma)
-	color.rgb = pow(color.rgb, vec3(1.0 / r_tonemapGamma));
+#if defined(USE_PBR)
+	color.rgb = pow(color.rgb, vec3(1.0 / 2.2));
 #endif
 
 	gl_FragColor = color;
diff --git a/MP/code/rend2/qgl.h b/MP/code/rend2/qgl.h
index 5e20b48..4ab6b45 100644
--- a/MP/code/rend2/qgl.h
+++ b/MP/code/rend2/qgl.h
@@ -814,6 +814,50 @@ extern GLboolean (APIENTRY * qglIsVertexArrayARB)(GLuint array);
 #define GL_VERTEX_ARRAY_BINDING_ARB                0x85B5
 #endif
 
+// GL_EXT_direct_state_access
+extern GLvoid(APIENTRY * qglBindMultiTexture)(GLenum texunit, GLenum target, GLuint texture);
+extern GLvoid(APIENTRY * qglTextureParameterf)(GLuint texture, GLenum target, GLenum pname, GLfloat param);
+extern GLvoid(APIENTRY * qglTextureParameteri)(GLuint texture, GLenum target, GLenum pname, GLint param);
+extern GLvoid(APIENTRY * qglTextureImage2D)(GLuint texture, GLenum target, GLint level, GLint internalformat,
+	GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+extern GLvoid(APIENTRY * qglTextureSubImage2D)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset,
+	GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+extern GLvoid(APIENTRY * qglCopyTextureImage2D)(GLuint texture, GLenum target, GLint level, GLenum internalformat,
+	GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+extern GLvoid(APIENTRY * qglCompressedTextureImage2D)(GLuint texture, GLenum target, GLint level, GLenum internalformat,
+	GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+extern GLvoid(APIENTRY * qglCompressedTextureSubImage2D)(GLuint texture, GLenum target, GLint level,
+	GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
+	GLsizei imageSize, const GLvoid *data);
+extern GLvoid(APIENTRY * qglGenerateTextureMipmap)(GLuint texture, GLenum target);
+
+extern GLvoid(APIENTRY * qglProgramUniform1i)(GLuint program, GLint location, GLint v0);
+extern GLvoid(APIENTRY * qglProgramUniform1f)(GLuint program, GLint location, GLfloat v0);
+extern GLvoid(APIENTRY * qglProgramUniform2f)(GLuint program, GLint location,
+	GLfloat v0, GLfloat v1);
+extern GLvoid(APIENTRY * qglProgramUniform3f)(GLuint program, GLint location,
+	GLfloat v0, GLfloat v1, GLfloat v2);
+extern GLvoid(APIENTRY * qglProgramUniform4f)(GLuint program, GLint location,
+	GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+extern GLvoid(APIENTRY * qglProgramUniform1fv)(GLuint program, GLint location,
+	GLsizei count, const GLfloat *value);
+extern GLvoid(APIENTRY * qglProgramUniformMatrix4fv)(GLuint program, GLint location,
+	GLsizei count, GLboolean transpose,
+	const GLfloat *value);
+
+extern GLvoid(APIENTRY * qglNamedRenderbufferStorage)(GLuint renderbuffer,
+	GLenum internalformat, GLsizei width, GLsizei height);
+
+extern GLvoid(APIENTRY * qglNamedRenderbufferStorageMultisample)(GLuint renderbuffer,
+	GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+
+extern GLenum(APIENTRY * qglCheckNamedFramebufferStatus)(GLuint framebuffer, GLenum target);
+extern GLvoid(APIENTRY * qglNamedFramebufferTexture2D)(GLuint framebuffer,
+	GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+extern GLvoid(APIENTRY * qglNamedFramebufferRenderbuffer)(GLuint framebuffer,
+	GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+
+
 #if defined(WIN32)
 // WGL_ARB_create_context
 #ifndef WGL_ARB_create_context
diff --git a/MP/code/rend2/tr_animation.c b/MP/code/rend2/tr_animation.c
index 20d9b93..5932f89 100644
--- a/MP/code/rend2/tr_animation.c
+++ b/MP/code/rend2/tr_animation.c
@@ -1198,7 +1198,7 @@ void RB_SurfaceAnim( mdsSurface_t *surface ) {
 			for ( i = 0; i < surface->numBoneReferences; i++, boneRefs++ ) {
 				bonePtr = &bones[*boneRefs];
 
-				GL_Bind( tr.whiteImage );
+				GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
 				qglLineWidth( 1 );
 				qglBegin( GL_LINES );
 				for ( j = 0; j < 3; j++ ) {
@@ -1232,7 +1232,7 @@ void RB_SurfaceAnim( mdsSurface_t *surface ) {
 			tempVert = ( float * )( tess.xyz + baseVertex );
 			tempNormal = ( uint32_t * )( tess.normal + baseVertex );
 
-			GL_Bind( tr.whiteImage );
+			GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
 			qglLineWidth( 1 );
 			qglBegin( GL_LINES );
 			qglColor3f( .0,.0,.8 );
@@ -1352,7 +1352,7 @@ int R_GetBoneTag( orientation_t *outTag, mdsHeader_t *mds, int startTagIndex, co
 	if (r_bonesDebug->integer == 4) {
 		int j;
 		// DEBUG: show the tag position/axis
-		GL_Bind( tr.whiteImage );
+		GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
 		qglLineWidth( 2 );
 		qglBegin( GL_LINES );
 		for (j=0; j<3; j++) {
diff --git a/MP/code/rend2/tr_backend.c b/MP/code/rend2/tr_backend.c
index 34550ae..f33e5a5 100644
--- a/MP/code/rend2/tr_backend.c
+++ b/MP/code/rend2/tr_backend.c
@@ -27,6 +27,8 @@ If you have questions concerning this license or the applicable additional terms
 */
 
 #include "tr_local.h"
+#include "tr_fbo.h"
+#include "tr_dsa.h"
 
 backEndData_t  *backEndData;
 backEndState_t backEnd;
@@ -43,80 +45,27 @@ static float s_flipMatrix[16] = {
 
 
 /*
-** GL_Bind
-*/
-void GL_Bind( image_t *image ) {
-	int texnum;
-
-	if ( !image ) {
-		ri.Printf( PRINT_WARNING, "GL_Bind: NULL image\n" );
-		texnum = tr.defaultImage->texnum;
-	} else {
-		texnum = image->texnum;
-	}
-
-	if ( r_nobind->integer && tr.dlightImage ) {        // performance evaluation option
-		texnum = tr.dlightImage->texnum;
-	}
-
-	if ( glState.currenttextures[glState.currenttmu] != texnum ) {
-		if ( image ) {
-			image->frameUsed = tr.frameCount;
-		}
-		glState.currenttextures[glState.currenttmu] = texnum;
-		if (image && image->flags & IMGFLAG_CUBEMAP)
-			qglBindTexture( GL_TEXTURE_CUBE_MAP, texnum );
-		else
-			qglBindTexture( GL_TEXTURE_2D, texnum );
-	}
-}
-
-
-/*
-** GL_SelectTexture
-*/
-void GL_SelectTexture( int unit ) {
-	if ( glState.currenttmu == unit ) {
-		return;
-	}
-
-	if (!(unit >= 0 && unit <= 31))
-		ri.Error( ERR_DROP, "GL_SelectTexture: unit = %i", unit );
-
-	if (!qglActiveTextureARB)
-		ri.Error( ERR_DROP, "GL_SelectTexture: multitexture disabled" );
-
-	qglActiveTextureARB( GL_TEXTURE0_ARB + unit );
-
-	glState.currenttmu = unit;
-}
-
-
-/*
 ** GL_BindToTMU
 */
 void GL_BindToTMU( image_t *image, int tmu )
 {
-	int		texnum;
-	int     oldtmu = glState.currenttmu;
+	GLuint texture = (tmu == TB_COLORMAP) ? tr.defaultImage->texnum : 0;
+	GLenum target = GL_TEXTURE_2D;
 
-	if (!image)
-		texnum = 0;
-	else
-		texnum = image->texnum;
-
-	if ( glState.currenttextures[tmu] != texnum ) {
-		GL_SelectTexture( tmu );
-		if (image)
-			image->frameUsed = tr.frameCount;
-		glState.currenttextures[tmu] = texnum;
+	if (image)
+	{
+		if (image->flags & IMGFLAG_CUBEMAP)
+			target = GL_TEXTURE_CUBE_MAP;
 
-		if (image && (image->flags & IMGFLAG_CUBEMAP))
-			qglBindTexture( GL_TEXTURE_CUBE_MAP, texnum );
-		else
-			qglBindTexture( GL_TEXTURE_2D, texnum );
-		GL_SelectTexture( oldtmu );
+		image->frameUsed = tr.frameCount;
+		texture = image->texnum;
+	}
+	else
+	{
+		ri.Printf(PRINT_WARNING, "GL_BindToTMU: NULL image\n");
 	}
+
+	GL_BindMultiTexture(GL_TEXTURE0_ARB + tmu, target, texture);
 }
 
 /*
@@ -148,37 +97,6 @@ void GL_Cull( int cullType ) {
 }
 
 /*
-** GL_TexEnv
-*/
-void GL_TexEnv( int env ) {
-	if ( env == glState.texEnv[glState.currenttmu] ) {
-		return;
-	}
-
-	glState.texEnv[glState.currenttmu] = env;
-
-
-	switch ( env )
-	{
-	case GL_MODULATE:
-		qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
-		break;
-	case GL_REPLACE:
-		qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
-		break;
-	case GL_DECAL:
-		qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
-		break;
-	case GL_ADD:
-		qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );
-		break;
-	default:
-		ri.Error( ERR_DROP, "GL_TexEnv: invalid env '%d' passed", env );
-		break;
-	}
-}
-
-/*
 ** GL_State
 **
 ** This routine is responsible for setting the most commonly changed state
@@ -452,31 +370,19 @@ void RB_BeginDrawingView( void ) {
 
 	if (glRefConfig.framebufferObject)
 	{
+		FBO_t *fbo = backEnd.viewParms.targetFbo;
+
 		// FIXME: HUGE HACK: render to the screen fbo if we've already postprocessed the frame and aren't drawing more world
 		// drawing more world check is in case of double renders, such as skyportals
-		if (backEnd.viewParms.targetFbo == NULL)
-		{
-			if (!tr.renderFbo || (backEnd.framePostProcessed && (backEnd.refdef.rdflags & RDF_NOWORLDMODEL)))
-			{
-				FBO_Bind(NULL);
-			}
-			else
-			{
-				FBO_Bind(tr.renderFbo);
-			}
-		}
-		else
-		{
-			FBO_Bind(backEnd.viewParms.targetFbo);
+		if (fbo == NULL && !(backEnd.framePostProcessed && (backEnd.refdef.rdflags & RDF_NOWORLDMODEL)))
+			fbo = tr.renderFbo;
 
-			// FIXME: hack for cubemap testing
-			if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo)
-			{
-				cubemap_t *cubemap = &tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex];
-				//qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, backEnd.viewParms.targetFbo->colorImage[0]->texnum, 0);
-				qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, cubemap->image->texnum, 0);
-			}
+		if (tr.renderCubeFbo && fbo == tr.renderCubeFbo)
+		{
+			cubemap_t *cubemap = &tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex];
+			FBO_AttachImage(fbo, cubemap->image, GL_COLOR_ATTACHMENT0_EXT, backEnd.viewParms.targetFboLayer);
 		}
+		FBO_Bind(fbo);
 	}
 
 	//
@@ -928,6 +834,7 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *
 	}
 
 	RE_UploadCinematic (w, h, cols, rows, data, client, dirty);
+	GL_BindToTMU(tr.scratchImage[client], TB_COLORMAP);
 
 	if ( r_speeds->integer ) {
 		end = ri.Milliseconds();
@@ -937,14 +844,7 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *
 	// FIXME: HUGE hack
 	if (glRefConfig.framebufferObject)
 	{
-		if (!tr.renderFbo || backEnd.framePostProcessed)
-		{
-			FBO_Bind(NULL);
-		}
-		else
-		{
-			FBO_Bind(tr.renderFbo);
-		}
+		FBO_Bind(backEnd.framePostProcessed ? NULL : tr.renderFbo);
 	}
 
 	RB_SetGL2D();
@@ -969,23 +869,30 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *
 
 
 void RE_UploadCinematic( int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty ) {
+	GLuint texture;
+
+	if (!tr.scratchImage[client])
+	{
+		ri.Printf(PRINT_WARNING, "RE_UploadCinematic: scratch images not initialized\n");
+		return;
+	}
 
-	GL_Bind( tr.scratchImage[client] );
+	texture = tr.scratchImage[client]->texnum;
 
 	// if the scratchImage isn't in the format we want, specify it as a new texture
 	if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
 		tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
 		tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
-		qglTexImage2D( GL_TEXTURE_2D, 0, 3, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
-		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
-		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
-		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+		qglTextureImage2D(texture, GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+		qglTextureParameterf(texture, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		qglTextureParameterf(texture, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+		qglTextureParameterf(texture, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+		qglTextureParameterf(texture, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 	} else {
 		if ( dirty ) {
 			// otherwise, just subimage upload it so that drivers can tell we are going to be changing
 			// it and don't try and do a texture compression
-			qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );
+			qglTextureSubImage2D(texture, GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data);
 		}
 	}
 }
@@ -1024,16 +931,7 @@ const void *RB_StretchPic( const void *data ) {
 
 	// FIXME: HUGE hack
 	if (glRefConfig.framebufferObject)
-	{
-		if (!tr.renderFbo || backEnd.framePostProcessed)
-		{
-			FBO_Bind(NULL);
-		}
-		else
-		{
-			FBO_Bind(tr.renderFbo);
-		}
-	}
+		FBO_Bind(backEnd.framePostProcessed ? NULL : tr.renderFbo);
 
 	RB_SetGL2D();
 
@@ -1337,11 +1235,10 @@ const void  *RB_DrawSurfs( const void *data ) {
 			// If we're using multisampling, resolve the depth first
 			FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
 		}
-		else if (tr.renderFbo == NULL)
+		else if (tr.renderFbo == NULL && tr.renderDepthImage)
 		{
 			// If we're rendering directly to the screen, copy the depth to a texture
-			GL_BindToTMU(tr.renderDepthImage, 0);
-			qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0);
+			qglCopyTextureImage2D(tr.renderDepthImage->texnum, GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0);
 		}
 
 		if (r_ssao->integer)
@@ -1581,10 +1478,8 @@ const void  *RB_DrawSurfs( const void *data ) {
 		cubemap_t *cubemap = &tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex];
 
 		FBO_Bind(NULL);
-		GL_SelectTexture(TB_CUBEMAP);
-		GL_BindToTMU(cubemap->image, TB_CUBEMAP);
-		qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP);
-		GL_SelectTexture(0);
+		if (cubemap && cubemap->image)
+			qglGenerateTextureMipmap(cubemap->image->texnum, GL_TEXTURE_CUBE_MAP);
 	}
 
 	return (const void *)( cmd + 1 );
@@ -1663,7 +1558,7 @@ void RB_ShowImages( void ) {
 		{
 			vec4_t quadVerts[4];
 
-			GL_Bind(image);
+			GL_BindToTMU(image, TB_COLORMAP);
 
 			VectorSet4(quadVerts[0], x, y, 0, 1);
 			VectorSet4(quadVerts[1], x + w, y, 0, 1);
@@ -1838,21 +1733,18 @@ const void *RB_CapShadowMap(const void *data)
 
 	if (cmd->map != -1)
 	{
-		GL_SelectTexture(0);
 		if (cmd->cubeSide != -1)
 		{
 			if (tr.shadowCubemaps[cmd->map])
 			{
-				GL_Bind(tr.shadowCubemaps[cmd->map]);
-				qglCopyTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cmd->cubeSide, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0);
+				qglCopyTextureImage2D(tr.shadowCubemaps[cmd->map]->texnum, GL_TEXTURE_CUBE_MAP_POSITIVE_X + cmd->cubeSide, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0);
 			}
 		}
 		else
 		{
 			if (tr.pshadowMaps[cmd->map])
 			{
-				GL_Bind(tr.pshadowMaps[cmd->map]);
-				qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0);
+				qglCopyTextureImage2D(tr.pshadowMaps[cmd->map]->texnum, GL_TEXTURE_2D, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - (backEnd.refdef.y + PSHADOW_MAP_SIZE), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0);
 			}
 		}
 	}
@@ -1925,7 +1817,7 @@ const void *RB_PostProcess(const void *data)
 
 	if (srcFbo)
 	{
-		if (r_hdr->integer && (r_toneMap->integer || r_forceToneMap->integer) && qglActiveTextureARB)
+		if (r_hdr->integer && (r_toneMap->integer || r_forceToneMap->integer))
 		{
 			autoExposure = r_autoExposure->integer || r_forceAutoExposure->integer;
 			RB_ToneMap(srcFbo, srcBox, NULL, dstBox, autoExposure);
@@ -2041,11 +1933,11 @@ const void *RB_ExportCubemaps(const void *data)
 		{
 			char filename[MAX_QPATH];
 			cubemap_t *cubemap = &tr.cubemaps[i];
-			unsigned char *p = cubemapPixels;
+			byte *p = cubemapPixels;
 
 			for (j = 0; j < 6; j++)
 			{
-				qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, cubemap->image->texnum, 0);
+				FBO_AttachImage(tr.renderCubeFbo, cubemap->image, GL_COLOR_ATTACHMENT0_EXT, j);
 				qglReadPixels(0, 0, r_cubemapSize->integer, r_cubemapSize->integer, GL_RGBA, GL_UNSIGNED_BYTE, p);
 				p += sideSize;
 			}
diff --git a/MP/code/rend2/tr_bsp.c b/MP/code/rend2/tr_bsp.c
index be2170e..0fa488a 100644
--- a/MP/code/rend2/tr_bsp.c
+++ b/MP/code/rend2/tr_bsp.c
@@ -146,7 +146,7 @@ static void R_ColorShiftLightingFloats(float in[4], float out[4], float scale )
 	float	r, g, b;
 
 #if defined(USE_OVERBRIGHT)
-	scale *= pow(2.0f, r_mapOverBrightBits->integer - tr.overbrightBits);
+	scale *= 1 << (r_mapOverBrightBits->integer - tr.overbrightBits);
 #endif
 
 	r = in[0] * scale;
@@ -3112,7 +3112,7 @@ void R_LoadLightGrid( lump_t *l ) {
 		if (hdrLightGrid)
 		{
 #if defined(USE_OVERBRIGHT)
-			float lightScale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits);
+			float lightScale = 1 << (r_mapOverBrightBits->integer - tr.overbrightBits);
 #else
 			float lightScale = 1.0f;
 #endif
@@ -3419,25 +3419,43 @@ void R_AssignCubemapsToWorldSurfaces(void)
 }
 
 
-void R_RenderAllCubemaps(void)
+void R_LoadCubemaps(void)
 {
-	int i, j;
+	int i;
+	imgFlags_t flags = IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_NOLIGHTSCALE | IMGFLAG_CUBEMAP;
 
 	for (i = 0; i < tr.numCubemaps; i++)
 	{
-		tr.cubemaps[i].image = R_CreateImage(va("*cubeMap%d", i), NULL, r_cubemapSize->integer, r_cubemapSize->integer, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, GL_RGBA8);
+		char filename[MAX_QPATH];
+		cubemap_t *cubemap = &tr.cubemaps[i];
+
+		Com_sprintf(filename, MAX_QPATH, "cubemaps/%s/%03d.dds", tr.world->baseName, i);
+
+		cubemap->image = R_FindImageFile(filename, IMGTYPE_COLORALPHA, flags);
 	}
+}
+
+
+void R_RenderMissingCubemaps(void)
+{
+	int i, j;
+	imgFlags_t flags = IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_NOLIGHTSCALE | IMGFLAG_CUBEMAP;
 	
 	ri.Printf(PRINT_ALL, "Total cubemaps: %d\n", tr.numCubemaps );
 
 	for (i = 0; i < tr.numCubemaps; i++)
 	{
-		for (j = 0; j < 6; j++)
+		if (!tr.cubemaps[i].image)
 		{
-			RE_ClearScene();
-			R_RenderCubemapSide(i, j, qfalse);
-			R_IssuePendingRenderCommands();
-			R_InitNextFrame();
+			tr.cubemaps[i].image = R_CreateImage(va("*cubeMap%d", i), NULL, r_cubemapSize->integer, r_cubemapSize->integer, IMGTYPE_COLORALPHA, flags, GL_RGBA8);
+
+			for (j = 0; j < 6; j++)
+			{
+				RE_ClearScene();
+				R_RenderCubemapSide(i, j, qfalse);
+				R_IssuePendingRenderCommands();
+				R_InitNextFrame();
+			}
 		}
 	}
 }
@@ -3812,10 +3830,11 @@ void RE_LoadWorldMap( const char *name ) {
 	// make sure the VAO glState entry is safe
 	R_BindNullVao();
 
-	// Render all cubemaps
+	// Render or load all cubemaps
 	if (r_cubeMapping->integer && tr.numCubemaps)
 	{
-		R_RenderAllCubemaps();
+		R_LoadCubemaps();
+		R_RenderMissingCubemaps();
 	}
 
 	ri.FS_FreeFile( buffer.v );
diff --git a/MP/code/rend2/tr_dsa.c b/MP/code/rend2/tr_dsa.c
new file mode 100644
index 0000000..a766263
--- /dev/null
+++ b/MP/code/rend2/tr_dsa.c
@@ -0,0 +1,287 @@
+/*
+===========================================================================
+Copyright (C) 2016 James Canete
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+#include "tr_dsa.h"
+
+static struct
+{
+	GLuint textures[NUM_TEXTURE_BUNDLES];
+	GLenum texunit;
+
+	GLuint program;
+
+	GLuint drawFramebuffer;
+	GLuint readFramebuffer;
+	GLuint renderbuffer;
+}
+glDsaState;
+
+void GL_BindNullTextures()
+{
+	int i;
+
+	if (glRefConfig.directStateAccess)
+	{
+		for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
+		{
+			qglBindMultiTexture(GL_TEXTURE0_ARB + i, GL_TEXTURE_2D, 0);
+			glDsaState.textures[i] = 0;
+		}
+	}
+	else
+	{
+		for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
+		{
+			qglActiveTextureARB(GL_TEXTURE0_ARB + i);
+			qglBindTexture(GL_TEXTURE_2D, 0);
+			glDsaState.textures[i] = 0;
+		}
+
+		qglActiveTextureARB(GL_TEXTURE0_ARB);
+		glDsaState.texunit = GL_TEXTURE0_ARB;
+	}
+}
+
+int GL_BindMultiTexture(GLenum texunit, GLenum target, GLuint texture)
+{
+	GLuint tmu = texunit - GL_TEXTURE0_ARB;
+
+	if (glDsaState.textures[tmu] == texture)
+		return 0;
+
+	if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
+		target = GL_TEXTURE_CUBE_MAP;
+
+	qglBindMultiTexture(texunit, target, texture);
+	glDsaState.textures[tmu] = texture;
+	return 1;
+}
+
+GLvoid APIENTRY GLDSA_BindMultiTexture(GLenum texunit, GLenum target, GLuint texture)
+{
+	if (glDsaState.texunit != texunit)
+	{
+		qglActiveTextureARB(texunit);
+		glDsaState.texunit = texunit;
+	}
+
+	qglBindTexture(target, texture);
+}
+
+GLvoid APIENTRY GLDSA_TextureParameterf(GLuint texture, GLenum target, GLenum pname, GLfloat param)
+{
+	GL_BindMultiTexture(glDsaState.texunit, target, texture);
+	qglTexParameterf(target, pname, param);
+}
+
+GLvoid APIENTRY GLDSA_TextureParameteri(GLuint texture, GLenum target, GLenum pname, GLint param)
+{
+	GL_BindMultiTexture(glDsaState.texunit, target, texture);
+	qglTexParameteri(target, pname, param);
+}
+
+GLvoid APIENTRY GLDSA_TextureImage2D(GLuint texture, GLenum target, GLint level, GLint internalformat,
+	GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
+{
+	GL_BindMultiTexture(glDsaState.texunit, target, texture);
+	qglTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
+}
+
+GLvoid APIENTRY GLDSA_TextureSubImage2D(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset,
+	GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
+{
+	GL_BindMultiTexture(glDsaState.texunit, target, texture);
+	qglTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
+
+GLvoid APIENTRY GLDSA_CopyTextureImage2D(GLuint texture, GLenum target, GLint level, GLenum internalformat,
+	GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+{
+	GL_BindMultiTexture(glDsaState.texunit, target, texture);
+	qglCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
+}
+
+GLvoid APIENTRY  GLDSA_CompressedTextureImage2D(GLuint texture, GLenum target, GLint level, GLenum internalformat,
+	GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data)
+{
+	GL_BindMultiTexture(glDsaState.texunit, target, texture);
+	qglCompressedTexImage2DARB(target, level, internalformat, width, height, border, imageSize, data);
+}
+
+GLvoid APIENTRY GLDSA_CompressedTextureSubImage2D(GLuint texture, GLenum target, GLint level,
+	GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
+	GLsizei imageSize, const GLvoid *data)
+{
+	GL_BindMultiTexture(glDsaState.texunit, target, texture);
+	qglCompressedTexSubImage2DARB(target, level, xoffset, yoffset, width, height, format, imageSize, data);
+}
+
+GLvoid APIENTRY GLDSA_GenerateTextureMipmap(GLuint texture, GLenum target)
+{
+	GL_BindMultiTexture(glDsaState.texunit, target, texture);
+	qglGenerateMipmapEXT(target);
+}
+
+void GL_BindNullProgram()
+{
+	qglUseProgramObjectARB(0);
+	glDsaState.program = 0;
+}
+
+int GL_UseProgramObject(GLuint program)
+{
+	if (glDsaState.program == program)
+		return 0;
+
+	qglUseProgramObjectARB(program);
+	glDsaState.program = program;
+	return 1;
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform1i(GLuint program, GLint location, GLint v0)
+{
+	GL_UseProgramObject(program);
+	qglUniform1iARB(location, v0);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform1f(GLuint program, GLint location, GLfloat v0)
+{
+	GL_UseProgramObject(program);
+	qglUniform1fARB(location, v0);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform2f(GLuint program, GLint location,
+	GLfloat v0, GLfloat v1)
+{
+	GL_UseProgramObject(program);
+	qglUniform2fARB(location, v0, v1);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform3f(GLuint program, GLint location,
+	GLfloat v0, GLfloat v1, GLfloat v2)
+{
+	GL_UseProgramObject(program);
+	qglUniform3fARB(location, v0, v1, v2);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform4f(GLuint program, GLint location,
+	GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
+{
+	GL_UseProgramObject(program);
+	qglUniform4fARB(location, v0, v1, v2, v3);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform1fv(GLuint program, GLint location,
+	GLsizei count, const GLfloat *value)
+{
+	GL_UseProgramObject(program);
+	qglUniform1fvARB(location, count, value);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniformMatrix4fv(GLuint program, GLint location,
+	GLsizei count, GLboolean transpose,
+	const GLfloat *value)
+{
+	GL_UseProgramObject(program);
+	qglUniformMatrix4fvARB(location, count, transpose, value);
+}
+
+void GL_BindNullFramebuffers()
+{
+	qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+	glDsaState.drawFramebuffer = glDsaState.readFramebuffer = 0;
+	qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
+	glDsaState.readFramebuffer = 0;
+}
+
+void GL_BindFramebuffer(GLenum target, GLuint framebuffer)
+{
+	switch (target)
+	{
+		case GL_FRAMEBUFFER_EXT:
+			if (framebuffer != glDsaState.drawFramebuffer || framebuffer != glDsaState.readFramebuffer)
+			{
+				qglBindFramebufferEXT(target, framebuffer);
+				glDsaState.drawFramebuffer = glDsaState.readFramebuffer = framebuffer;
+			}
+			break;
+
+		case GL_DRAW_FRAMEBUFFER_EXT:
+			if (framebuffer != glDsaState.drawFramebuffer)
+			{
+				qglBindFramebufferEXT(target, framebuffer);
+				glDsaState.drawFramebuffer = framebuffer;
+			}
+			break;
+
+		case GL_READ_FRAMEBUFFER_EXT:
+			if (framebuffer != glDsaState.readFramebuffer)
+			{
+				qglBindFramebufferEXT(target, framebuffer);
+				glDsaState.readFramebuffer = framebuffer;
+			}
+			break;
+	}
+}
+
+void GL_BindRenderbuffer(GLuint renderbuffer)
+{
+	if (renderbuffer != glDsaState.renderbuffer)
+	{
+		qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderbuffer);
+		glDsaState.renderbuffer = renderbuffer;
+	}
+}
+
+GLvoid APIENTRY GLDSA_NamedRenderbufferStorage(GLuint renderbuffer,
+	GLenum internalformat, GLsizei width, GLsizei height)
+{
+	GL_BindRenderbuffer(renderbuffer);
+	qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalformat, width, height);
+}
+
+GLvoid APIENTRY GLDSA_NamedRenderbufferStorageMultisample(GLuint renderbuffer,
+	GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+{
+	GL_BindRenderbuffer(renderbuffer);
+	qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, internalformat, width, height);
+}
+
+GLenum APIENTRY GLDSA_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target)
+{
+	GL_BindFramebuffer(target, framebuffer);
+	return qglCheckFramebufferStatusEXT(target);
+}
+
+GLvoid APIENTRY GLDSA_NamedFramebufferTexture2D(GLuint framebuffer,
+	GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+	GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, framebuffer);
+	qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, textarget, texture, level);
+}
+
+GLvoid APIENTRY GLDSA_NamedFramebufferRenderbuffer(GLuint framebuffer,
+	GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+	GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, framebuffer);
+	qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, renderbuffertarget, renderbuffer);
+}
diff --git a/MP/code/rend2/tr_dsa.h b/MP/code/rend2/tr_dsa.h
new file mode 100644
index 0000000..9d610ef
--- /dev/null
+++ b/MP/code/rend2/tr_dsa.h
@@ -0,0 +1,80 @@
+/*
+===========================================================================
+Copyright (C) 2016 James Canete
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+===========================================================================
+*/
+
+#ifndef __TR_DSA_H__
+#define __TR_DSA_H__
+
+#include "qgl.h"
+
+void GL_BindNullTextures(void);
+int GL_BindMultiTexture(GLenum texunit, GLenum target, GLuint texture);
+
+GLvoid APIENTRY GLDSA_BindMultiTexture(GLenum texunit, GLenum target, GLuint texture);
+GLvoid APIENTRY GLDSA_TextureParameterf(GLuint texture, GLenum target, GLenum pname, GLfloat param);
+GLvoid APIENTRY GLDSA_TextureParameteri(GLuint texture, GLenum target, GLenum pname, GLint param);
+GLvoid APIENTRY GLDSA_TextureImage2D(GLuint texture, GLenum target, GLint level, GLint internalformat,
+	GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+GLvoid APIENTRY GLDSA_TextureSubImage2D(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset,
+	GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+GLvoid APIENTRY GLDSA_CopyTextureImage2D(GLuint texture, GLenum target, GLint level, GLenum internalformat,
+	GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GLvoid APIENTRY GLDSA_CompressedTextureImage2D(GLuint texture, GLenum target, GLint level, GLenum internalformat,
+	GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+GLvoid APIENTRY GLDSA_CompressedTextureSubImage2D(GLuint texture, GLenum target, GLint level,
+	GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
+	GLsizei imageSize, const GLvoid *data);
+
+GLvoid APIENTRY GLDSA_GenerateTextureMipmap(GLuint texture, GLenum target);
+
+void GL_BindNullProgram(void);
+int GL_UseProgramObject(GLuint program);
+
+GLvoid APIENTRY GLDSA_ProgramUniform1i(GLuint program, GLint location, GLint v0);
+GLvoid APIENTRY GLDSA_ProgramUniform1f(GLuint program, GLint location, GLfloat v0);
+GLvoid APIENTRY GLDSA_ProgramUniform2f(GLuint program, GLint location,
+	GLfloat v0, GLfloat v1);
+GLvoid APIENTRY GLDSA_ProgramUniform3f(GLuint program, GLint location,
+	GLfloat v0, GLfloat v1, GLfloat v2);
+GLvoid APIENTRY GLDSA_ProgramUniform4f(GLuint program, GLint location,
+	GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+GLvoid APIENTRY GLDSA_ProgramUniform1fv(GLuint program, GLint location,
+	GLsizei count, const GLfloat *value);
+GLvoid APIENTRY GLDSA_ProgramUniformMatrix4fv(GLuint program, GLint location,
+	GLsizei count, GLboolean transpose,
+	const GLfloat *value);
+
+void GL_BindNullFramebuffers(void);
+void GL_BindFramebuffer(GLenum target, GLuint framebuffer);
+void GL_BindRenderbuffer(GLuint renderbuffer);
+
+GLvoid APIENTRY GLDSA_NamedRenderbufferStorage(GLuint renderbuffer,
+	GLenum internalformat, GLsizei width, GLsizei height);
+
+GLvoid APIENTRY GLDSA_NamedRenderbufferStorageMultisample(GLuint renderbuffer,
+	GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+
+GLenum APIENTRY GLDSA_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target);
+GLvoid APIENTRY GLDSA_NamedFramebufferTexture2D(GLuint framebuffer,
+	GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLvoid APIENTRY GLDSA_NamedFramebufferRenderbuffer(GLuint framebuffer,
+	GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+
+
+#endif
diff --git a/MP/code/rend2/tr_extensions.c b/MP/code/rend2/tr_extensions.c
index 8c2d9d0..7a4bacc 100644
--- a/MP/code/rend2/tr_extensions.c
+++ b/MP/code/rend2/tr_extensions.c
@@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #endif
 
 #include "tr_local.h"
+#include "tr_dsa.h"
 
 // GL_EXT_draw_range_elements
 void            (APIENTRY * qglDrawRangeElementsEXT) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
@@ -184,6 +185,50 @@ void (APIENTRY * qglDeleteVertexArraysARB)(GLsizei n, const GLuint *arrays);
 void (APIENTRY * qglGenVertexArraysARB)(GLsizei n, GLuint *arrays);
 GLboolean (APIENTRY * qglIsVertexArrayARB)(GLuint array);
 
+// GL_EXT_direct_state_access
+GLvoid (APIENTRY * qglBindMultiTexture)(GLenum texunit, GLenum target, GLuint texture);
+GLvoid (APIENTRY * qglTextureParameterf)(GLuint texture, GLenum target, GLenum pname, GLfloat param);
+GLvoid (APIENTRY * qglTextureParameteri)(GLuint texture, GLenum target, GLenum pname, GLint param);
+GLvoid (APIENTRY * qglTextureImage2D)(GLuint texture, GLenum target, GLint level, GLint internalformat,
+	GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+GLvoid (APIENTRY * qglTextureSubImage2D)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset,
+	GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+GLvoid (APIENTRY * qglCopyTextureImage2D)(GLuint texture, GLenum target, GLint level, GLenum internalformat,
+	GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GLvoid (APIENTRY * qglCompressedTextureImage2D)(GLuint texture, GLenum target, GLint level, GLenum internalformat,
+	GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+GLvoid (APIENTRY * qglCompressedTextureSubImage2D)(GLuint texture, GLenum target, GLint level,
+	GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
+	GLsizei imageSize, const GLvoid *data);
+GLvoid (APIENTRY * qglGenerateTextureMipmap)(GLuint texture, GLenum target);
+
+GLvoid(APIENTRY * qglProgramUniform1i)(GLuint program, GLint location, GLint v0);
+GLvoid(APIENTRY * qglProgramUniform1f)(GLuint program, GLint location, GLfloat v0);
+GLvoid(APIENTRY * qglProgramUniform2f)(GLuint program, GLint location,
+	GLfloat v0, GLfloat v1);
+GLvoid(APIENTRY * qglProgramUniform3f)(GLuint program, GLint location,
+	GLfloat v0, GLfloat v1, GLfloat v2);
+GLvoid(APIENTRY * qglProgramUniform4f)(GLuint program, GLint location,
+	GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+GLvoid(APIENTRY * qglProgramUniform1fv)(GLuint program, GLint location,
+	GLsizei count, const GLfloat *value);
+GLvoid(APIENTRY * qglProgramUniformMatrix4fv)(GLuint program, GLint location,
+	GLsizei count, GLboolean transpose,
+	const GLfloat *value);
+
+GLvoid(APIENTRY * qglNamedRenderbufferStorage)(GLuint renderbuffer,
+	GLenum internalformat, GLsizei width, GLsizei height);
+
+GLvoid(APIENTRY * qglNamedRenderbufferStorageMultisample)(GLuint renderbuffer,
+	GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+
+GLenum(APIENTRY * qglCheckNamedFramebufferStatus)(GLuint framebuffer, GLenum target);
+GLvoid(APIENTRY * qglNamedFramebufferTexture2D)(GLuint framebuffer,
+	GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GLvoid(APIENTRY * qglNamedFramebufferRenderbuffer)(GLuint framebuffer,
+	GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+
+
 static qboolean GLimp_HaveExtension(const char *ext)
 {
 	const char *ptr = Q_stristr( (char *)qglGetString(GL_EXTENSIONS), ext );
@@ -750,4 +795,68 @@ void GLimp_InitExtraExtensions()
 		ri.Printf(PRINT_ALL, result[2], extension);
 	}
 
+	// GL_EXT_direct_state_access
+	extension = "GL_EXT_direct_state_access";
+
+	qglBindMultiTexture = GLDSA_BindMultiTexture;
+	qglTextureParameterf = GLDSA_TextureParameterf;
+	qglTextureParameteri = GLDSA_TextureParameteri;
+	qglTextureImage2D = GLDSA_TextureImage2D;
+	qglTextureSubImage2D = GLDSA_TextureSubImage2D;
+	qglCopyTextureImage2D = GLDSA_CopyTextureImage2D;
+	qglCompressedTextureImage2D = GLDSA_CompressedTextureImage2D;
+	qglCompressedTextureSubImage2D = GLDSA_CompressedTextureSubImage2D;
+	qglGenerateTextureMipmap = GLDSA_GenerateTextureMipmap;
+
+	qglProgramUniform1i = GLDSA_ProgramUniform1i;
+	qglProgramUniform1f = GLDSA_ProgramUniform1f;
+	qglProgramUniform2f = GLDSA_ProgramUniform2f;
+	qglProgramUniform3f = GLDSA_ProgramUniform3f;
+	qglProgramUniform4f = GLDSA_ProgramUniform4f;
+	qglProgramUniform1fv = GLDSA_ProgramUniform1fv;
+	qglProgramUniformMatrix4fv = GLDSA_ProgramUniformMatrix4fv;
+
+	qglNamedRenderbufferStorage = GLDSA_NamedRenderbufferStorage;
+	qglNamedRenderbufferStorageMultisample = GLDSA_NamedRenderbufferStorageMultisample;
+	qglCheckNamedFramebufferStatus = GLDSA_CheckNamedFramebufferStatus;
+	qglNamedFramebufferTexture2D = GLDSA_NamedFramebufferTexture2D;
+	qglNamedFramebufferRenderbuffer = GLDSA_NamedFramebufferRenderbuffer;
+
+	glRefConfig.directStateAccess = qfalse;
+	if (GLimp_HaveExtension(extension))
+	{
+		if (r_ext_direct_state_access->integer)
+		{
+			glRefConfig.directStateAccess = qtrue;
+			qglBindMultiTexture = (void *)SDL_GL_GetProcAddress("glBindMultiTextureEXT");
+			qglTextureParameterf = (void *)SDL_GL_GetProcAddress("glTextureParameterfEXT");
+			qglTextureParameteri = (void *)SDL_GL_GetProcAddress("glTextureParameteriEXT");
+			qglTextureImage2D = (void *)SDL_GL_GetProcAddress("glTextureImage2DEXT");
+			qglTextureSubImage2D = (void *)SDL_GL_GetProcAddress("glTextureSubImage2DEXT");
+			qglCopyTextureImage2D = (void *)SDL_GL_GetProcAddress("glCopyTextureImage2DEXT");
+			qglCompressedTextureImage2D = (void *)SDL_GL_GetProcAddress("glCompressedTextureImage2DEXT");
+			qglCompressedTextureSubImage2D = (void *)SDL_GL_GetProcAddress("glCompressedTextureSubImage2DEXT");
+			qglGenerateTextureMipmap = (void *)SDL_GL_GetProcAddress("glGenerateTextureMipmapEXT");
+
+			qglProgramUniform1i = (void *)SDL_GL_GetProcAddress("glProgramUniform1iEXT");
+			qglProgramUniform1f = (void *)SDL_GL_GetProcAddress("glProgramUniform1fEXT");
+			qglProgramUniform2f = (void *)SDL_GL_GetProcAddress("glProgramUniform2fEXT");
+			qglProgramUniform3f = (void *)SDL_GL_GetProcAddress("glProgramUniform3fEXT");
+			qglProgramUniform4f = (void *)SDL_GL_GetProcAddress("glProgramUniform4fEXT");
+			qglProgramUniform1fv = (void *)SDL_GL_GetProcAddress("glProgramUniform1fvEXT");
+			qglProgramUniformMatrix4fv = (void *)SDL_GL_GetProcAddress("glProgramUniformMatrix4fvEXT");
+
+			qglNamedRenderbufferStorage = (void *)SDL_GL_GetProcAddress("glNamedRenderbufferStorageEXT");
+			qglNamedRenderbufferStorageMultisample = (void *)SDL_GL_GetProcAddress("glNamedRenderbufferStorageMultisampleEXT");
+			qglCheckNamedFramebufferStatus = (void *)SDL_GL_GetProcAddress("glCheckNamedFramebufferStatusEXT");
+			qglNamedFramebufferTexture2D = (void *)SDL_GL_GetProcAddress("glNamedFramebufferTexture2DEXT");
+			qglNamedFramebufferRenderbuffer = (void *)SDL_GL_GetProcAddress("glNamedFramebufferRenderbufferEXT");
+		}
+
+		ri.Printf(PRINT_ALL, result[glRefConfig.directStateAccess ? 1 : 0], extension);
+	}
+	else
+	{
+		ri.Printf(PRINT_ALL, result[2], extension);
+	}
 }
diff --git a/MP/code/rend2/tr_fbo.c b/MP/code/rend2/tr_fbo.c
index c8ea0ae..59b1703 100644
--- a/MP/code/rend2/tr_fbo.c
+++ b/MP/code/rend2/tr_fbo.c
@@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 // tr_fbo.c
 #include "tr_local.h"
 
+#include "tr_dsa.h"
+
 /*
 =============
 R_CheckFBO
@@ -30,19 +32,10 @@ R_CheckFBO
 */
 qboolean R_CheckFBO(const FBO_t * fbo)
 {
-	int             code;
-	int             id;
-
-	qglGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &id);
-	qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->frameBuffer);
-
-	code = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+	GLenum code = qglCheckNamedFramebufferStatus(fbo->frameBuffer, GL_FRAMEBUFFER_EXT);
 
 	if(code == GL_FRAMEBUFFER_COMPLETE_EXT)
-	{
-		qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
 		return qtrue;
-	}
 
 	// an error occured
 	switch (code)
@@ -83,13 +76,9 @@ qboolean R_CheckFBO(const FBO_t * fbo)
 
 		default:
 			ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) unknown error 0x%X\n", fbo->name, code);
-			//ri.Error(ERR_FATAL, "R_CheckFBO: (%s) unknown error 0x%X", fbo->name, code);
-			//assert(0);
 			break;
 	}
 
-	qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
-
 	return qfalse;
 }
 
@@ -133,6 +122,11 @@ FBO_t          *FBO_Create(const char *name, int width, int height)
 	return fbo;
 }
 
+/*
+=================
+FBO_CreateBuffer
+=================
+*/
 void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample)
 {
 	uint32_t *pRenderBuffer;
@@ -189,115 +183,45 @@ void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample)
 	if (absent)
 		qglGenRenderbuffersEXT(1, pRenderBuffer);
 
-	qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, *pRenderBuffer);
 	if (multisample && glRefConfig.framebufferMultisample)
-	{
-		qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, multisample, format, fbo->width, fbo->height);
-	}
+		qglNamedRenderbufferStorageMultisample(*pRenderBuffer, multisample, format, fbo->width, fbo->height);
 	else
-	{
-		qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format, fbo->width, fbo->height);
-	}
+		qglNamedRenderbufferStorage(*pRenderBuffer, format, fbo->width, fbo->height);
 
 	if(absent)
 	{
 		if (attachment == 0)
 		{
-			qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,   GL_RENDERBUFFER_EXT, *pRenderBuffer);
-			qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer);
+			qglNamedFramebufferRenderbuffer(fbo->frameBuffer, GL_DEPTH_ATTACHMENT_EXT,   GL_RENDERBUFFER_EXT, *pRenderBuffer);
+			qglNamedFramebufferRenderbuffer(fbo->frameBuffer, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer);
 		}
 		else
-			qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, GL_RENDERBUFFER_EXT, *pRenderBuffer);
-	}
-}
-
-
-/*
-=================
-R_AttachFBOTexture1D
-=================
-*/
-void R_AttachFBOTexture1D(int texId, int index)
-{
-	if(index < 0 || index >= glRefConfig.maxColorAttachments)
-	{
-		ri.Printf(PRINT_WARNING, "R_AttachFBOTexture1D: invalid attachment index %i\n", index);
-		return;
+		{
+			qglNamedFramebufferRenderbuffer(fbo->frameBuffer, attachment, GL_RENDERBUFFER_EXT, *pRenderBuffer);
+		}
 	}
-
-	qglFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_TEXTURE_1D, texId, 0);
 }
 
-/*
-=================
-R_AttachFBOTexture2D
-=================
-*/
-void R_AttachFBOTexture2D(int target, int texId, int index)
-{
-	if(target != GL_TEXTURE_2D && (target < GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB || target > GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB))
-	{
-		ri.Printf(PRINT_WARNING, "R_AttachFBOTexture2D: invalid target %i\n", target);
-		return;
-	}
-
-	if(index < 0 || index >= glRefConfig.maxColorAttachments)
-	{
-		ri.Printf(PRINT_WARNING, "R_AttachFBOTexture2D: invalid attachment index %i\n", index);
-		return;
-	}
-
-	qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, target, texId, 0);
-}
 
 /*
 =================
-R_AttachFBOTexture3D
+FBO_AttachImage
 =================
 */
-void R_AttachFBOTexture3D(int texId, int index, int zOffset)
+void FBO_AttachImage(FBO_t *fbo, image_t *image, GLenum attachment, GLuint cubemapside)
 {
-	if(index < 0 || index >= glRefConfig.maxColorAttachments)
-	{
-		ri.Printf(PRINT_WARNING, "R_AttachFBOTexture3D: invalid attachment index %i\n", index);
-		return;
-	}
+	GLenum target = GL_TEXTURE_2D;
+	int index;
 
-	qglFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_TEXTURE_3D_EXT, texId, 0, zOffset);
-}
+	if (image->flags & IMGFLAG_CUBEMAP)
+		target = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + cubemapside;
 
-/*
-=================
-R_AttachFBOTextureDepth
-=================
-*/
-void R_AttachFBOTextureDepth(int texId)
-{
-	qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0);
+	qglNamedFramebufferTexture2D(fbo->frameBuffer, attachment, target, image->texnum, 0);
+	index = attachment - GL_COLOR_ATTACHMENT0_EXT;
+	if (index >= 0 && index <= 15)
+		fbo->colorImage[index] = image;
 }
 
-/*
-=================
-R_AttachFBOTexturePackedDepthStencil
-=================
-*/
-void R_AttachFBOTexturePackedDepthStencil(int texId)
-{
-	qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0);
-	qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0);
-}
-
-void FBO_AttachTextureImage(image_t *img, int index)
-{
-	if (!glState.currentFBO)
-	{
-		ri.Printf(PRINT_WARNING, "FBO: attempted to attach a texture image with no FBO bound!\n");
-		return;
-	}
-
-	R_AttachFBOTexture2D(GL_TEXTURE_2D, img->texnum, index);
-	glState.currentFBO->colorImage[index] = img;
-}
 
 /*
 ============
@@ -312,38 +236,10 @@ void FBO_Bind(FBO_t * fbo)
 	if (r_logFile->integer)
 	{
 		// don't just call LogComment, or we will get a call to va() every frame!
-		if (fbo)
-			GLimp_LogComment(va("--- FBO_Bind( %s ) ---\n", fbo->name));
-		else
-			GLimp_LogComment("--- FBO_Bind ( NULL ) ---\n");
-	}
-
-	if (!fbo)
-	{
-		qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-		//qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
-		glState.currentFBO = NULL;
-		
-		return;
+		GLimp_LogComment(va("--- FBO_Bind( %s ) ---\n", fbo ? fbo->name : "NULL"));
 	}
-		
-	qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->frameBuffer);
-
-	/*
-	   if(fbo->colorBuffers[0])
-	   {
-	   qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->colorBuffers[0]);
-	   }
-	 */
-
-	/*
-	   if(fbo->depthBuffer)
-	   {
-	   qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->depthBuffer);
-	   qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depthBuffer);
-	   }
-	 */
 
+	GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, fbo ? fbo->frameBuffer : 0);
 	glState.currentFBO = fbo;
 }
 
@@ -355,7 +251,6 @@ FBO_Init
 void FBO_Init(void)
 {
 	int             i;
-	// int             width, height, hdrFormat, multisample;
 	int             hdrFormat, multisample;
 
 	ri.Printf(PRINT_ALL, "------- FBO_Init -------\n");
@@ -369,73 +264,40 @@ void FBO_Init(void)
 
 	R_IssuePendingRenderCommands();
 
-/*	if(glRefConfig.textureNonPowerOfTwo)
-	{
-		width = glConfig.vidWidth;
-		height = glConfig.vidHeight;
-	}
-	else
-	{
-		width = NextPowerOfTwo(glConfig.vidWidth);
-		height = NextPowerOfTwo(glConfig.vidHeight);
-	} */
-
 	hdrFormat = GL_RGBA8;
 	if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat)
-	{
 		hdrFormat = GL_RGBA16F_ARB;
-	}
 
 	qglGetIntegerv(GL_MAX_SAMPLES_EXT, &multisample);
 
 	if (r_ext_framebuffer_multisample->integer < multisample)
-	{
 		multisample = r_ext_framebuffer_multisample->integer;
-	}
 
 	if (multisample < 2 || !glRefConfig.framebufferBlit)
 		multisample = 0;
 
 	if (multisample != r_ext_framebuffer_multisample->integer)
-	{
 		ri.Cvar_SetValue("r_ext_framebuffer_multisample", (float)multisample);
-	}
 	
 	// only create a render FBO if we need to resolve MSAA or do HDR
 	// otherwise just render straight to the screen (tr.renderFbo = NULL)
 	if (multisample && glRefConfig.framebufferMultisample)
 	{
 		tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
-		FBO_Bind(tr.renderFbo);
-
 		FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, multisample);
 		FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, multisample);
-
 		R_CheckFBO(tr.renderFbo);
 
-
 		tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height);
-		FBO_Bind(tr.msaaResolveFbo);
-
-		//FBO_CreateBuffer(tr.msaaResolveFbo, hdrFormat, 0, 0);
-		FBO_AttachTextureImage(tr.renderImage, 0);
-
-		//FBO_CreateBuffer(tr.msaaResolveFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
-		R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
-
+		FBO_AttachImage(tr.msaaResolveFbo, tr.renderImage, GL_COLOR_ATTACHMENT0_EXT, 0);
+		FBO_AttachImage(tr.msaaResolveFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT_EXT, 0);
 		R_CheckFBO(tr.msaaResolveFbo);
 	}
 	else if (r_hdr->integer)
 	{
 		tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
-		FBO_Bind(tr.renderFbo);
-
-		//FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, 0);
-		FBO_AttachTextureImage(tr.renderImage, 0);
-
-		//FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
-		R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
-
+		FBO_AttachImage(tr.renderFbo, tr.renderImage, GL_COLOR_ATTACHMENT0_EXT, 0);
+		FBO_AttachImage(tr.renderFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT_EXT, 0);
 		R_CheckFBO(tr.renderFbo);
 	}
 
@@ -443,20 +305,15 @@ void FBO_Init(void)
 	// this fixes the corrupt screen bug with r_hdr 1 on older hardware
 	if (tr.renderFbo)
 	{
-		FBO_Bind(tr.renderFbo);
+		GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, tr.renderFbo->frameBuffer);
 		qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
-		FBO_Bind(NULL);
 	}
 
 	if (r_drawSunRays->integer)
 	{
 		tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height);
-		FBO_Bind(tr.sunRaysFbo);
-
-		FBO_AttachTextureImage(tr.sunRaysImage, 0);
-
-		R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
-
+		FBO_AttachImage(tr.sunRaysFbo, tr.sunRaysImage, GL_COLOR_ATTACHMENT0_EXT, 0);
+		FBO_AttachImage(tr.sunRaysFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT_EXT, 0);
 		R_CheckFBO(tr.sunRaysFbo);
 	}
 
@@ -466,14 +323,8 @@ void FBO_Init(void)
 		for( i = 0; i < MAX_DRAWN_PSHADOWS; i++)
 		{
 			tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height);
-			FBO_Bind(tr.pshadowFbos[i]);
-
-			//FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0);
-			FBO_AttachTextureImage(tr.pshadowMaps[i], 0);
-
+			FBO_AttachImage(tr.pshadowFbos[i], tr.pshadowMaps[i], GL_COLOR_ATTACHMENT0_EXT, 0);
 			FBO_CreateBuffer(tr.pshadowFbos[i], GL_DEPTH_COMPONENT24_ARB, 0, 0);
-			//R_AttachFBOTextureDepth(tr.textureDepthImage->texnum);
-
 			R_CheckFBO(tr.pshadowFbos[i]);
 		}
 	}
@@ -483,104 +334,64 @@ void FBO_Init(void)
 		for ( i = 0; i < 4; i++)
 		{
 			tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height);
-			FBO_Bind(tr.sunShadowFbo[i]);
-
-			//FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0);
-			//FBO_AttachTextureImage(tr.sunShadowImage, 0);
-			qglDrawBuffer(GL_NONE);
-			qglReadBuffer(GL_NONE);
-
-			//FBO_CreateBuffer(tr.sunShadowFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
-			R_AttachFBOTextureDepth(tr.sunShadowDepthImage[i]->texnum);
-
+			FBO_AttachImage(tr.sunShadowFbo[i], tr.sunShadowDepthImage[i], GL_DEPTH_ATTACHMENT_EXT, 0);
 			R_CheckFBO(tr.sunShadowFbo[i]);
-
 		}
 
 		tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height);
-		FBO_Bind(tr.screenShadowFbo);
-
-		FBO_AttachTextureImage(tr.screenShadowImage, 0);
-
+		FBO_AttachImage(tr.screenShadowFbo, tr.screenShadowImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.screenShadowFbo);
 	}
 
 	for (i = 0; i < 2; i++)
 	{
 		tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height);
-		FBO_Bind(tr.textureScratchFbo[i]);
-
-		//FBO_CreateBuffer(tr.textureScratchFbo[i], GL_RGBA8, 0, 0);
-		FBO_AttachTextureImage(tr.textureScratchImage[i], 0);
-
+		FBO_AttachImage(tr.textureScratchFbo[i], tr.textureScratchImage[i], GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.textureScratchFbo[i]);
 	}
 
 	{
 		tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height);
-		FBO_Bind(tr.calcLevelsFbo);
-
-		//FBO_CreateBuffer(tr.calcLevelsFbo, hdrFormat, 0, 0);
-		FBO_AttachTextureImage(tr.calcLevelsImage, 0);
-
+		FBO_AttachImage(tr.calcLevelsFbo, tr.calcLevelsImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.calcLevelsFbo);
 	}
 
 	{
 		tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height);
-		FBO_Bind(tr.targetLevelsFbo);
-
-		//FBO_CreateBuffer(tr.targetLevelsFbo, hdrFormat, 0, 0);
-		FBO_AttachTextureImage(tr.targetLevelsImage, 0);
-
+		FBO_AttachImage(tr.targetLevelsFbo, tr.targetLevelsImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.targetLevelsFbo);
 	}
 
 	for (i = 0; i < 2; i++)
 	{
 		tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height);
-		FBO_Bind(tr.quarterFbo[i]);
-
-		//FBO_CreateBuffer(tr.quarterFbo[i], hdrFormat, 0, 0);
-		FBO_AttachTextureImage(tr.quarterImage[i], 0);
-
+		FBO_AttachImage(tr.quarterFbo[i], tr.quarterImage[i], GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.quarterFbo[i]);
 	}
 
 	if (r_ssao->integer)
 	{
 		tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height);
-		FBO_Bind(tr.hdrDepthFbo);
-
-		FBO_AttachTextureImage(tr.hdrDepthImage, 0);
-
+		FBO_AttachImage(tr.hdrDepthFbo, tr.hdrDepthImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.hdrDepthFbo);
 
 		tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height);
-		FBO_Bind(tr.screenSsaoFbo);
-		
-		FBO_AttachTextureImage(tr.screenSsaoImage, 0);
-
+		FBO_AttachImage(tr.screenSsaoFbo, tr.screenSsaoImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		R_CheckFBO(tr.screenSsaoFbo);
 	}
 
 	if (tr.renderCubeImage)
 	{
 		tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height);
-		FBO_Bind(tr.renderCubeFbo);
-		
-		//FBO_AttachTextureImage(tr.renderCubeImage, 0);
-		R_AttachFBOTexture2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, tr.renderCubeImage->texnum, 0);
-		glState.currentFBO->colorImage[0] = tr.renderCubeImage;
-
+		FBO_AttachImage(tr.renderCubeFbo, tr.renderCubeImage, GL_COLOR_ATTACHMENT0_EXT, 0);
 		FBO_CreateBuffer(tr.renderCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
-
 		R_CheckFBO(tr.renderCubeFbo);
 	}
 
 	GL_CheckErrors();
 
-	FBO_Bind(NULL);
+	GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
+	glState.currentFBO = NULL;
 }
 
 /*
@@ -663,7 +474,10 @@ void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexS
 	int width, height;
 
 	if (!src)
+	{
+		ri.Printf(PRINT_WARNING, "Tried to blit from a NULL texture!\n");
 		return;
+	}
 
 	if (inSrcBox)
 	{
@@ -849,12 +663,12 @@ void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int bu
 		VectorSet4(dstBoxFinal, dstBox[0], dstBox[1], dstBox[0] + dstBox[2], dstBox[1] + dstBox[3]);
 	}
 
-	qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, srcFb);
-	qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dstFb);
+	GL_BindFramebuffer(GL_READ_FRAMEBUFFER_EXT, srcFb);
+	GL_BindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, dstFb);
 	qglBlitFramebufferEXT(srcBoxFinal[0], srcBoxFinal[1], srcBoxFinal[2], srcBoxFinal[3],
 	                      dstBoxFinal[0], dstBoxFinal[1], dstBoxFinal[2], dstBoxFinal[3],
 						  buffers, filter);
 
-	qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+	GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
 	glState.currentFBO = NULL;
 }
diff --git a/MP/code/rend2/tr_fbo.h b/MP/code/rend2/tr_fbo.h
index b5ab18c..3f23a35 100644
--- a/MP/code/rend2/tr_fbo.h
+++ b/MP/code/rend2/tr_fbo.h
@@ -52,6 +52,7 @@ typedef struct FBO_s
 	int             height;
 } FBO_t;
 
+void FBO_AttachImage(FBO_t *fbo, image_t *image, GLenum attachment, GLuint cubemapside);
 void FBO_Bind(FBO_t *fbo);
 void FBO_Init(void);
 void FBO_Shutdown(void);
diff --git a/MP/code/rend2/tr_glsl.c b/MP/code/rend2/tr_glsl.c
index ce83a62..9cfa025 100644
--- a/MP/code/rend2/tr_glsl.c
+++ b/MP/code/rend2/tr_glsl.c
@@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 // tr_glsl.c
 #include "tr_local.h"
 
-void GLSL_BindNullProgram(void);
+#include "tr_dsa.h"
 
 extern const char *fallbackShader_bokeh_vp;
 extern const char *fallbackShader_bokeh_fp;
@@ -328,17 +328,8 @@ static void GLSL_GetShaderHeader( GLenum shaderType, const GLcharARB *extra, cha
 	Q_strcat(dest, size,
 			 va("#ifndef r_FBufScale\n#define r_FBufScale vec2(%f, %f)\n#endif\n", fbufWidthScale, fbufHeightScale));
 
-	if (r_materialGamma->value != 1.0f)
-		Q_strcat(dest, size, va("#ifndef r_materialGamma\n#define r_materialGamma %f\n#endif\n", r_materialGamma->value));
-
-	if (r_lightGamma->value != 1.0f)
-		Q_strcat(dest, size, va("#ifndef r_lightGamma\n#define r_lightGamma %f\n#endif\n", r_lightGamma->value));
-
-	if (r_framebufferGamma->value != 1.0f)
-		Q_strcat(dest, size, va("#ifndef r_framebufferGamma\n#define r_framebufferGamma %f\n#endif\n", r_framebufferGamma->value));
-
-	if (r_tonemapGamma->value != 1.0f)
-		Q_strcat(dest, size, va("#ifndef r_tonemapGamma\n#define r_tonemapGamma %f\n#endif\n", r_tonemapGamma->value));
+	if (r_pbr->integer)
+		Q_strcat(dest, size, "#define USE_PBR\n");
 
 	if (extra)
 	{
@@ -488,11 +479,6 @@ static void GLSL_ShowProgramUniforms(GLhandleARB program)
 	GLenum			type;
 	char            uniformName[1000];
 
-	// install the executables in the program object as part of current state.
-	qglUseProgramObjectARB(program);
-
-	// check for GL Errors
-
 	// query the number of active uniforms
 	qglGetObjectParameterivARB(program, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &count);
 
@@ -503,8 +489,6 @@ static void GLSL_ShowProgramUniforms(GLhandleARB program)
 
 		ri.Printf(PRINT_DEVELOPER, "active uniform: '%s'\n", uniformName);
 	}
-
-	qglUseProgramObjectARB(0);
 }
 
 static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int attribs, const char *vpCode, const char *fpCode)
@@ -709,7 +693,7 @@ void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value)
 
 	*compare = value;
 
-	qglUniform1iARB(uniforms[uniformNum], value);
+	qglProgramUniform1i(program->program, uniforms[uniformNum], value);
 }
 
 void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value)
@@ -733,7 +717,7 @@ void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat valu
 
 	*compare = value;
 	
-	qglUniform1fARB(uniforms[uniformNum], value);
+	qglProgramUniform1f(program->program, uniforms[uniformNum], value);
 }
 
 void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t v)
@@ -758,7 +742,7 @@ void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t
 	compare[0] = v[0];
 	compare[1] = v[1];
 
-	qglUniform2fARB(uniforms[uniformNum], v[0], v[1]);
+	qglProgramUniform2f(program->program, uniforms[uniformNum], v[0], v[1]);
 }
 
 void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t v)
@@ -782,7 +766,7 @@ void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t
 
 	VectorCopy(v, compare);
 
-	qglUniform3fARB(uniforms[uniformNum], v[0], v[1], v[2]);
+	qglProgramUniform3f(program->program, uniforms[uniformNum], v[0], v[1], v[2]);
 }
 
 void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t v)
@@ -806,7 +790,7 @@ void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t
 
 	VectorCopy4(v, compare);
 
-	qglUniform4fARB(uniforms[uniformNum], v[0], v[1], v[2], v[3]);
+	qglProgramUniform4f(program->program, uniforms[uniformNum], v[0], v[1], v[2], v[3]);
 }
 
 void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_t v)
@@ -830,7 +814,7 @@ void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_
 
 	VectorCopy5(v, compare);
 
-	qglUniform1fvARB(uniforms[uniformNum], 5, v);
+	qglProgramUniform1fv(program->program, uniforms[uniformNum], 5, v);
 }
 
 void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t matrix)
@@ -854,7 +838,7 @@ void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t
 
 	Mat4Copy(matrix, compare);
 
-	qglUniformMatrix4fvARB(uniforms[uniformNum], 1, GL_FALSE, matrix);
+	qglProgramUniformMatrix4fv(program->program, uniforms[uniformNum], 1, GL_FALSE, matrix);
 }
 
 void GLSL_DeleteGPUShader(shaderProgram_t *program)
@@ -937,10 +921,8 @@ void GLSL_InitGPUShaders(void)
 
 		GLSL_InitUniforms(&tr.genericShader[i]);
 
-		qglUseProgramObjectARB(tr.genericShader[i].program);
 		GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP);
 		GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_LIGHTMAP,   TB_LIGHTMAP);
-		qglUseProgramObjectARB(0);
 
 		GLSL_FinishGPUShader(&tr.genericShader[i]);
 
@@ -957,9 +939,7 @@ void GLSL_InitGPUShaders(void)
 	
 	GLSL_InitUniforms(&tr.textureColorShader);
 
-	qglUseProgramObjectARB(tr.textureColorShader.program);
 	GLSL_SetUniformInt(&tr.textureColorShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
-	qglUseProgramObjectARB(0);
 
 	GLSL_FinishGPUShader(&tr.textureColorShader);
 
@@ -1011,9 +991,7 @@ void GLSL_InitGPUShaders(void)
 
 		GLSL_InitUniforms(&tr.dlightShader[i]);
 		
-		qglUseProgramObjectARB(tr.dlightShader[i].program);
 		GLSL_SetUniformInt(&tr.dlightShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP);
-		qglUseProgramObjectARB(0);
 
 		GLSL_FinishGPUShader(&tr.dlightShader[i]);
 
@@ -1040,12 +1018,6 @@ void GLSL_InitGPUShaders(void)
 
 		extradefines[0] = '\0';
 
-		if (r_specularIsMetallic->value)
-			Q_strcat(extradefines, 1024, "#define SPECULAR_IS_METALLIC\n");
-
-		if (r_glossIsRoughness->value)
-			Q_strcat(extradefines, 1024, "#define GLOSS_IS_ROUGHNESS\n");
-
 		if (r_dlightMode->integer >= 2)
 			Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n");
 
@@ -1141,7 +1113,6 @@ void GLSL_InitGPUShaders(void)
 
 		GLSL_InitUniforms(&tr.lightallShader[i]);
 
-		qglUseProgramObjectARB(tr.lightallShader[i].program);
 		GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_DIFFUSEMAP,  TB_DIFFUSEMAP);
 		GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_LIGHTMAP,    TB_LIGHTMAP);
 		GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_NORMALMAP,   TB_NORMALMAP);
@@ -1149,7 +1120,6 @@ void GLSL_InitGPUShaders(void)
 		GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SPECULARMAP, TB_SPECULARMAP);
 		GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SHADOWMAP,   TB_SHADOWMAP);
 		GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_CUBEMAP,     TB_CUBEMAP);
-		qglUseProgramObjectARB(0);
 
 		GLSL_FinishGPUShader(&tr.lightallShader[i]);
 
@@ -1182,9 +1152,7 @@ void GLSL_InitGPUShaders(void)
 	
 	GLSL_InitUniforms(&tr.pshadowShader);
 
-	qglUseProgramObjectARB(tr.pshadowShader.program);
 	GLSL_SetUniformInt(&tr.pshadowShader, UNIFORM_SHADOWMAP, TB_DIFFUSEMAP);
-	qglUseProgramObjectARB(0);
 
 	GLSL_FinishGPUShader(&tr.pshadowShader);
 
@@ -1201,9 +1169,7 @@ void GLSL_InitGPUShaders(void)
 	
 	GLSL_InitUniforms(&tr.down4xShader);
 
-	qglUseProgramObjectARB(tr.down4xShader.program);
 	GLSL_SetUniformInt(&tr.down4xShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
-	qglUseProgramObjectARB(0);
 
 	GLSL_FinishGPUShader(&tr.down4xShader);
 
@@ -1220,9 +1186,7 @@ void GLSL_InitGPUShaders(void)
 
 	GLSL_InitUniforms(&tr.bokehShader);
 
-	qglUseProgramObjectARB(tr.bokehShader.program);
 	GLSL_SetUniformInt(&tr.bokehShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
-	qglUseProgramObjectARB(0);
 
 	GLSL_FinishGPUShader(&tr.bokehShader);
 
@@ -1239,10 +1203,8 @@ void GLSL_InitGPUShaders(void)
 
 	GLSL_InitUniforms(&tr.tonemapShader);
 
-	qglUseProgramObjectARB(tr.tonemapShader.program);
 	GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_TEXTUREMAP, TB_COLORMAP);
 	GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_LEVELSMAP,  TB_LEVELSMAP);
-	qglUseProgramObjectARB(0);
 
 	GLSL_FinishGPUShader(&tr.tonemapShader);
 
@@ -1264,9 +1226,7 @@ void GLSL_InitGPUShaders(void)
 
 		GLSL_InitUniforms(&tr.calclevels4xShader[i]);
 
-		qglUseProgramObjectARB(tr.calclevels4xShader[i].program);
 		GLSL_SetUniformInt(&tr.calclevels4xShader[i], UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
-		qglUseProgramObjectARB(0);
 
 		GLSL_FinishGPUShader(&tr.calclevels4xShader[i]);
 
@@ -1297,13 +1257,11 @@ void GLSL_InitGPUShaders(void)
 	
 	GLSL_InitUniforms(&tr.shadowmaskShader);
 
-	qglUseProgramObjectARB(tr.shadowmaskShader.program);
 	GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP);
 	GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP,  TB_SHADOWMAP);
 	GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP2, TB_SHADOWMAP2);
 	GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP3, TB_SHADOWMAP3);
 	GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP4, TB_SHADOWMAP4);
-	qglUseProgramObjectARB(0);
 
 	GLSL_FinishGPUShader(&tr.shadowmaskShader);
 
@@ -1320,9 +1278,7 @@ void GLSL_InitGPUShaders(void)
 
 	GLSL_InitUniforms(&tr.ssaoShader);
 
-	qglUseProgramObjectARB(tr.ssaoShader.program);
 	GLSL_SetUniformInt(&tr.ssaoShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP);
-	qglUseProgramObjectARB(0);
 
 	GLSL_FinishGPUShader(&tr.ssaoShader);
 
@@ -1347,10 +1303,8 @@ void GLSL_InitGPUShaders(void)
 		
 		GLSL_InitUniforms(&tr.depthBlurShader[i]);
 
-		qglUseProgramObjectARB(tr.depthBlurShader[i].program);
 		GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENIMAGEMAP, TB_COLORMAP);
 		GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENDEPTHMAP, TB_LIGHTMAP);
-		qglUseProgramObjectARB(0);
 
 		GLSL_FinishGPUShader(&tr.depthBlurShader[i]);
 
@@ -1368,9 +1322,7 @@ void GLSL_InitGPUShaders(void)
 
 	GLSL_InitUniforms(&tr.testcubeShader);
 
-	qglUseProgramObjectARB(tr.testcubeShader.program);
 	GLSL_SetUniformInt(&tr.testcubeShader, UNIFORM_TEXTUREMAP, TB_COLORMAP);
-	qglUseProgramObjectARB(0);
 
 	GLSL_FinishGPUShader(&tr.testcubeShader);
 
@@ -1394,7 +1346,7 @@ void GLSL_ShutdownGPUShaders(void)
 	for (i = 0; i < ATTR_INDEX_COUNT; i++)
 		qglDisableVertexAttribArrayARB(i);
 
-	GLSL_BindNullProgram();
+	GL_BindNullProgram();
 
 	for ( i = 0; i < GENERICDEF_COUNT; i++)
 		GLSL_DeleteGPUShader(&tr.genericShader[i]);
@@ -1424,49 +1376,25 @@ void GLSL_ShutdownGPUShaders(void)
 
 	for ( i = 0; i < 2; i++)
 		GLSL_DeleteGPUShader(&tr.depthBlurShader[i]);
-
-	glState.currentProgram = 0;
-	qglUseProgramObjectARB(0);
 }
 
 
 void GLSL_BindProgram(shaderProgram_t * program)
 {
-	if(!program)
-	{
-		GLSL_BindNullProgram();
-		return;
-	}
+	GLuint programObject = program ? program->program : 0;
+	char *name = program ? program->name : "NULL";
 
 	if(r_logFile->integer)
 	{
 		// don't just call LogComment, or we will get a call to va() every frame!
-		GLimp_LogComment(va("--- GL_BindProgram( %s ) ---\n", program->name));
+		GLimp_LogComment(va("--- GLSL_BindProgram( %s ) ---\n", name));
 	}
 
-	if(glState.currentProgram != program)
-	{
-		qglUseProgramObjectARB(program->program);
-		glState.currentProgram = program;
+	if (GL_UseProgramObject(programObject))
 		backEnd.pc.c_glslShaderBinds++;
-	}
 }
 
 
-void GLSL_BindNullProgram(void)
-{
-	if(r_logFile->integer)
-	{
-		GLimp_LogComment("--- GL_BindNullProgram ---\n");
-	}
-
-	if(glState.currentProgram)
-	{
-		qglUseProgramObjectARB(0);
-		glState.currentProgram = NULL;
-	}
-}
-
 
 shaderProgram_t *GLSL_GetGenericShaderProgram(int stage, glfog_t *glFog)
 {
diff --git a/MP/code/rend2/tr_image.c b/MP/code/rend2/tr_image.c
index 0b01a25..65cde8e 100644
--- a/MP/code/rend2/tr_image.c
+++ b/MP/code/rend2/tr_image.c
@@ -35,6 +35,7 @@ If you have questions concerning this license or the applicable additional terms
 
 #include "tr_local.h"
 
+#include "tr_dsa.h"
 
 static byte s_intensitytable[256];
 static unsigned char s_gammatable[256];
@@ -132,9 +133,8 @@ void GL_TextureMode( const char *string ) {
 	for ( i = 0 ; i < tr.numImages ; i++ ) {
 		glt = tr.images[ i ];
 		if ( glt->flags & IMGFLAG_MIPMAP ) {
-			GL_Bind( glt );
-			qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min );
-			qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max );
+			qglTextureParameterf(glt->texnum, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+			qglTextureParameterf(glt->texnum, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
 		}
 	}
 }
@@ -1979,7 +1979,7 @@ static void CompressMonoBlock(byte outdata[8], const byte indata[16])
 	}
 }
 
-static void RawImage_UploadToRgtc2Texture(byte *data, int width, int height, int mip)
+static void RawImage_UploadToRgtc2Texture(GLuint texture, byte *data, int width, int height, int mip)
 {
 	int wBlocks, hBlocks, y, x, size;
 	byte *compressedData, *p;
@@ -2019,86 +2019,61 @@ static void RawImage_UploadToRgtc2Texture(byte *data, int width, int height, int
 		}
 	}
 
-	qglCompressedTexImage2DARB(GL_TEXTURE_2D, mip, GL_COMPRESSED_RG_RGTC2, width, height, 0, size, compressedData);
+	qglCompressedTextureImage2D(texture, GL_TEXTURE_2D, mip, GL_COMPRESSED_RG_RGTC2, width, height, 0, size, compressedData);
 
 	ri.Hunk_FreeTempMemory(compressedData);
 }
 
-static void RawImage_UploadTexture( byte *data, int x, int y, int width, int height, GLenum picFormat, int numMips, GLenum internalFormat, imgType_t type, imgFlags_t flags, qboolean subtexture )
+static int CalculateMipSize(int width, int height, GLenum picFormat)
 {
-	int dataFormat, dataType;
-	qboolean rgtc = (internalFormat == GL_COMPRESSED_RG_RGTC2);
+	int numBlocks = ((width + 3) / 4) * ((height + 3) / 4);
+	int numPixels = width * height;
 
-	if (data && picFormat != GL_RGBA8 && picFormat != GL_SRGB8_ALPHA8_EXT)
+	switch (picFormat)
 	{
-		int bytesPer4x4Block = 0;
-		int miplevel = 0;
-
-		switch (picFormat)
-		{
-			case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-			case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
-			case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-			case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
-			case GL_COMPRESSED_RED_RGTC1:
-			case GL_COMPRESSED_SIGNED_RED_RGTC1:
-				bytesPer4x4Block = 8;
-				break;
-			case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
-			case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
-			case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
-			case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
-			case GL_COMPRESSED_RG_RGTC2:
-			case GL_COMPRESSED_SIGNED_RG_RGTC2:
-			case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB:
-			case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB:
-			case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB:
-			case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB:
-				bytesPer4x4Block = 16;
-				break;
-			default:
-				ri.Printf(PRINT_ALL, "Unsupported texture format %08x\n", picFormat);
-				return;
-				break;
-		}
-
-		if (flags & IMGFLAG_PICMIP)
-		{
-			for (miplevel = r_picmip->integer; miplevel > 0 && numMips > 1; miplevel--, numMips--)
-			{
-				int size = ((width + 3) / 4) * ((height + 3) / 4) * bytesPer4x4Block;
-
-				x >>= 1;
-				y >>= 1;
-				width = MAX(1, width >> 1);
-				height = MAX(1, height >> 1);
-				data += size;
-			}
-		}
+		case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+		case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+		case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+		case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+		case GL_COMPRESSED_RED_RGTC1:
+		case GL_COMPRESSED_SIGNED_RED_RGTC1:
+			return numBlocks * 8;
 
-		if (!(flags & IMGFLAG_MIPMAP))
-			numMips = 1;
+		case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+		case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
+		case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+		case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
+		case GL_COMPRESSED_RG_RGTC2:
+		case GL_COMPRESSED_SIGNED_RG_RGTC2:
+		case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB:
+		case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB:
+		case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB:
+		case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB:
+			return numBlocks * 16;
 
-		for (miplevel = 0; miplevel < numMips; miplevel++)
-		{
-			int size = ((width + 3) / 4) * ((height + 3) / 4) * bytesPer4x4Block;
+		case GL_RGBA8:
+		case GL_SRGB8_ALPHA8_EXT:
+			return numPixels * 4;
 
-			if (subtexture)
-				qglCompressedTexSubImage2DARB(GL_TEXTURE_2D, miplevel, x, y, width, height, internalFormat, size, data);
-			else
-				qglCompressedTexImage2DARB(GL_TEXTURE_2D, miplevel, internalFormat, width, height, 0, size, data);
+		default:
+			ri.Printf(PRINT_ALL, "Unsupported texture format %08x\n", picFormat);
+			return 0;
+	}
 
-			x >>= 1;
-			y >>= 1;
-			width  = MAX(1, width >> 1);
-			height = MAX(1, height >> 1);
-			data += size;
-		}
+	return 0;
+}
 
-		return;
-	}
+static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int width, int height, GLenum target, GLenum picFormat, int numMips, GLenum internalFormat, imgType_t type, imgFlags_t flags, qboolean subtexture )
+{
+	int dataFormat, dataType;
+	qboolean rgtc = (internalFormat == GL_COMPRESSED_RG_RGTC2);
+	qboolean compressed = (!(picFormat == GL_RGBA8) || (picFormat == GL_SRGB8_ALPHA8_EXT));
+	qboolean mipmap = !!(flags & IMGFLAG_MIPMAP);
+	qboolean picmip = !!(flags & IMGFLAG_PICMIP);
+	int size, miplevel;
+	qboolean lastMip = qfalse;
 
-	switch(internalFormat)
+	switch (internalFormat)
 	{
 		case GL_DEPTH_COMPONENT:
 		case GL_DEPTH_COMPONENT16_ARB:
@@ -2117,52 +2092,83 @@ static void RawImage_UploadTexture( byte *data, int x, int y, int width, int hei
 			break;
 	}
 
-	if ( subtexture )
-		qglTexSubImage2D( GL_TEXTURE_2D, 0, x, y, width, height, dataFormat, dataType, data );
-	else
+	if (!data)
 	{
-		if (rgtc)
-			RawImage_UploadToRgtc2Texture(data, width, height, 0);
-		else
-			qglTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, dataFormat, dataType, data);
+		miplevel = 0;
+		do
+		{
+			lastMip = (width == 1 && height == 1) || !mipmap;
+			qglTextureImage2D(texture, target, miplevel, internalFormat, width, height, 0, dataFormat, dataType, NULL);
+
+			width = MAX(1, width >> 1);
+			height = MAX(1, height >> 1);
+			miplevel++;
+		}
+		while (!lastMip);
+
+		return;
 	}
 
-	if (flags & IMGFLAG_MIPMAP)
+	if (compressed && picmip)
 	{
-		int miplevel = 0;
-
-		while (width > 1 || height > 1)
+		for (miplevel = r_picmip->integer; miplevel > 0 && numMips > 1; miplevel--, numMips--)
 		{
-			if (data)
-			{
-				if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)
-					R_MipMapNormalHeight( data, data, width, height, glRefConfig.swizzleNormalmap );
-				else
-					R_MipMapsRGB( data, width, height );
-			}
-			
+			size = CalculateMipSize(width, height, picFormat);
+			x >>= 1;
+			y >>= 1;
 			width = MAX(1, width >> 1);
 			height = MAX(1, height >> 1);
-			miplevel++;
+			data += size;
+		}
+	}
 
-			if ( data && r_colorMipLevels->integer )
-				R_BlendOverTexture( (byte *)data, width * height, mipBlendColors[miplevel] );
+	miplevel = 0;
+	do
+	{
+		lastMip = (width == 1 && height == 1) || !mipmap;
+		size = CalculateMipSize(width, height, picFormat);
 
-			if ( subtexture )
-			{
-				x >>= 1;
-				y >>= 1;
-				qglTexSubImage2D( GL_TEXTURE_2D, miplevel, x, y, width, height, dataFormat, dataType, data );
-			}
+		if (compressed)
+		{
+			if (subtexture)
+				qglCompressedTextureSubImage2D(texture, target, miplevel, x, y, width, height, picFormat, size, data);
 			else
+				qglCompressedTextureImage2D(texture, target, miplevel, picFormat, width, height, 0, size, data);
+		}
+		else
+		{
+			if (miplevel != 0 && r_colorMipLevels->integer)
+				R_BlendOverTexture((byte *)data, width * height, mipBlendColors[miplevel]);
+
+			if (rgtc)
+				RawImage_UploadToRgtc2Texture(texture, data, width, height, miplevel);
+			else if (subtexture)
+				qglTextureSubImage2D(texture, target, miplevel, x, y, width, height, dataFormat, dataType, data);
+			else
+				qglTextureImage2D(texture, target, miplevel, internalFormat, width, height, 0, dataFormat, dataType, data);
+
+			if (!lastMip && numMips < 2)
 			{
-				if (rgtc)
-					RawImage_UploadToRgtc2Texture(data, width, height, miplevel);
+				if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)
+					R_MipMapNormalHeight(data, data, width, height, glRefConfig.swizzleNormalmap);
 				else
-					qglTexImage2D(GL_TEXTURE_2D, miplevel, internalFormat, width, height, 0, dataFormat, dataType, data);
+					R_MipMapsRGB(data, width, height);
 			}
 		}
+
+		x >>= 1;
+		y >>= 1;
+		width = MAX(1, width >> 1);
+		height = MAX(1, height >> 1);
+		miplevel++;
+
+		if (numMips > 1)
+		{
+			data += size;
+			numMips--;
+		}
 	}
+	while (!lastMip);
 }
 
 /*
@@ -2196,19 +2202,35 @@ static void Upload32(byte *data, int x, int y, int width, int height, GLenum pic
 	GLenum internalFormat = image->internalFormat;
 	qboolean subtexture = (x != 0) || (y != 0) || (width != image->width) || (height != image->height);
 	qboolean notScaled = qtrue;
-	qboolean mipmap = !!(flags & IMGFLAG_MIPMAP);
+	qboolean compressed = (picFormat != GL_RGBA8 && picFormat != GL_SRGB8_ALPHA8_EXT);
+	qboolean mipmap = !!(flags & IMGFLAG_MIPMAP) && (!compressed || numMips > 1);
+	qboolean cubemap = !!(flags & IMGFLAG_CUBEMAP);
+	GLenum uploadTarget = cubemap ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : GL_TEXTURE_2D;
+	GLenum textureTarget = cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
+	int depth = cubemap ? 6 : 1;
 
 	if (!data)
 	{
 		RawImage_ScaleToPower2(NULL, &width, &height, type, flags, NULL);
-		RawImage_UploadTexture(NULL, 0, 0, width, height, GL_RGBA8, 0, internalFormat, type, flags, qfalse);
+		for (i = 0; i < depth; i++)
+			RawImage_UploadTexture(image->texnum, NULL, 0, 0, width, height, uploadTarget + i, GL_RGBA8, 0, internalFormat, type, flags, qfalse);
 		goto done;
 	}
 	else if (!subtexture)
 	{
-		if (picFormat != GL_RGBA8 && picFormat != GL_SRGB8_ALPHA8_EXT)
+		if (compressed || cubemap)
 		{
-			RawImage_UploadTexture(data, 0, 0, width, height, picFormat, numMips, internalFormat, type, flags, qfalse);
+			for (i = 0; i < depth; i++)
+			{
+				int w2 = width, h2 = height;
+				RawImage_UploadTexture(image->texnum, data, 0, 0, width, height, uploadTarget + i, picFormat, numMips, internalFormat, type, flags, qfalse);
+				for (c = numMips; c; c--)
+				{
+					data += CalculateMipSize(w2, h2, picFormat);
+					w2 = MAX(1, w2 >> 1);
+					h2 = MAX(1, h2 >> 1);
+				}
+			}
 			goto done;
 		}
 		notScaled = RawImage_ScaleToPower2(&data, &width, &height, type, flags, &resampledBuffer);
@@ -2248,12 +2270,12 @@ static void Upload32(byte *data, int x, int y, int width, int height, GLenum pic
 	if (subtexture)
 	{
 		// FIXME: Incorrect if original texture was not a power of 2 texture or picmipped
-		RawImage_UploadTexture(data, x, y, width, height, GL_RGBA8, 0, internalFormat, type, flags, qtrue);
+		RawImage_UploadTexture(image->texnum, data, x, y, width, height, uploadTarget, GL_RGBA8, 0, internalFormat, type, flags, qtrue);
 		GL_CheckErrors();
 		return;
 	}
 
-	RawImage_UploadTexture(data, 0, 0, width, height, GL_RGBA8, 0, internalFormat, type, flags, qfalse);
+	RawImage_UploadTexture(image->texnum, data, 0, 0, width, height, uploadTarget, GL_RGBA8, 0, internalFormat, type, flags, qfalse);
 
 done:
 
@@ -2262,20 +2284,20 @@ done:
 
 	if (mipmap)
 	{
-		if ( textureFilterAnisotropic )
-			qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
-					(GLint)Com_Clamp( 1, maxAnisotropy, r_ext_max_anisotropy->integer ) );
+		if (textureFilterAnisotropic && !cubemap)
+			qglTextureParameteri(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT,
+			(GLint)Com_Clamp(1, maxAnisotropy, r_ext_max_anisotropy->integer));
 
-		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
-		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+		qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+		qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, gl_filter_max);
 	}
 	else
 	{
-		if ( textureFilterAnisotropic )
-			qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 );
+		if (textureFilterAnisotropic && !cubemap)
+			qglTextureParameteri(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
 
-		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
-		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+		qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 	}
 
 	// Fix for sampling depth buffer on old nVidia cards
@@ -2286,9 +2308,9 @@ done:
 		case GL_DEPTH_COMPONENT16_ARB:
 		case GL_DEPTH_COMPONENT24_ARB:
 		case GL_DEPTH_COMPONENT32_ARB:
-			qglTexParameterf(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE );
-			qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
-			qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+			qglTextureParameterf(image->texnum, textureTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
+			qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+			qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 			break;
 		default:
 			break;
@@ -2341,68 +2363,24 @@ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLe
 		glWrapClampMode = GL_REPEAT;
 
 	if (!internalFormat)
-	{
-		if (image->flags & IMGFLAG_CUBEMAP)
-			internalFormat = GL_RGBA8;
-		else
-			internalFormat = RawImage_GetFormat(pic, width * height, picFormat, isLightmap, image->type, image->flags);
-	}
+		internalFormat = RawImage_GetFormat(pic, width * height, picFormat, isLightmap, image->type, image->flags);
 
 	image->internalFormat = internalFormat;
 
-	// lightmaps are always allocated on TMU 1
-	if ( qglActiveTextureARB && isLightmap ) {
-		image->TMU = 1;
-	} else {
-		image->TMU = 0;
-	}
-
-	if ( qglActiveTextureARB ) {
-		GL_SelectTexture( image->TMU );
-	}
-
-	GL_Bind(image);
+	Upload32(pic, 0, 0, image->width, image->height, picFormat, numMips, image);
 
 	if (image->flags & IMGFLAG_CUBEMAP)
 	{
-		qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-		qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-		qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
-
-		qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-		if (image->flags & IMGFLAG_MIPMAP)
-		{
-			qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
-		}
-		else
-		{
-			qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-		}
-
-		qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic);
-		qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic);
-		qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic);
-		qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic);
-		qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic);
-		qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic);
-
-		if (image->flags & IMGFLAG_MIPMAP)
-			qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP);
-
-		image->uploadWidth = width;
-		image->uploadHeight = height;
+		qglTextureParameterf(image->texnum, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, glWrapClampMode);
+		qglTextureParameterf(image->texnum, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, glWrapClampMode);
+		qglTextureParameteri(image->texnum, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, glWrapClampMode);
 	}
 	else
 	{
-		Upload32( pic, 0, 0, image->width, image->height, picFormat, numMips, image );
-
-		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode );
-		qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode );
+		qglTextureParameterf(image->texnum, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode);
+		qglTextureParameterf(image->texnum, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode);
 	}
 
-	GL_SelectTexture( 0 );
-
 	hash = generateHashValue( name );
 	image->next = hashTable[hash];
 	hashTable[hash] = image;
@@ -2427,15 +2405,7 @@ image_t *R_CreateImage(const char *name, byte *pic, int width, int height, imgTy
 
 void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height )
 {
-	if (qglActiveTextureARB) {
-		GL_SelectTexture(image->TMU);
-	}
-
-	GL_Bind(image);
-
 	Upload32(pic, x, y, width, height, GL_RGBA8, 0, image);
-
-	GL_SelectTexture(0);
 }
 
 //===================================================================
@@ -2579,6 +2549,7 @@ image_t	*R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags )
 	GLenum  picFormat;
 	int picNumMips;
 	long hash;
+	imgFlags_t checkFlagsTrue, checkFlagsFalse;
 
 	if ( !name ) {
 		return NULL;
@@ -2609,7 +2580,10 @@ image_t	*R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags )
 		return NULL;
 	}
 
-	if (r_normalMapping->integer && (picFormat == GL_RGBA8) && !(type == IMGTYPE_NORMAL) && (flags & IMGFLAG_PICMIP) && (flags & IMGFLAG_MIPMAP) && (flags & IMGFLAG_GENNORMALMAP))
+	checkFlagsTrue = IMGFLAG_PICMIP | IMGFLAG_MIPMAP | IMGFLAG_GENNORMALMAP;
+	checkFlagsFalse = IMGFLAG_CUBEMAP;
+	if (r_normalMapping->integer && (picFormat == GL_RGBA8) && (type == IMGTYPE_COLORALPHA) &&
+		((flags & checkFlagsTrue) == checkFlagsTrue) && !(flags & checkFlagsFalse))
 	{
 		char normalName[MAX_QPATH];
 		image_t *normalImage;
@@ -2712,6 +2686,20 @@ image_t	*R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags )
 		}
 	}
 
+	// force mipmaps off if image is compressed but doesn't have enough mips
+	if ((flags & IMGFLAG_MIPMAP) && picFormat != GL_RGBA8 && picFormat != GL_SRGB8_ALPHA8_EXT)
+	{
+		int wh = MAX(width, height);
+		int neededMips = 0;
+		while (wh)
+		{
+			neededMips++;
+			wh >>= 1;
+		}
+		if (neededMips > picNumMips)
+			flags &= ~IMGFLAG_MIPMAP;
+	}
+
 	image = R_CreateImage2( ( char * ) name, pic, width, height, picFormat, picNumMips, type, flags, 0 );
 	ri.Free( pic );
 	return image;
@@ -3002,11 +2990,10 @@ void R_CreateBuiltinImages( void ) {
 			for ( x = 0; x < 4; x++)
 			{
 				tr.sunShadowDepthImage[x] = R_CreateImage(va("*sunshadowdepth%i", x), NULL, r_shadowMapSize->integer, r_shadowMapSize->integer, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB);
-				GL_Bind(tr.sunShadowDepthImage[x]);
-				qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
-				qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
-				qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
-				qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+				qglTextureParameterf(tr.sunShadowDepthImage[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+				qglTextureParameterf(tr.sunShadowDepthImage[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+				qglTextureParameterf(tr.sunShadowDepthImage[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
+				qglTextureParameterf(tr.sunShadowDepthImage[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
 			}
 
 			tr.screenShadowImage = R_CreateImage("*screenShadow", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8);
@@ -3044,6 +3031,11 @@ void R_SetColorMappings( void ) {
 		tr.overbrightBits = 0;
 	}
 
+	// don't allow more overbright bits than map overbright bits
+	if ( tr.overbrightBits > r_mapOverBrightBits->integer ) {
+		tr.overbrightBits = r_mapOverBrightBits->integer;
+	}
+
 	tr.identityLight = 1.0f / ( 1 << tr.overbrightBits );
 	tr.identityLightByte = 255 * tr.identityLight;
 
@@ -3115,17 +3107,11 @@ void R_DeleteTextures( void ) {
 	for ( i = 0; i < tr.numImages ; i++ ) {
 		qglDeleteTextures( 1, &tr.images[i]->texnum );
 	}
-	memset( tr.images, 0, sizeof( tr.images ) );
+	Com_Memset( tr.images, 0, sizeof( tr.images ) );
 
-	memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) );
-	if ( qglActiveTextureARB ) {
-		GL_SelectTexture( 1 );
-		qglBindTexture( GL_TEXTURE_2D, 0 );
-		GL_SelectTexture( 0 );
-		qglBindTexture( GL_TEXTURE_2D, 0 );
-	} else {
-		qglBindTexture( GL_TEXTURE_2D, 0 );
-	}
+	tr.numImages = 0;
+
+	GL_BindNullTextures();
 }
 
 /*
diff --git a/MP/code/rend2/tr_init.c b/MP/code/rend2/tr_init.c
index 85ebd1b..1787326 100644
--- a/MP/code/rend2/tr_init.c
+++ b/MP/code/rend2/tr_init.c
@@ -30,6 +30,8 @@ If you have questions concerning this license or the applicable additional terms
 
 #include "tr_local.h"
 
+#include "tr_dsa.h"
+
 glconfig_t  glConfig;
 glRefConfig_t glRefConfig;
 qboolean    textureFilterAnisotropic = qfalse;
@@ -125,6 +127,7 @@ cvar_t  *r_ext_framebuffer_multisample;
 cvar_t  *r_arb_seamless_cube_map;
 cvar_t  *r_arb_vertex_type_2_10_10_10_rev;
 cvar_t  *r_arb_vertex_array_object;
+cvar_t  *r_ext_direct_state_access;
 
 cvar_t  *r_mergeMultidraws;
 cvar_t  *r_mergeLeafSurfaces;
@@ -148,11 +151,6 @@ cvar_t  *r_forceAutoExposure;
 cvar_t  *r_forceAutoExposureMin;
 cvar_t  *r_forceAutoExposureMax;
 
-cvar_t  *r_materialGamma;
-cvar_t  *r_lightGamma;
-cvar_t  *r_framebufferGamma;
-cvar_t  *r_tonemapGamma;
-
 cvar_t  *r_depthPrepass;
 cvar_t  *r_ssao;
 
@@ -162,8 +160,7 @@ cvar_t  *r_deluxeMapping;
 cvar_t  *r_parallaxMapping;
 cvar_t  *r_cubeMapping;
 cvar_t  *r_cubemapSize;
-cvar_t  *r_specularIsMetallic;
-cvar_t  *r_glossIsRoughness;
+cvar_t  *r_pbr;
 cvar_t  *r_baseNormalX;
 cvar_t  *r_baseNormalY;
 cvar_t  *r_baseParallax;
@@ -1025,19 +1022,11 @@ void GL_SetDefaultState( void ) {
 
 	qglColor4f( 1,1,1,1 );
 
-	// initialize downstream texture unit if we're running
-	// in a multitexture environment
-	if ( qglActiveTextureARB ) {
-		GL_SelectTexture( 1 );
-		GL_TextureMode( r_textureMode->string );
-		GL_TexEnv( GL_MODULATE );
-		qglDisable( GL_TEXTURE_2D );
-		GL_SelectTexture( 0 );
-	}
+	GL_BindNullTextures();
+	GL_BindNullFramebuffers();
 
 	qglEnable( GL_TEXTURE_2D );
 	GL_TextureMode( r_textureMode->string );
-	GL_TexEnv( GL_MODULATE );
 
 	//qglShadeModel( GL_SMOOTH );
 	qglDepthFunc( GL_LEQUAL );
@@ -1050,8 +1039,7 @@ void GL_SetDefaultState( void ) {
 	glState.faceCulling = CT_TWO_SIDED;
 	glState.faceCullFront = qtrue;
 
-	glState.currentProgram = 0;
-	qglUseProgramObjectARB(0);
+	GL_BindNullProgram();
 
 	if (glRefConfig.vertexArrayObject)
 		qglBindVertexArrayARB(0);
@@ -1290,6 +1278,7 @@ void R_Register( void ) {
 	r_arb_seamless_cube_map = ri.Cvar_Get( "r_arb_seamless_cube_map", "0", CVAR_ARCHIVE | CVAR_LATCH);
 	r_arb_vertex_type_2_10_10_10_rev = ri.Cvar_Get( "r_arb_vertex_type_2_10_10_10_rev", "1", CVAR_ARCHIVE | CVAR_LATCH);
 	r_arb_vertex_array_object = ri.Cvar_Get( "r_arb_vertex_array_object", "1", CVAR_ARCHIVE | CVAR_LATCH);
+	r_ext_direct_state_access = ri.Cvar_Get("r_ext_direct_state_access", "1", CVAR_ARCHIVE | CVAR_LATCH);
 
 	r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic", "0", CVAR_ARCHIVE | CVAR_LATCH );
 	r_ext_max_anisotropy = ri.Cvar_Get( "r_ext_max_anisotropy", "2", CVAR_ARCHIVE | CVAR_LATCH );
@@ -1328,7 +1317,7 @@ void R_Register( void ) {
 	r_floatLightmap = ri.Cvar_Get( "r_floatLightmap", "0", CVAR_ARCHIVE | CVAR_LATCH );
 	r_postProcess = ri.Cvar_Get( "r_postProcess", "1", CVAR_ARCHIVE );
 
-	r_toneMap = ri.Cvar_Get( "r_toneMap", "1", CVAR_ARCHIVE | CVAR_LATCH );
+	r_toneMap = ri.Cvar_Get( "r_toneMap", "1", CVAR_ARCHIVE );
 	r_forceToneMap = ri.Cvar_Get( "r_forceToneMap", "0", CVAR_CHEAT );
 	r_forceToneMapMin = ri.Cvar_Get( "r_forceToneMapMin", "-8.0", CVAR_CHEAT );
 	r_forceToneMapAvg = ri.Cvar_Get( "r_forceToneMapAvg", "-2.0", CVAR_CHEAT );
@@ -1341,11 +1330,6 @@ void R_Register( void ) {
 
 	r_cameraExposure = ri.Cvar_Get( "r_cameraExposure", "0", CVAR_CHEAT );
 
-	r_materialGamma = ri.Cvar_Get( "r_materialGamma", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
-	r_lightGamma = ri.Cvar_Get( "r_lightGamma", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
-	r_framebufferGamma = ri.Cvar_Get( "r_framebufferGamma", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
-	r_tonemapGamma = ri.Cvar_Get( "r_tonemapGamma", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
-
 	r_depthPrepass = ri.Cvar_Get( "r_depthPrepass", "1", CVAR_ARCHIVE );
 	r_ssao = ri.Cvar_Get( "r_ssao", "0", CVAR_LATCH | CVAR_ARCHIVE );
 
@@ -1355,8 +1339,7 @@ void R_Register( void ) {
 	r_parallaxMapping = ri.Cvar_Get( "r_parallaxMapping", "0", CVAR_ARCHIVE | CVAR_LATCH );
 	r_cubeMapping = ri.Cvar_Get( "r_cubeMapping", "0", CVAR_ARCHIVE | CVAR_LATCH );
 	r_cubemapSize = ri.Cvar_Get( "r_cubemapSize", "128", CVAR_ARCHIVE | CVAR_LATCH );
-	r_specularIsMetallic = ri.Cvar_Get( "r_specularIsMetallic", "0", CVAR_ARCHIVE | CVAR_LATCH );
-	r_glossIsRoughness = ri.Cvar_Get("r_glossIsRoughness", "0", CVAR_ARCHIVE | CVAR_LATCH);
+	r_pbr = ri.Cvar_Get("r_pbr", "0", CVAR_ARCHIVE | CVAR_LATCH);
 	r_baseNormalX = ri.Cvar_Get( "r_baseNormalX", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
 	r_baseNormalY = ri.Cvar_Get( "r_baseNormalY", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
 	r_baseParallax = ri.Cvar_Get( "r_baseParallax", "0.05", CVAR_ARCHIVE | CVAR_LATCH );
diff --git a/MP/code/rend2/tr_local.h b/MP/code/rend2/tr_local.h
index f5e7e0a..b5bae66 100644
--- a/MP/code/rend2/tr_local.h
+++ b/MP/code/rend2/tr_local.h
@@ -27,7 +27,6 @@ If you have questions concerning this license or the applicable additional terms
 */
 
 
-
 #ifndef TR_LOCAL_H
 #define TR_LOCAL_H
 
@@ -35,10 +34,6 @@ If you have questions concerning this license or the applicable additional terms
 #include "../qcommon/qfiles.h"
 #include "../qcommon/qcommon.h"
 #include "../renderer/tr_public.h"
-#include "tr_extratypes.h"
-#include "tr_extramath.h"
-#include "tr_fbo.h"
-#include "tr_postprocess.h"
 #include "qgl.h"
 #include "../renderer/iqm.h"
 
@@ -130,6 +125,11 @@ typedef struct image_s {
 	struct image_s* next;
 } image_t;
 
+#include "tr_extratypes.h"
+#include "tr_extramath.h"
+#include "tr_fbo.h"
+#include "tr_postprocess.h"
+
 // Ensure this is >= the ATTR_INDEX_COUNT enum below
 #define VAO_MAX_ATTRIBS 16
 
@@ -1483,8 +1483,6 @@ typedef struct {
 
 // the renderer front end should never modify glstate_t
 typedef struct {
-	int			currenttextures[NUM_TEXTURE_BUNDLES];
-	int currenttmu;
 	qboolean finishCalled;
 	int texEnv[2];
 	int faceCulling;
@@ -1494,7 +1492,6 @@ typedef struct {
 	float           vertexAttribsInterpolation;
 	qboolean        vertexAnimation;
 	uint32_t        vertexAttribsEnabled;  // global if no VAOs, tess only otherwise
-	shaderProgram_t *currentProgram;
 	FBO_t          *currentFBO;
 	vao_t          *currentVao;
 	mat4_t        modelview;
@@ -1552,6 +1549,7 @@ typedef struct {
 
 	qboolean floatLightmap;
 	qboolean vertexArrayObject;
+	qboolean directStateAccess;
 } glRefConfig_t;
 
 typedef struct {
@@ -1898,6 +1896,7 @@ extern  cvar_t  *r_ext_framebuffer_multisample;
 extern  cvar_t  *r_arb_seamless_cube_map;
 extern  cvar_t  *r_arb_vertex_type_2_10_10_10_rev;
 extern  cvar_t  *r_arb_vertex_array_object;
+extern  cvar_t  *r_ext_direct_state_access;
 
 //----(SA)	added
 extern cvar_t   *r_ext_NV_fog_dist;
@@ -1975,11 +1974,6 @@ extern  cvar_t  *r_forceAutoExposureMax;
 
 extern  cvar_t  *r_cameraExposure;
 
-extern  cvar_t  *r_materialGamma;
-extern  cvar_t  *r_lightGamma;
-extern  cvar_t  *r_framebufferGamma;
-extern  cvar_t  *r_tonemapGamma;
-
 extern  cvar_t  *r_depthPrepass;
 extern  cvar_t  *r_ssao;
 
@@ -1989,8 +1983,7 @@ extern  cvar_t  *r_deluxeMapping;
 extern  cvar_t  *r_parallaxMapping;
 extern  cvar_t  *r_cubeMapping;
 extern  cvar_t  *r_cubemapSize;
-extern  cvar_t  *r_specularIsMetallic;
-extern  cvar_t  *r_glossIsRoughness;
+extern  cvar_t  *r_pbr;
 extern  cvar_t  *r_baseNormalX;
 extern  cvar_t  *r_baseNormalY;
 extern  cvar_t  *r_baseParallax;
@@ -2095,17 +2088,14 @@ void R_RotateForEntity( const trRefEntity_t * ent, const viewParms_t * viewParms
 /*
 ** GL wrapper/helper functions
 */
-void    GL_Bind( image_t *image );
 void	GL_BindToTMU( image_t *image, int tmu );
 void    GL_SetDefaultState( void );
-void    GL_SelectTexture( int unit );
 void    GL_TextureMode( const char *string );
 void	GL_CheckErrs( char *file, int line );
 #define GL_CheckErrors(...) GL_CheckErrs(__FILE__, __LINE__)
 void    GL_State( unsigned long stateVector );
 void    GL_SetProjectionMatrix(mat4_t matrix);
 void    GL_SetModelviewMatrix(mat4_t matrix);
-void    GL_TexEnv( int env );
 void    GL_Cull( int cullType );
 
 #define GLS_SRCBLEND_ZERO                       0x00000001
@@ -2453,7 +2443,6 @@ void GLSL_InitGPUShaders(void);
 void GLSL_ShutdownGPUShaders(void);
 void GLSL_VertexAttribPointers(uint32_t attribBits);
 void GLSL_BindProgram(shaderProgram_t * program);
-void GLSL_BindNullProgram(void);
 
 void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value);
 void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value);
diff --git a/MP/code/rend2/tr_main.c b/MP/code/rend2/tr_main.c
index c5756f8..0ee2e5e 100644
--- a/MP/code/rend2/tr_main.c
+++ b/MP/code/rend2/tr_main.c
@@ -2299,7 +2299,7 @@ void R_DebugGraphics( void ) {
 
 	R_IssuePendingRenderCommands();
 
-	GL_Bind( tr.whiteImage );
+	GL_BindToTMU(tr.whiteImage, TB_COLORMAP);
 	GL_Cull( CT_FRONT_SIDED );
 	ri.CM_DrawDebugSurface( R_DebugPolygon );
 }
diff --git a/MP/code/rend2/tr_postprocess.c b/MP/code/rend2/tr_postprocess.c
index 35982fc..1952ae9 100644
--- a/MP/code/rend2/tr_postprocess.c
+++ b/MP/code/rend2/tr_postprocess.c
@@ -183,7 +183,7 @@ void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float
 					FBO_Blit(tr.textureScratchFbo[0], NULL, blurTexScale, tr.textureScratchFbo[1], NULL, &tr.bokehShader, color, 0);
 			}
 
-			FBO_Blit(tr.textureScratchFbo[1], NULL, NULL, dst, dstBox, &tr.textureColorShader, NULL, 0);
+			FBO_Blit(tr.textureScratchFbo[1], NULL, NULL, dst, dstBox, NULL, NULL, 0);
 		}
 #else // higher quality blur, but slower
 		else if (blur > 1.0f)
@@ -217,7 +217,7 @@ void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float
 				FBO_Blit(tr.quarterFbo[0], NULL, blurTexScale, tr.quarterFbo[1], NULL, &tr.bokehShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
 			}
 
-			FBO_Blit(tr.quarterFbo[1], NULL, NULL, dst, dstBox, &tr.textureColorShader, NULL, 0);
+			FBO_Blit(tr.quarterFbo[1], NULL, NULL, dst, dstBox, NULL, NULL, 0);
 		}
 #endif
 	}
@@ -232,49 +232,44 @@ static void RB_RadialBlur(FBO_t *srcFbo, FBO_t *dstFbo, int passes, float stretc
 	const float mul = powf(stretch, inc);
 	float scale;
 
-	{
-		vec2_t texScale;
+	alpha *= inc;
+	VectorSet4(color, alpha, alpha, alpha, 1.0f);
 
-		texScale[0] = 
-		texScale[1] = 1.0f;
+	if (srcFbo)
+		VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height);
+	else
+		VectorSet4(srcBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight);
 
-		alpha *= inc;
-		VectorSet4(color, alpha, alpha, alpha, 1.0f);
+	VectorSet4(dstBox, x, y, w, h);
+	FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, 0);
 
-		VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height);
-		VectorSet4(dstBox, x, y, w, h);
-		FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, 0);
+	--passes;
+	scale = mul;
+	while (passes > 0)
+	{
+		float iscale = 1.f / scale;
+		float s0 = xcenter * (1.f - iscale);
+		float t0 = (1.0f - ycenter) * (1.f - iscale);
 
-		--passes;
-		scale = mul;
-		while (passes > 0)
+		if (srcFbo)
 		{
-			float iscale = 1.f / scale;
-			float s0 = xcenter * (1.f - iscale);
-			float t0 = (1.0f - ycenter) * (1.f - iscale);
-			float s1 = iscale + s0;
-			float t1 = iscale + t0;
-
-			if (srcFbo)
-			{
-				srcBox[0] = s0 * srcFbo->width;
-				srcBox[1] = t0 * srcFbo->height;
-				srcBox[2] = (s1 - s0) * srcFbo->width;
-				srcBox[3] = (t1 - t0) * srcFbo->height;
-			}
-			else
-			{
-				srcBox[0] = s0 * glConfig.vidWidth;
-				srcBox[1] = t0 * glConfig.vidHeight;
-				srcBox[2] = (s1 - s0) * glConfig.vidWidth;
-				srcBox[3] = (t1 - t0) * glConfig.vidHeight;
-			}
+			srcBox[0] = s0 * srcFbo->width;
+			srcBox[1] = t0 * srcFbo->height;
+			srcBox[2] = iscale * srcFbo->width;
+			srcBox[3] = iscale * srcFbo->height;
+		}
+		else
+		{
+			srcBox[0] = s0 * glConfig.vidWidth;
+			srcBox[1] = t0 * glConfig.vidHeight;
+			srcBox[2] = iscale * glConfig.vidWidth;
+			srcBox[3] = iscale * glConfig.vidHeight;
+		}
 			
-			FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+		FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
 
-			scale *= mul;
-			--passes;
-		}
+		scale *= mul;
+		--passes;
 	}
 }
 
@@ -329,7 +324,7 @@ void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox)
 	// From RB_DrawSun()
 	{
 		float dist;
-		mat4_t trans, model, mvp;
+		mat4_t trans, model;
 
 		Mat4Translation( backEnd.viewParms.or.origin, trans );
 		Mat4Multiply( backEnd.viewParms.world.modelMatrix, trans, model );
@@ -353,12 +348,8 @@ void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox)
 	// initialize quarter buffers
 	{
 		float mul = 1.f;
-		vec2_t texScale;
 		ivec4_t rayBox, quarterBox;
 
-		texScale[0] = 
-		texScale[1] = 1.0f;
-
 		VectorSet4(color, mul, mul, mul, 1);
 
 		if (srcFbo)
@@ -408,14 +399,10 @@ void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox)
 	// add result back on top of the main buffer
 	{
 		float mul = 1.f;
-		vec2_t texScale;
-
-		texScale[0] = 
-		texScale[1] = 1.0f;
 
 		VectorSet4(color, mul, mul, mul, 1);
 
-		FBO_Blit(tr.quarterFbo[0], NULL, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
+		FBO_Blit(tr.quarterFbo[0], NULL, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
 	}
 }
 
@@ -443,31 +430,27 @@ static void RB_BlurAxis(FBO_t *srcFbo, FBO_t *dstFbo, float strength, qboolean h
 	{
 		ivec4_t srcBox, dstBox;
 		vec4_t color;
-		vec2_t texScale;
-
-		texScale[0] = 
-		texScale[1] = 1.0f;
 
 		VectorSet4(color, weights[0], weights[0], weights[0], 1.0f);
 		VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height);
 		VectorSet4(dstBox, 0, 0, dstFbo->width, dstFbo->height);
-		FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, 0 );
+		FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, 0);
 
 		VectorSet4(color, weights[1], weights[1], weights[1], 1.0f);
 		dx = offsets[1] * xmul;
 		dy = offsets[1] * ymul;
 		VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height);
-		FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+		FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
 		VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height);
-		FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+		FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
 
 		VectorSet4(color, weights[2], weights[2], weights[2], 1.0f);
 		dx = offsets[2] * xmul;
 		dy = offsets[2] * ymul;
 		VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height);
-		FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+		FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
 		VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height);
-		FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+		FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
 	}
 }
 
@@ -492,10 +475,6 @@ void RB_GaussianBlur(float blur)
 	{
 		ivec4_t srcBox, dstBox;
 		vec4_t color;
-		vec2_t texScale;
-
-		texScale[0] = 
-		texScale[1] = 1.0f;
 
 		VectorSet4(color, 1, 1, 1, 1);
 
@@ -507,7 +486,7 @@ void RB_GaussianBlur(float blur)
 		VectorSet4(srcBox, 0, 0, tr.whiteImage->width, tr.whiteImage->height);
 		VectorSet4(dstBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height);
 		qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
-		FBO_BlitFromTexture(tr.whiteImage, srcBox, texScale, tr.textureScratchFbo[0], dstBox, &tr.textureColorShader, color, GLS_DEPTHTEST_DISABLE);
+		FBO_BlitFromTexture(tr.whiteImage, srcBox, NULL, tr.textureScratchFbo[0], dstBox, NULL, color, GLS_DEPTHTEST_DISABLE);
 		qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
 
 		// blur the tiny buffer horizontally and vertically
@@ -518,6 +497,6 @@ void RB_GaussianBlur(float blur)
 		VectorSet4(srcBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height);
 		VectorSet4(dstBox, 0, 0, glConfig.vidWidth,              glConfig.vidHeight);
 		color[3] = factor;
-		FBO_Blit(tr.textureScratchFbo[0], srcBox, texScale, NULL, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
+		FBO_Blit(tr.textureScratchFbo[0], srcBox, NULL, NULL, dstBox, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
 	}
 }
diff --git a/MP/code/rend2/tr_scene.c b/MP/code/rend2/tr_scene.c
index eb0a372..07cb46c 100644
--- a/MP/code/rend2/tr_scene.c
+++ b/MP/code/rend2/tr_scene.c
@@ -452,7 +452,7 @@ void RE_BeginScene(const refdef_t *fd)
 	else
 	{
 #if defined(USE_OVERBRIGHT)
-		float scale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits - 8);
+		float scale = (1 << (r_mapOverBrightBits->integer - tr.overbrightBits)) / 255.0f;
 #else
 		float scale = (1 << r_mapOverBrightBits->integer) / 255.0f;
 #endif
diff --git a/MP/code/rend2/tr_shade.c b/MP/code/rend2/tr_shade.c
index 897501b..9d7c0e1 100644
--- a/MP/code/rend2/tr_shade.c
+++ b/MP/code/rend2/tr_shade.c
@@ -107,11 +107,9 @@ static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) {
 	int		index;
 
 	if ( bundle->isVideoMap ) {
-		int oldtmu = glState.currenttmu;
-		GL_SelectTexture(tmu);
 		ri.CIN_RunCinematic(bundle->videoMapHandle);
 		ri.CIN_UploadCinematic(bundle->videoMapHandle);
-		GL_SelectTexture(oldtmu);
+		GL_BindToTMU(tr.scratchImage[bundle->videoMapHandle], tmu);
 		return;
 	}
 
@@ -150,7 +148,7 @@ Draws triangle outlines for debugging
 ================
 */
 static void DrawTris (shaderCommands_t *input) {
-	GL_Bind( tr.whiteImage );
+	GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
 
 	GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
 	qglDepthRange( 0, 0 );
@@ -449,7 +447,7 @@ static void ProjectDlightTexture( void ) {
 		vector[3] = scale;
 		GLSL_SetUniformVec4(sp, UNIFORM_DLIGHTINFO, vector);
 	  
-		GL_Bind( tr.dlightImage );
+		GL_BindToTMU( tr.dlightImage, TB_COLORMAP );
 
 		// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
 		// where they aren't rendered
@@ -960,11 +958,7 @@ static void ForwardDlight( void ) {
 		}
 
 		if (r_dlightMode->integer >= 2)
-		{
-			GL_SelectTexture(TB_SHADOWMAP);
-			GL_Bind(tr.shadowCubemaps[l]);
-			GL_SelectTexture(0);
-		}
+			GL_BindToTMU(tr.shadowCubemaps[l], TB_SHADOWMAP);
 
 		ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb );
 		GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix);
@@ -1562,7 +1556,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
 		if ( backEnd.depthFill )
 		{
 			if (!(pStage->stateBits & GLS_ATEST_BITS))
-				GL_BindToTMU( tr.whiteImage, 0 );
+				GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
 			else if ( pStage->bundle[TB_COLORMAP].image[0] != 0 )
 				R_BindAnimatedImageToTMU( &pStage->bundle[TB_COLORMAP], TB_COLORMAP );
 		}
diff --git a/MP/code/rend2/tr_shader.c b/MP/code/rend2/tr_shader.c
index 060371e..d367e4d 100644
--- a/MP/code/rend2/tr_shader.c
+++ b/MP/code/rend2/tr_shader.c
@@ -912,9 +912,18 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) {
 				ri.Printf( PRINT_WARNING, "WARNING: missing parameter for specular reflectance in shader '%s'\n", shader.name );
 				continue;
 			}
-			stage->specularScale[0] = 
-			stage->specularScale[1] = 
-			stage->specularScale[2] = atof( token );
+
+			if (r_pbr->integer)
+			{
+				// interpret specularReflectance < 0.5 as nonmetal
+				stage->specularScale[1] = (atof(token) < 0.5f) ? 0.0f : 1.0f;
+			}
+			else
+			{
+				stage->specularScale[0] =
+				stage->specularScale[1] =
+				stage->specularScale[2] = atof( token );
+			}
 		}
 		//
 		// specularExponent <value>
@@ -932,8 +941,8 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) {
 
 			exponent = atof( token );
 
-			if (r_glossIsRoughness->integer)
-				stage->specularScale[3] = powf(2.0f / (exponent + 2.0), 0.25);
+			if (r_pbr->integer)
+				stage->specularScale[0] = 1.0f - powf(2.0f / (exponent + 2.0), 0.25);
 			else
 			{
 				// Change shininess to gloss
@@ -958,8 +967,8 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) {
 
 			gloss = atof(token);
 
-			if (r_glossIsRoughness->integer)
-				stage->specularScale[3] = exp2f(-3.0f * gloss);
+			if (r_pbr->integer)
+				stage->specularScale[0] = 1.0f - exp2f(-3.0f * gloss);
 			else
 				stage->specularScale[3] = gloss;
 		}
@@ -979,8 +988,8 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) {
 
 			roughness = atof(token);
 
-			if (r_glossIsRoughness->integer)
-				stage->specularScale[3] = roughness;
+			if (r_pbr->integer)
+				stage->specularScale[0] = 1.0 - roughness;
 			else
 			{
 				if (roughness >= 0.125)
@@ -1040,6 +1049,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) {
 		}
 		//
 		// specularScale <rgb> <gloss>
+		// or specularScale <metallic> <smoothness> with r_pbr 1
 		// or specularScale <r> <g> <b>
 		// or specularScale <r> <g> <b> <gloss>
 		//
@@ -1066,10 +1076,19 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) {
 			token = COM_ParseExt(text, qfalse);
 			if ( token[0] == 0 )
 			{
-				// two values, rgb then gloss
-				stage->specularScale[3] = stage->specularScale[1];
-				stage->specularScale[1] =
-				stage->specularScale[2] = stage->specularScale[0];
+				if (r_pbr->integer)
+				{
+					// two values, metallic then smoothness
+					float smoothness = stage->specularScale[1];
+					stage->specularScale[1] = (stage->specularScale[0] < 0.5f) ? 0.0f : 1.0f;
+					stage->specularScale[0] = smoothness;
+				}
+				{
+					// two values, rgb then gloss
+					stage->specularScale[3] = stage->specularScale[1];
+					stage->specularScale[1] =
+					stage->specularScale[2] = stage->specularScale[0];
+				}
 				continue;
 			}
 
@@ -2933,10 +2952,17 @@ static void InitShader( const char *name, int lightmapIndex ) {
 
 		// default normal/specular
 		VectorSet4(stages[i].normalScale, 0.0f, 0.0f, 0.0f, 0.0f);
-		stages[i].specularScale[0] =
-		stages[i].specularScale[1] =
-		stages[i].specularScale[2] = r_baseSpecular->value;
-		stages[i].specularScale[3] = r_baseGloss->value;
+		if (r_pbr->integer)
+		{
+			stages[i].specularScale[0] = r_baseGloss->value;
+		}
+		else
+		{
+			stages[i].specularScale[0] =
+			stages[i].specularScale[1] =
+			stages[i].specularScale[2] = r_baseSpecular->value;
+			stages[i].specularScale[3] = r_baseGloss->value;
+		}
 	}
 }
 
diff --git a/MP/code/rend2/tr_shadows.c b/MP/code/rend2/tr_shadows.c
index 6036ece..85e754e 100644
--- a/MP/code/rend2/tr_shadows.c
+++ b/MP/code/rend2/tr_shadows.c
@@ -213,7 +213,7 @@ void RB_ShadowTessEnd( void ) {
 
 	// draw the silhouette edges
 
-	GL_Bind( tr.whiteImage );
+	GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
 	GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
 	qglColor3f( 0.2f, 0.2f, 0.2f );
 
@@ -262,7 +262,7 @@ void RB_ShadowFinish( void ) {
 	qglDisable( GL_CLIP_PLANE0 );
 	GL_Cull( CT_TWO_SIDED );
 
-	GL_Bind( tr.whiteImage );
+	GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
 
 	qglLoadIdentity();
 
diff --git a/MP/code/rend2/tr_sky.c b/MP/code/rend2/tr_sky.c
index 37bc21d..34d2fff 100644
--- a/MP/code/rend2/tr_sky.c
+++ b/MP/code/rend2/tr_sky.c
@@ -388,7 +388,7 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max
 	//tess.numIndexes = 0;
 	tess.firstIndex = tess.numIndexes;
 	
-	GL_Bind( image );
+	GL_BindToTMU( image, TB_COLORMAP );
 	GL_Cull( CT_TWO_SIDED );
 
 	for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
@@ -505,7 +505,7 @@ static void DrawSkySideInner( struct image_s *image, const int mins[2], const in
 	//tess.numIndexes = 0;
 	tess.firstIndex = tess.numIndexes;
 	
-	GL_Bind( image );
+	GL_BindToTMU( image, TB_COLORMAP );
 	GL_Cull( CT_TWO_SIDED );
 
 	for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
diff --git a/MP/code/rend2/tr_surface.c b/MP/code/rend2/tr_surface.c
index df76ec9..4f2fd88 100644
--- a/MP/code/rend2/tr_surface.c
+++ b/MP/code/rend2/tr_surface.c
@@ -603,7 +603,7 @@ static void RB_SurfaceBeam( void ) {
 		VectorAdd( start_points[i], direction, end_points[i] );
 	}
 
-	GL_Bind( tr.whiteImage );
+	GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
 
 	GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
 
@@ -1772,7 +1772,7 @@ Draws x/y/z lines from the origin for orientation debugging
 */
 static void RB_SurfaceAxis( void ) {
 #if 0
-	GL_Bind( tr.whiteImage );
+	GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
 	GL_State( GLS_DEFAULT );
 	qglLineWidth( 3 );
 	qglBegin( GL_LINES );
diff --git a/MP/code/renderer/qgl.h b/MP/code/renderer/qgl.h
index f1164fb..2ae3d4e 100644
--- a/MP/code/renderer/qgl.h
+++ b/MP/code/renderer/qgl.h
@@ -815,12 +815,12 @@ extern void (APIENTRY * qglRenderbufferStorageMultisampleEXT)(GLenum target, GLs
 #define GL_FRAMEBUFFER_SRGB_EXT                         0x8DB9
 #endif
 
-#ifndef GL_EXT_texture_compression_latc
-#define GL_EXT_texture_compression_latc
-#define GL_COMPRESSED_LUMINANCE_LATC1_EXT                 0x8C70
-#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT          0x8C71
-#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT           0x8C72
-#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT    0x8C73
+#ifndef GL_ARB_texture_compression_rgtc
+#define GL_ARB_texture_compression_rgtc
+#define GL_COMPRESSED_RED_RGTC1                       0x8DBB
+#define GL_COMPRESSED_SIGNED_RED_RGTC1                0x8DBC
+#define GL_COMPRESSED_RG_RGTC2                        0x8DBD
+#define GL_COMPRESSED_SIGNED_RG_RGTC2                 0x8DBE
 #endif
 
 #ifndef GL_ARB_texture_compression_bptc
@@ -874,6 +874,50 @@ extern GLboolean (APIENTRY * qglIsVertexArrayARB)(GLuint array);
 #define GL_VERTEX_ARRAY_BINDING_ARB                0x85B5
 #endif
 
+// GL_EXT_direct_state_access
+extern GLvoid(APIENTRY * qglBindMultiTexture)(GLenum texunit, GLenum target, GLuint texture);
+extern GLvoid(APIENTRY * qglTextureParameterf)(GLuint texture, GLenum target, GLenum pname, GLfloat param);
+extern GLvoid(APIENTRY * qglTextureParameteri)(GLuint texture, GLenum target, GLenum pname, GLint param);
+extern GLvoid(APIENTRY * qglTextureImage2D)(GLuint texture, GLenum target, GLint level, GLint internalformat,
+	GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+extern GLvoid(APIENTRY * qglTextureSubImage2D)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset,
+	GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+extern GLvoid(APIENTRY * qglCopyTextureImage2D)(GLuint texture, GLenum target, GLint level, GLenum internalformat,
+	GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+extern GLvoid(APIENTRY * qglCompressedTextureImage2D)(GLuint texture, GLenum target, GLint level, GLenum internalformat,
+	GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+extern GLvoid(APIENTRY * qglCompressedTextureSubImage2D)(GLuint texture, GLenum target, GLint level,
+	GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
+	GLsizei imageSize, const GLvoid *data);
+extern GLvoid(APIENTRY * qglGenerateTextureMipmap)(GLuint texture, GLenum target);
+
+extern GLvoid(APIENTRY * qglProgramUniform1i)(GLuint program, GLint location, GLint v0);
+extern GLvoid(APIENTRY * qglProgramUniform1f)(GLuint program, GLint location, GLfloat v0);
+extern GLvoid(APIENTRY * qglProgramUniform2f)(GLuint program, GLint location,
+	GLfloat v0, GLfloat v1);
+extern GLvoid(APIENTRY * qglProgramUniform3f)(GLuint program, GLint location,
+	GLfloat v0, GLfloat v1, GLfloat v2);
+extern GLvoid(APIENTRY * qglProgramUniform4f)(GLuint program, GLint location,
+	GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+extern GLvoid(APIENTRY * qglProgramUniform1fv)(GLuint program, GLint location,
+	GLsizei count, const GLfloat *value);
+extern GLvoid(APIENTRY * qglProgramUniformMatrix4fv)(GLuint program, GLint location,
+	GLsizei count, GLboolean transpose,
+	const GLfloat *value);
+
+extern GLvoid(APIENTRY * qglNamedRenderbufferStorage)(GLuint renderbuffer,
+	GLenum internalformat, GLsizei width, GLsizei height);
+
+extern GLvoid(APIENTRY * qglNamedRenderbufferStorageMultisample)(GLuint renderbuffer,
+	GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+
+extern GLenum(APIENTRY * qglCheckNamedFramebufferStatus)(GLuint framebuffer, GLenum target);
+extern GLvoid(APIENTRY * qglNamedFramebufferTexture2D)(GLuint framebuffer,
+	GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+extern GLvoid(APIENTRY * qglNamedFramebufferRenderbuffer)(GLuint framebuffer,
+	GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+
+
 #if defined(WIN32)
 // WGL_ARB_create_context
 #ifndef WGL_ARB_create_context
diff --git a/MP/code/renderer/tr_image.c b/MP/code/renderer/tr_image.c
index 5c2e738..6b3ce45 100644
--- a/MP/code/renderer/tr_image.c
+++ b/MP/code/renderer/tr_image.c
@@ -1659,9 +1659,11 @@ void R_DeleteTextures( void ) {
 	for ( i = 0; i < tr.numImages ; i++ ) {
 		qglDeleteTextures( 1, &tr.images[i]->texnum );
 	}
-	memset( tr.images, 0, sizeof( tr.images ) );
+	Com_Memset( tr.images, 0, sizeof( tr.images ) );
 
-	memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) );
+	tr.numImages = 0;
+
+	Com_Memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) );
 	if ( qglActiveTextureARB ) {
 		GL_SelectTexture( 1 );
 		qglBindTexture( GL_TEXTURE_2D, 0 );
diff --git a/MP/code/renderer/tr_local.h b/MP/code/renderer/tr_local.h
index 0bcb1e0..c036572 100644
--- a/MP/code/renderer/tr_local.h
+++ b/MP/code/renderer/tr_local.h
@@ -27,7 +27,6 @@ If you have questions concerning this license or the applicable additional terms
 */
 
 
-
 #ifndef TR_LOCAL_H
 #define TR_LOCAL_H
 
diff --git a/MP/rend2-readme.txt b/MP/rend2-readme.txt
index 9504c42..0c096d8 100644
--- a/MP/rend2-readme.txt
+++ b/MP/rend2-readme.txt
@@ -219,6 +219,12 @@ Cvars for advanced material usage:
                                      0.05 - Standard depth. (default)
                                      0.1  - Looks broken.
 
+  r_pbr                          - Enable physically based rendering.
+                                   Experimental, will not look correct without
+                                   assets meant for it.
+                                     0 - No. (default)
+                                     1 - Yes.
+
 Cvars for image interpolation and generation:
   r_imageUpsample                - Use interpolation to artifically increase
                                    the resolution of all textures.  Looks good
@@ -337,21 +343,7 @@ Cvars that you probably don't care about or shouldn't mess with:
   r_shadowCascadeZBias           - Z-bias for shadow cascade frustums.
                                      -256 - Default.
 
-  r_materialGamma                - Gamma level for material textures.
-                                   (diffuse, specular)
-                                     1.0 - RTCW, fastest. (default)
-
-  r_lightGamma                   - Gamma level for light.
-                                   (lightmap, lightgrid, vertex lights)
-                                     1.0 - RTCW, fastest. (default)
 
-  r_framebufferGamma             - Gamma level for framebuffers.
-                                     1.0 - RTCW, fastest. (default)
-
-  r_tonemapGamma                 - Gamma applied after tonemapping.
-                                     1.0 - RTCW, fastest. (default)
-
-  
 Cvars that have broken bits:
   r_dlightMode                   - Change how dynamic lights look.
                                      0 - RTCW style dlights, fake

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/iortcw.git



More information about the Pkg-games-commits mailing list