[iortcw] 125/152: All: Rend2: Some tr_image refactoring/cleanup

Simon McVittie smcv at debian.org
Fri Sep 8 10:40:23 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 16c7a9981583b437c58204c2d1c9b15b84f8cfec
Author: MAN-AT-ARMS <M4N4T4RMS at gmail.com>
Date:   Sun Sep 25 06:03:23 2016 -0400

    All: Rend2: Some tr_image refactoring/cleanup
---
 MP/code/rend2/tr_image.c | 382 +++++++++++++++++++++++-----------------------
 SP/code/rend2/tr_image.c | 385 +++++++++++++++++++++++------------------------
 2 files changed, 375 insertions(+), 392 deletions(-)

diff --git a/MP/code/rend2/tr_image.c b/MP/code/rend2/tr_image.c
index 122e436..4e8b56f 100644
--- a/MP/code/rend2/tr_image.c
+++ b/MP/code/rend2/tr_image.c
@@ -1507,6 +1507,7 @@ static void R_MipMapNormalHeight (const byte *in, byte *out, int width, int heig
 R_RMSE
 ================
 */
+#if 0 // FIXME
 static float R_RMSE( byte *in, int width, int height ) {
 	int i, j;
 	float out, rmse, rtemp;
@@ -1546,6 +1547,7 @@ static float R_RMSE( byte *in, int width, int height ) {
 	rmse = sqrt( rmse / ( height * width * 4 ) );
 	return rmse;
 }
+#endif
 
 
 /*
@@ -1621,7 +1623,23 @@ static qboolean RawImage_ScaleToPower2( byte **data, int *inout_width, int *inou
 	qboolean picmip = flags & IMGFLAG_PICMIP;
 	qboolean mipmap = flags & IMGFLAG_MIPMAP;
 	qboolean clampToEdge = flags & IMGFLAG_CLAMPTOEDGE;
-	qboolean notScaled;
+	qboolean scaled;
+#if 0
+	static int rmse_saved = 0;
+
+	// do the root mean square error stuff first
+	if ( r_rmse->value ) {
+		while ( R_RMSE( *data, width, height ) < r_rmse->value ) {
+			rmse_saved += ( height * width * 4 ) - ( ( width >> 1 ) * ( height >> 1 ) * 4 );
+			*resampledBuffer = ri.Hunk_AllocateTempMemory( ( width >> 1 ) * ( height >> 1 ) * 4 );
+			ResampleTexture( *data, width, height, *resampledBuffer, width >> 1, height >> 1 );
+			*data = *resampledBuffer;
+			width = width >> 1;
+			height = height >> 1;
+			ri.Printf( PRINT_ALL, "r_rmse of %f has saved %dkb\n", r_rmse->value, ( rmse_saved / 1024 ) );
+		}
+	}
+#endif
 
 	//
 	// convert to exact power of 2 sizes
@@ -1688,7 +1706,6 @@ static qboolean RawImage_ScaleToPower2( byte **data, int *inout_width, int *inou
 		else if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)
 			FillInNormalizedZ(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height);
 
-
 		//endTime = ri.Milliseconds();
 
 		//ri.Printf(PRINT_ALL, "upsampled %dx%d to %dx%d in %dms\n", width, height, scaled_width, scaled_height, endTime - startTime);
@@ -1733,7 +1750,7 @@ static qboolean RawImage_ScaleToPower2( byte **data, int *inout_width, int *inou
 	scaled_width  = MAX(1, scaled_width);
 	scaled_height = MAX(1, scaled_height);
 
-	notScaled = (width == scaled_width) && (height == scaled_height);
+	scaled = (width != scaled_width) || (height != scaled_height);
 
 	//
 	// rescale texture to new size using existing mipmap functions
@@ -1755,7 +1772,7 @@ static qboolean RawImage_ScaleToPower2( byte **data, int *inout_width, int *inou
 	*inout_width  = width;
 	*inout_height = height;
 
-	return notScaled;
+	return scaled;
 }
 
 
@@ -1789,7 +1806,7 @@ static GLenum RawImage_GetFormat(const byte *data, int numPixels, GLenum picForm
 
 	if(normalmap)
 	{
-		if ((type == IMGTYPE_NORMALHEIGHT) && RawImage_HasAlpha(data, numPixels))
+		if ((type == IMGTYPE_NORMALHEIGHT) && RawImage_HasAlpha(data, numPixels) && r_parallaxMapping->integer)
 		{
 			if (!forceNoCompression && glRefConfig.textureCompression & TCR_BPTC)
 			{
@@ -1979,9 +1996,9 @@ static void CompressMonoBlock(byte outdata[8], const byte indata[16])
 	}
 }
 
-static void RawImage_UploadToRgtc2Texture(GLuint texture, byte *data, int width, int height, int mip)
+static void RawImage_UploadToRgtc2Texture(GLuint texture, int miplevel, int x, int y, int width, int height, byte *data)
 {
-	int wBlocks, hBlocks, y, x, size;
+	int wBlocks, hBlocks, iy, ix, size;
 	byte *compressedData, *p;
 
 	wBlocks = (width + 3) / 4;
@@ -1989,16 +2006,16 @@ static void RawImage_UploadToRgtc2Texture(GLuint texture, byte *data, int width,
 	size = wBlocks * hBlocks * 16;
 
 	p = compressedData = ri.Hunk_AllocateTempMemory(size);
-	for (y = 0; y < height; y += 4)
+	for (iy = 0; iy < height; iy += 4)
 	{
-		int oh = MIN(4, height - y);
+		int oh = MIN(4, height - iy);
 
-		for (x = 0; x < width; x += 4)
+		for (ix = 0; ix < width; ix += 4)
 		{
 			byte workingData[16];
 			int component;
 
-			int ow = MIN(4, width - x);
+			int ow = MIN(4, width - ix);
 
 			for (component = 0; component < 2; component++)
 			{
@@ -2006,7 +2023,7 @@ static void RawImage_UploadToRgtc2Texture(GLuint texture, byte *data, int width,
 
 				for (oy = 0; oy < oh; oy++)
 					for (ox = 0; ox < ow; ox++)
-						workingData[oy * 4 + ox] = data[((y + oy) * width + x + ox) * 4 + component];
+						workingData[oy * 4 + ox] = data[((iy + oy) * width + ix + ox) * 4 + component];
 
 				// dupe data to fill
 				for (oy = 0; oy < 4; oy++)
@@ -2019,7 +2036,8 @@ static void RawImage_UploadToRgtc2Texture(GLuint texture, byte *data, int width,
 		}
 	}
 
-	qglCompressedTextureImage2DEXT(texture, GL_TEXTURE_2D, mip, GL_COMPRESSED_RG_RGTC2, width, height, 0, size, compressedData);
+	// FIXME: Won't work for x/y that aren't multiples of 4.
+	qglCompressedTextureSubImage2DEXT(texture, GL_TEXTURE_2D, miplevel, x, y, width, height, GL_COMPRESSED_RG_RGTC2, size, compressedData);
 
 	ri.Hunk_FreeTempMemory(compressedData);
 }
@@ -2063,64 +2081,35 @@ static int CalculateMipSize(int width, int height, GLenum picFormat)
 	return 0;
 }
 
-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;
 
+static GLenum PixelDataFormatFromInternalFormat(GLenum internalFormat)
+{
 	switch (internalFormat)
 	{
 		case GL_DEPTH_COMPONENT:
 		case GL_DEPTH_COMPONENT16_ARB:
 		case GL_DEPTH_COMPONENT24_ARB:
 		case GL_DEPTH_COMPONENT32_ARB:
-			dataFormat = GL_DEPTH_COMPONENT;
-			dataType = GL_UNSIGNED_BYTE;
-			break;
-		case GL_RGBA16F_ARB:
-			dataFormat = GL_RGBA;
-			dataType = GL_HALF_FLOAT_ARB;
-			break;
+			return GL_DEPTH_COMPONENT;
 		default:
-			dataFormat = GL_RGBA;
-			dataType = GL_UNSIGNED_BYTE;
+			return GL_RGBA;
 			break;
 	}
+}
 
-	if (!data)
-	{
-		miplevel = 0;
-		do
-		{
-			lastMip = (width == 1 && height == 1) || !mipmap;
-			qglTextureImage2DEXT(texture, target, miplevel, internalFormat, width, height, 0, dataFormat, dataType, NULL);
+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 )
+{
+	GLenum dataFormat, dataType;
+	qboolean rgtc = (internalFormat == GL_COMPRESSED_RG_RGTC2);
+	qboolean compressed = (!(picFormat == GL_RGBA8) || (picFormat == GL_SRGB8_ALPHA8_EXT));
+	qboolean mipmap = !!(flags & IMGFLAG_MIPMAP);
+	int size, miplevel;
+	qboolean lastMip = qfalse;
 
-			width = MAX(1, width >> 1);
-			height = MAX(1, height >> 1);
-			miplevel++;
-		}
-		while (!lastMip);
+	dataFormat = PixelDataFormatFromInternalFormat(internalFormat);
 
-		return;
-	}
-
-	if (compressed && picmip)
-	{
-		for (miplevel = r_picmip->integer; miplevel > 0 && numMips > 1; miplevel--, numMips--)
-		{
-			size = CalculateMipSize(width, height, picFormat);
-			x >>= 1;
-			y >>= 1;
-			width = MAX(1, width >> 1);
-			height = MAX(1, height >> 1);
-			data += size;
-		}
-	}
+	// FIXME: This is an old hack to use half floats with lightmaps, use picFormat to determine this instead.
+	dataType = (internalFormat == GL_RGBA16F_ARB) ? GL_HALF_FLOAT_ARB : GL_UNSIGNED_BYTE;
 
 	miplevel = 0;
 	do
@@ -2130,10 +2119,7 @@ static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int
 
 		if (compressed)
 		{
-			if (subtexture)
-				qglCompressedTextureSubImage2DEXT(texture, target, miplevel, x, y, width, height, picFormat, size, data);
-			else
-				qglCompressedTextureImage2DEXT(texture, target, miplevel, picFormat, width, height, 0, size, data);
+			qglCompressedTextureSubImage2DEXT(texture, target, miplevel, x, y, width, height, picFormat, size, data);
 		}
 		else
 		{
@@ -2141,11 +2127,9 @@ static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int
 				R_BlendOverTexture((byte *)data, width * height, mipBlendColors[miplevel]);
 
 			if (rgtc)
-				RawImage_UploadToRgtc2Texture(texture, data, width, height, miplevel);
-			else if (subtexture)
-				qglTextureSubImage2DEXT(texture, target, miplevel, x, y, width, height, dataFormat, dataType, data);
+				RawImage_UploadToRgtc2Texture(texture, miplevel, x, y, width, height, data);
 			else
-				qglTextureImage2DEXT(texture, target, miplevel, internalFormat, width, height, 0, dataFormat, dataType, data);
+				qglTextureSubImage2DEXT(texture, target, miplevel, x, y, width, height, dataFormat, dataType, data);
 
 			if (!lastMip && numMips < 2)
 			{
@@ -2171,157 +2155,86 @@ static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int
 	while (!lastMip);
 }
 
+
 /*
 ===============
 Upload32
 
 ===============
 */
-static void Upload32(byte *data, int x, int y, int width, int height, GLenum picFormat, int numMips, image_t *image)
+static void Upload32(byte *data, int x, int y, int width, int height, GLenum picFormat, int numMips, image_t *image, qboolean scaled)
 {
-	byte		*resampledBuffer = NULL;
 	int			i, c;
 	byte		*scan;
-	static int rmse_saved = 0;
-
-	// do the root mean square error stuff first
-	if ( r_rmse->value ) {
-		while ( R_RMSE( (byte *)data, width, height ) < r_rmse->value ) {
-			rmse_saved += ( height * width * 4 ) - ( ( width >> 1 ) * ( height >> 1 ) * 4 );
-			resampledBuffer = ri.Hunk_AllocateTempMemory( ( width >> 1 ) * ( height >> 1 ) * 4 );
-			ResampleTexture( data, width, height, resampledBuffer, width >> 1, height >> 1 );
-			data = resampledBuffer;
-			width = width >> 1;
-			height = height >> 1;
-			ri.Printf( PRINT_ALL, "r_rmse of %f has saved %dkb\n", r_rmse->value, ( rmse_saved / 1024 ) );
-		}
-	}
 
 	imgType_t type = image->type;
 	imgFlags_t flags = image->flags;
 	GLenum internalFormat = image->internalFormat;
-	qboolean subtexture = (x != 0) || (y != 0) || (width != image->width) || (height != image->height);
-	qboolean notScaled = qtrue;
 	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)
+	// These operations cannot be performed on pre-compressed images.
+	if (!compressed && !cubemap)
 	{
-		RawImage_ScaleToPower2(NULL, &width, &height, type, flags, NULL);
-		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 (compressed || cubemap)
+		c = width*height;
+		scan = data;
+
+		if (type == IMGTYPE_COLORALPHA)
 		{
-			for (i = 0; i < depth; i++)
+			if( r_greyscale->integer )
 			{
-				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--)
+				for ( i = 0; i < c; i++ )
 				{
-					data += CalculateMipSize(w2, h2, picFormat);
-					w2 = MAX(1, w2 >> 1);
-					h2 = MAX(1, h2 >> 1);
+					byte luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
+					scan[i*4] = luma;
+					scan[i*4 + 1] = luma;
+					scan[i*4 + 2] = luma;
+				}
+			}
+			else if( r_greyscale->value )
+			{
+				for ( i = 0; i < c; i++ )
+				{
+					float luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
+					scan[i*4] = LERP(scan[i*4], luma, r_greyscale->value);
+					scan[i*4 + 1] = LERP(scan[i*4 + 1], luma, r_greyscale->value);
+					scan[i*4 + 2] = LERP(scan[i*4 + 2], luma, r_greyscale->value);
 				}
 			}
-			goto done;
-		}
-		notScaled = RawImage_ScaleToPower2(&data, &width, &height, type, flags, &resampledBuffer);
-	}
 
-	c = width*height;
-	scan = data;
-	
-	if( r_greyscale->integer )
-	{
-		for ( i = 0; i < c; i++ )
-		{
-			byte luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
-			scan[i*4] = luma;
-			scan[i*4 + 1] = luma;
-			scan[i*4 + 2] = luma;
-		}
-	}
-	else if( r_greyscale->value )
-	{
-		for ( i = 0; i < c; i++ )
-		{
-			float luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
-			scan[i*4] = LERP(scan[i*4], luma, r_greyscale->value);
-			scan[i*4 + 1] = LERP(scan[i*4 + 1], luma, r_greyscale->value);
-			scan[i*4 + 2] = LERP(scan[i*4 + 2], luma, r_greyscale->value);
+			// This corresponds to what the OpenGL1 renderer does.
+			if (!(flags & IMGFLAG_NOLIGHTSCALE) && (scaled || mipmap))
+				R_LightScaleTexture(data, width, height, !mipmap);
 		}
-	}
-
-	if (glRefConfig.swizzleNormalmap && (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT))
-		RawImage_SwizzleRA(data, width, height);
-
-	// This corresponds to what the OpenGL1 renderer does
-	if (!(flags & IMGFLAG_NOLIGHTSCALE) && (!notScaled || mipmap))
-		R_LightScaleTexture(data, width, height, !mipmap);
 
-	if (subtexture)
-	{
-		// FIXME: Incorrect if original texture was not a power of 2 texture or picmipped
-		RawImage_UploadTexture(image->texnum, data, x, y, width, height, uploadTarget, GL_RGBA8, 0, internalFormat, type, flags, qtrue);
-		GL_CheckErrors();
-		return;
+		if (glRefConfig.swizzleNormalmap && (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT))
+			RawImage_SwizzleRA(data, width, height);
 	}
 
-	RawImage_UploadTexture(image->texnum, data, 0, 0, width, height, uploadTarget, GL_RGBA8, 0, internalFormat, type, flags, qfalse);
-
-done:
-
-	image->uploadWidth  = width;
-	image->uploadHeight = height;
-
-	if (mipmap)
+	if (cubemap)
 	{
-		if (textureFilterAnisotropic && !cubemap)
-			qglTextureParameteriEXT(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT,
-			(GLint)Com_Clamp(1, maxAnisotropy, r_ext_max_anisotropy->integer));
-
-		qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, gl_filter_min);
-		qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+		for (i = 0; i < 6; i++)
+		{
+			int w2 = width, h2 = height;
+			RawImage_UploadTexture(image->texnum, data, x, y, width, height, GL_TEXTURE_CUBE_MAP_POSITIVE_X + 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);
+			}
+		}
 	}
 	else
 	{
-		if (textureFilterAnisotropic && !cubemap)
-			qglTextureParameteriEXT(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
-
-		qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-		qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	}
-
-	// Fix for sampling depth buffer on old nVidia cards
-	// from http://www.idevgames.com/forums/thread-4141-post-34844.html#pid34844
-	switch(internalFormat)
-	{
-		case GL_DEPTH_COMPONENT:
-		case GL_DEPTH_COMPONENT16_ARB:
-		case GL_DEPTH_COMPONENT24_ARB:
-		case GL_DEPTH_COMPONENT32_ARB:
-			qglTextureParameterfEXT(image->texnum, textureTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
-			qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-			qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-			break;
-		default:
-			break;
+		RawImage_UploadTexture(image->texnum, data, x, y, width, height, GL_TEXTURE_2D, picFormat, numMips, internalFormat, type, flags, qfalse);
 	}
 
 	GL_CheckErrors();
-
-	if ( resampledBuffer != NULL )
-		ri.Hunk_FreeTempMemory( resampledBuffer );
 }
 
+
 /*
 ================
 R_CreateImage2
@@ -2330,10 +2243,18 @@ This is the only way any image_t are created
 ================
 */
 image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLenum picFormat, int numMips, imgType_t type, imgFlags_t flags, int internalFormat ) {
-	image_t     *image;
-	qboolean isLightmap = qfalse;
-	long hash;
-	int         glWrapClampMode;
+	byte       *resampledBuffer = NULL;
+	image_t    *image;
+	qboolean    isLightmap = qfalse, scaled = qfalse;
+	long        hash;
+	int         glWrapClampMode, mipWidth, mipHeight, miplevel;
+	qboolean    compressed = (!(picFormat == GL_RGBA8) || (picFormat == GL_SRGB8_ALPHA8_EXT));
+	qboolean    mipmap = !!(flags & IMGFLAG_MIPMAP);
+	qboolean    cubemap = !!(flags & IMGFLAG_CUBEMAP);
+	qboolean    picmip = !!(flags & IMGFLAG_PICMIP);
+	qboolean    lastMip;
+	GLenum textureTarget = cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
+	GLenum dataFormat;
 
 	if ( strlen( name ) >= MAX_QPATH ) {
 		ri.Error( ERR_DROP, "R_CreateImage: \"%s\" is too long", name );
@@ -2367,20 +2288,91 @@ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLe
 
 	image->internalFormat = internalFormat;
 
-	Upload32(pic, 0, 0, image->width, image->height, picFormat, numMips, image);
+	// Possibly scale image before uploading.
+	// if compressed and uploading an image, skip picmips.
+	if (!cubemap)
+	{
+		if (!compressed)
+			scaled = RawImage_ScaleToPower2(&pic, &width, &height, type, flags, &resampledBuffer);
+		else if (pic && picmip)
+		{
+			for (miplevel = r_picmip->integer; miplevel > 0 && numMips > 1; miplevel--, numMips--)
+			{
+				int size = CalculateMipSize(width, height, picFormat);
+				width = MAX(1, width >> 1);
+				height = MAX(1, height >> 1);
+				pic += size;
+			}
+		}
+	}
+
+	image->uploadWidth = width;
+	image->uploadHeight = height;
 
-	if (image->flags & IMGFLAG_CUBEMAP)
+	// Allocate texture storage so we don't have to worry about it later.
+	dataFormat = PixelDataFormatFromInternalFormat(internalFormat);
+	mipWidth = width;
+	mipHeight = height;
+	miplevel = 0;
+	do
 	{
-		qglTextureParameterfEXT(image->texnum, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, glWrapClampMode);
-		qglTextureParameterfEXT(image->texnum, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, glWrapClampMode);
-		qglTextureParameteriEXT(image->texnum, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, glWrapClampMode);
+		lastMip = !mipmap || (mipWidth == 1 && mipHeight == 1);
+		if (cubemap)
+		{
+			int i;
+
+			for (i = 0; i < 6; i++)
+				qglTextureImage2DEXT(image->texnum, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, miplevel, internalFormat, mipWidth, mipHeight, 0, dataFormat, GL_UNSIGNED_BYTE, NULL);
+		}
+		else
+		{
+			qglTextureImage2DEXT(image->texnum, GL_TEXTURE_2D, miplevel, internalFormat, mipWidth, mipHeight, 0, dataFormat, GL_UNSIGNED_BYTE, NULL);
+		}
+
+		mipWidth  = MAX(1, mipWidth >> 1);
+		mipHeight = MAX(1, mipHeight >> 1);
+		miplevel++;
 	}
-	else
+	while (!lastMip);
+
+	// Upload data.
+	if (pic)
+		Upload32(pic, 0, 0, width, height, picFormat, numMips, image, scaled);
+
+	if (resampledBuffer != NULL)
+		ri.Hunk_FreeTempMemory(resampledBuffer);
+
+	// Set all necessary texture parameters.
+	qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_WRAP_S, glWrapClampMode);
+	qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_WRAP_T, glWrapClampMode);
+
+	if (cubemap)
+		qglTextureParameteriEXT(image->texnum, textureTarget, GL_TEXTURE_WRAP_R, glWrapClampMode);
+
+	if (textureFilterAnisotropic && !cubemap)
+		qglTextureParameteriEXT(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT,
+			mipmap ? (GLint)Com_Clamp(1, maxAnisotropy, r_ext_max_anisotropy->integer) : 1);
+
+	switch(internalFormat)
 	{
-		qglTextureParameterfEXT(image->texnum, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode);
-		qglTextureParameterfEXT(image->texnum, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode);
+		case GL_DEPTH_COMPONENT:
+		case GL_DEPTH_COMPONENT16_ARB:
+		case GL_DEPTH_COMPONENT24_ARB:
+		case GL_DEPTH_COMPONENT32_ARB:
+			// Fix for sampling depth buffer on old nVidia cards.
+			// from http://www.idevgames.com/forums/thread-4141-post-34844.html#pid34844
+			qglTextureParameterfEXT(image->texnum, textureTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
+			qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+			qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+			break;
+		default:
+			qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, mipmap ? gl_filter_min : GL_LINEAR);
+			qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, mipmap ? gl_filter_max : GL_LINEAR);
+			break;
 	}
 
+	GL_CheckErrors();
+
 	hash = generateHashValue( name );
 	image->next = hashTable[hash];
 	hashTable[hash] = image;
@@ -2391,6 +2383,7 @@ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLe
 	return image;
 }
 
+
 /*
 ================
 R_CreateImage
@@ -2403,9 +2396,10 @@ image_t *R_CreateImage(const char *name, byte *pic, int width, int height, imgTy
 	return R_CreateImage2(name, pic, width, height, GL_RGBA8, 0, type, flags, internalFormat);
 }
 
+
 void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height )
 {
-	Upload32(pic, x, y, width, height, GL_RGBA8, 0, image);
+	Upload32(pic, x, y, width, height, GL_RGBA8, 0, image, qfalse);
 }
 
 //===================================================================
@@ -2433,7 +2427,6 @@ static imageExtToLoaderMap_t imageLoaders[ ] =
 
 static int numImageLoaders = ARRAY_LEN( imageLoaders );
 
-
 /*
 =================
 R_LoadImage
@@ -2533,6 +2526,7 @@ void R_LoadImage( const char *name, byte **pic, int *width, int *height, GLenum
 	}
 }
 
+
 /*
 ===============
 R_FindImageFile
diff --git a/SP/code/rend2/tr_image.c b/SP/code/rend2/tr_image.c
index e6b3b80..428ffc8 100644
--- a/SP/code/rend2/tr_image.c
+++ b/SP/code/rend2/tr_image.c
@@ -46,7 +46,6 @@ int gl_filter_max = GL_LINEAR;
 #define FILE_HASH_SIZE      4096
 static image_t*        hashTable[FILE_HASH_SIZE];
 
-
 /*
 ** R_GammaCorrect
 */
@@ -1503,6 +1502,7 @@ static void R_MipMapNormalHeight (const byte *in, byte *out, int width, int heig
 R_RMSE
 ================
 */
+#if 0 // FIXME
 static float R_RMSE( byte *in, int width, int height ) {
 	int i, j;
 	float out, rmse, rtemp;
@@ -1542,6 +1542,8 @@ static float R_RMSE( byte *in, int width, int height ) {
 	rmse = sqrt( rmse / ( height * width * 4 ) );
 	return rmse;
 }
+#endif
+
 
 /*
 ==================
@@ -1616,7 +1618,23 @@ static qboolean RawImage_ScaleToPower2( byte **data, int *inout_width, int *inou
 	qboolean picmip = flags & IMGFLAG_PICMIP;
 	qboolean mipmap = flags & IMGFLAG_MIPMAP;
 	qboolean clampToEdge = flags & IMGFLAG_CLAMPTOEDGE;
-	qboolean notScaled;
+	qboolean scaled;
+#if 0
+	static int rmse_saved = 0;
+
+	// do the root mean square error stuff first
+	if ( r_rmse->value ) {
+		while ( R_RMSE( *data, width, height ) < r_rmse->value ) {
+			rmse_saved += ( height * width * 4 ) - ( ( width >> 1 ) * ( height >> 1 ) * 4 );
+			*resampledBuffer = ri.Hunk_AllocateTempMemory( ( width >> 1 ) * ( height >> 1 ) * 4 );
+			ResampleTexture( *data, width, height, *resampledBuffer, width >> 1, height >> 1 );
+			*data = *resampledBuffer;
+			width = width >> 1;
+			height = height >> 1;
+			ri.Printf( PRINT_ALL, "r_rmse of %f has saved %dkb\n", r_rmse->value, ( rmse_saved / 1024 ) );
+		}
+	}
+#endif
 
 	//
 	// convert to exact power of 2 sizes
@@ -1683,7 +1701,6 @@ static qboolean RawImage_ScaleToPower2( byte **data, int *inout_width, int *inou
 		else if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)
 			FillInNormalizedZ(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height);
 
-
 		//endTime = ri.Milliseconds();
 
 		//ri.Printf(PRINT_ALL, "upsampled %dx%d to %dx%d in %dms\n", width, height, scaled_width, scaled_height, endTime - startTime);
@@ -1728,7 +1745,7 @@ static qboolean RawImage_ScaleToPower2( byte **data, int *inout_width, int *inou
 	scaled_width  = MAX(1, scaled_width);
 	scaled_height = MAX(1, scaled_height);
 
-	notScaled = (width == scaled_width) && (height == scaled_height);
+	scaled = (width != scaled_width) || (height != scaled_height);
 
 	//
 	// rescale texture to new size using existing mipmap functions
@@ -1750,7 +1767,7 @@ static qboolean RawImage_ScaleToPower2( byte **data, int *inout_width, int *inou
 	*inout_width  = width;
 	*inout_height = height;
 
-	return notScaled;
+	return scaled;
 }
 
 
@@ -1784,7 +1801,7 @@ static GLenum RawImage_GetFormat(const byte *data, int numPixels, GLenum picForm
 
 	if(normalmap)
 	{
-		if ((type == IMGTYPE_NORMALHEIGHT) && RawImage_HasAlpha(data, numPixels))
+		if ((type == IMGTYPE_NORMALHEIGHT) && RawImage_HasAlpha(data, numPixels) && r_parallaxMapping->integer)
 		{
 			if (!forceNoCompression && glRefConfig.textureCompression & TCR_BPTC)
 			{
@@ -1974,9 +1991,9 @@ static void CompressMonoBlock(byte outdata[8], const byte indata[16])
 	}
 }
 
-static void RawImage_UploadToRgtc2Texture(GLuint texture, byte *data, int width, int height, int mip)
+static void RawImage_UploadToRgtc2Texture(GLuint texture, int miplevel, int x, int y, int width, int height, byte *data)
 {
-	int wBlocks, hBlocks, y, x, size;
+	int wBlocks, hBlocks, iy, ix, size;
 	byte *compressedData, *p;
 
 	wBlocks = (width + 3) / 4;
@@ -1984,16 +2001,16 @@ static void RawImage_UploadToRgtc2Texture(GLuint texture, byte *data, int width,
 	size = wBlocks * hBlocks * 16;
 
 	p = compressedData = ri.Hunk_AllocateTempMemory(size);
-	for (y = 0; y < height; y += 4)
+	for (iy = 0; iy < height; iy += 4)
 	{
-		int oh = MIN(4, height - y);
+		int oh = MIN(4, height - iy);
 
-		for (x = 0; x < width; x += 4)
+		for (ix = 0; ix < width; ix += 4)
 		{
 			byte workingData[16];
 			int component;
 
-			int ow = MIN(4, width - x);
+			int ow = MIN(4, width - ix);
 
 			for (component = 0; component < 2; component++)
 			{
@@ -2001,7 +2018,7 @@ static void RawImage_UploadToRgtc2Texture(GLuint texture, byte *data, int width,
 
 				for (oy = 0; oy < oh; oy++)
 					for (ox = 0; ox < ow; ox++)
-						workingData[oy * 4 + ox] = data[((y + oy) * width + x + ox) * 4 + component];
+						workingData[oy * 4 + ox] = data[((iy + oy) * width + ix + ox) * 4 + component];
 
 				// dupe data to fill
 				for (oy = 0; oy < 4; oy++)
@@ -2014,7 +2031,8 @@ static void RawImage_UploadToRgtc2Texture(GLuint texture, byte *data, int width,
 		}
 	}
 
-	qglCompressedTextureImage2DEXT(texture, GL_TEXTURE_2D, mip, GL_COMPRESSED_RG_RGTC2, width, height, 0, size, compressedData);
+	// FIXME: Won't work for x/y that aren't multiples of 4.
+	qglCompressedTextureSubImage2DEXT(texture, GL_TEXTURE_2D, miplevel, x, y, width, height, GL_COMPRESSED_RG_RGTC2, size, compressedData);
 
 	ri.Hunk_FreeTempMemory(compressedData);
 }
@@ -2058,64 +2076,35 @@ static int CalculateMipSize(int width, int height, GLenum picFormat)
 	return 0;
 }
 
-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;
 
+static GLenum PixelDataFormatFromInternalFormat(GLenum internalFormat)
+{
 	switch (internalFormat)
 	{
 		case GL_DEPTH_COMPONENT:
 		case GL_DEPTH_COMPONENT16_ARB:
 		case GL_DEPTH_COMPONENT24_ARB:
 		case GL_DEPTH_COMPONENT32_ARB:
-			dataFormat = GL_DEPTH_COMPONENT;
-			dataType = GL_UNSIGNED_BYTE;
-			break;
-		case GL_RGBA16F_ARB:
-			dataFormat = GL_RGBA;
-			dataType = GL_HALF_FLOAT_ARB;
-			break;
+			return GL_DEPTH_COMPONENT;
 		default:
-			dataFormat = GL_RGBA;
-			dataType = GL_UNSIGNED_BYTE;
+			return GL_RGBA;
 			break;
 	}
+}
 
-	if (!data)
-	{
-		miplevel = 0;
-		do
-		{
-			lastMip = (width == 1 && height == 1) || !mipmap;
-			qglTextureImage2DEXT(texture, target, miplevel, internalFormat, width, height, 0, dataFormat, dataType, NULL);
-
-			width = MAX(1, width >> 1);
-			height = MAX(1, height >> 1);
-			miplevel++;
-		}
-		while (!lastMip);
+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 )
+{
+	GLenum dataFormat, dataType;
+	qboolean rgtc = (internalFormat == GL_COMPRESSED_RG_RGTC2);
+	qboolean compressed = (!(picFormat == GL_RGBA8) || (picFormat == GL_SRGB8_ALPHA8_EXT));
+	qboolean mipmap = !!(flags & IMGFLAG_MIPMAP);
+	int size, miplevel;
+	qboolean lastMip = qfalse;
 
-		return;
-	}
+	dataFormat = PixelDataFormatFromInternalFormat(internalFormat);
 
-	if (compressed && picmip)
-	{
-		for (miplevel = r_picmip->integer; miplevel > 0 && numMips > 1; miplevel--, numMips--)
-		{
-			size = CalculateMipSize(width, height, picFormat);
-			x >>= 1;
-			y >>= 1;
-			width = MAX(1, width >> 1);
-			height = MAX(1, height >> 1);
-			data += size;
-		}
-	}
+	// FIXME: This is an old hack to use half floats with lightmaps, use picFormat to determine this instead.
+	dataType = (internalFormat == GL_RGBA16F_ARB) ? GL_HALF_FLOAT_ARB : GL_UNSIGNED_BYTE;
 
 	miplevel = 0;
 	do
@@ -2125,10 +2114,7 @@ static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int
 
 		if (compressed)
 		{
-			if (subtexture)
-				qglCompressedTextureSubImage2DEXT(texture, target, miplevel, x, y, width, height, picFormat, size, data);
-			else
-				qglCompressedTextureImage2DEXT(texture, target, miplevel, picFormat, width, height, 0, size, data);
+			qglCompressedTextureSubImage2DEXT(texture, target, miplevel, x, y, width, height, picFormat, size, data);
 		}
 		else
 		{
@@ -2136,11 +2122,9 @@ static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int
 				R_BlendOverTexture((byte *)data, width * height, mipBlendColors[miplevel]);
 
 			if (rgtc)
-				RawImage_UploadToRgtc2Texture(texture, data, width, height, miplevel);
-			else if (subtexture)
-				qglTextureSubImage2DEXT(texture, target, miplevel, x, y, width, height, dataFormat, dataType, data);
+				RawImage_UploadToRgtc2Texture(texture, miplevel, x, y, width, height, data);
 			else
-				qglTextureImage2DEXT(texture, target, miplevel, internalFormat, width, height, 0, dataFormat, dataType, data);
+				qglTextureSubImage2DEXT(texture, target, miplevel, x, y, width, height, dataFormat, dataType, data);
 
 			if (!lastMip && numMips < 2)
 			{
@@ -2166,160 +2150,87 @@ static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int
 	while (!lastMip);
 }
 
+
 /*
 ===============
 Upload32
 
 ===============
 */
-static void Upload32(byte *data, int x, int y, int width, int height, GLenum picFormat, int numMips, image_t *image)
+static void Upload32(byte *data, int x, int y, int width, int height, GLenum picFormat, int numMips, image_t *image, qboolean scaled)
 {
-	byte		*resampledBuffer = NULL;
 	int			i, c;
 	byte		*scan;
-	static int rmse_saved = 0;
-
-	// do the root mean square error stuff first
-	if ( r_rmse->value ) {
-		while ( R_RMSE( (byte *)data, width, height ) < r_rmse->value ) {
-			rmse_saved += ( height * width * 4 ) - ( ( width >> 1 ) * ( height >> 1 ) * 4 );
-			resampledBuffer = ri.Hunk_AllocateTempMemory( ( width >> 1 ) * ( height >> 1 ) * 4 );
-			ResampleTexture( data, width, height, resampledBuffer, width >> 1, height >> 1 );
-			data = resampledBuffer;
-			width = width >> 1;
-			height = height >> 1;
-			ri.Printf( PRINT_ALL, "r_rmse of %f has saved %dkb\n", r_rmse->value, ( rmse_saved / 1024 ) );
-		}
-	}
 
 	imgType_t type = image->type;
 	imgFlags_t flags = image->flags;
 	GLenum internalFormat = image->internalFormat;
-	qboolean subtexture = (x != 0) || (y != 0) || (width != image->width) || (height != image->height);
-	qboolean notScaled = qtrue;
 	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);
-		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)
+	// These operations cannot be performed on pre-compressed images.
+	if (!compressed && !cubemap)
 	{
-		if (compressed || cubemap)
+		c = width*height;
+		scan = data;
+
+		if (type == IMGTYPE_COLORALPHA)
 		{
-			for (i = 0; i < depth; i++)
+			if( r_greyscale->integer )
 			{
-				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--)
+				for ( i = 0; i < c; i++ )
 				{
-					data += CalculateMipSize(w2, h2, picFormat);
-					w2 = MAX(1, w2 >> 1);
-					h2 = MAX(1, h2 >> 1);
+					byte luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
+					scan[i*4] = luma;
+					scan[i*4 + 1] = luma;
+					scan[i*4 + 2] = luma;
+				}
+			}
+			else if( r_greyscale->value )
+			{
+				for ( i = 0; i < c; i++ )
+				{
+					float luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
+					scan[i*4] = LERP(scan[i*4], luma, r_greyscale->value);
+					scan[i*4 + 1] = LERP(scan[i*4 + 1], luma, r_greyscale->value);
+					scan[i*4 + 2] = LERP(scan[i*4 + 2], luma, r_greyscale->value);
 				}
 			}
-			goto done;
-		}
-		notScaled = RawImage_ScaleToPower2(&data, &width, &height, type, flags, &resampledBuffer);
-	}
 
-	c = width*height;
-	scan = data;
-	
-	if( r_greyscale->integer )
-	{
-		for ( i = 0; i < c; i++ )
-		{
-			byte luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
-			scan[i*4] = luma;
-			scan[i*4 + 1] = luma;
-			scan[i*4 + 2] = luma;
-		}
-	}
-	else if( r_greyscale->value )
-	{
-		for ( i = 0; i < c; i++ )
-		{
-			float luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
-			scan[i*4] = LERP(scan[i*4], luma, r_greyscale->value);
-			scan[i*4 + 1] = LERP(scan[i*4 + 1], luma, r_greyscale->value);
-			scan[i*4 + 2] = LERP(scan[i*4 + 2], luma, r_greyscale->value);
+			// This corresponds to what the OpenGL1 renderer does.
+			if (!(flags & IMGFLAG_NOLIGHTSCALE) && (scaled || mipmap))
+				R_LightScaleTexture(data, width, height, !mipmap);
 		}
-	}
-
-	if (glRefConfig.swizzleNormalmap && (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT))
-		RawImage_SwizzleRA(data, width, height);
 
-	// This corresponds to what the OpenGL1 renderer does
-	if (!(flags & IMGFLAG_NOLIGHTSCALE) && (!notScaled || mipmap))
-		R_LightScaleTexture(data, width, height, !mipmap);
-
-	if (subtexture)
-	{
-		// FIXME: Incorrect if original texture was not a power of 2 texture or picmipped
-		RawImage_UploadTexture(image->texnum, data, x, y, width, height, uploadTarget, GL_RGBA8, 0, internalFormat, type, flags, qtrue);
-		GL_CheckErrors();
-		return;
+		if (glRefConfig.swizzleNormalmap && (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT))
+			RawImage_SwizzleRA(data, width, height);
 	}
 
-	RawImage_UploadTexture(image->texnum, data, 0, 0, width, height, uploadTarget, GL_RGBA8, 0, internalFormat, type, flags, qfalse);
-
-done:
-
-	image->uploadWidth  = width;
-	image->uploadHeight = height;
-
-	if (mipmap)
+	if (cubemap)
 	{
-		if (textureFilterAnisotropic && !cubemap)
-			qglTextureParameteriEXT(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT,
-			(GLint)Com_Clamp(1, maxAnisotropy, r_ext_max_anisotropy->integer));
-
-		qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, gl_filter_min);
-		qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+		for (i = 0; i < 6; i++)
+		{
+			int w2 = width, h2 = height;
+			RawImage_UploadTexture(image->texnum, data, x, y, width, height, GL_TEXTURE_CUBE_MAP_POSITIVE_X + 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);
+			}
+		}
 	}
 	else
 	{
-		if (textureFilterAnisotropic && !cubemap)
-			qglTextureParameteriEXT(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
-
-		qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-		qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	}
-
-	// Fix for sampling depth buffer on old nVidia cards
-	// from http://www.idevgames.com/forums/thread-4141-post-34844.html#pid34844
-	switch(internalFormat)
-	{
-		case GL_DEPTH_COMPONENT:
-		case GL_DEPTH_COMPONENT16_ARB:
-		case GL_DEPTH_COMPONENT24_ARB:
-		case GL_DEPTH_COMPONENT32_ARB:
-			qglTextureParameterfEXT(image->texnum, textureTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
-			qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-			qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-			break;
-		default:
-			break;
+		RawImage_UploadTexture(image->texnum, data, x, y, width, height, GL_TEXTURE_2D, picFormat, numMips, internalFormat, type, flags, qfalse);
 	}
 
 	GL_CheckErrors();
-
-	if ( resampledBuffer != NULL )
-		ri.Hunk_FreeTempMemory( resampledBuffer );
 }
 
 
 //----(SA)	modified
-
 /*
 ================
 R_CreateImageExt2
@@ -2328,10 +2239,18 @@ This is the only way any image_t are created
 ================
 */
 image_t *R_CreateImageExt2( const char *name, byte *pic, int width, int height, GLenum picFormat, int numMips, imgType_t type, imgFlags_t flags, int internalFormat, qboolean characterMip ) {
-	image_t     *image;
-	qboolean isLightmap = qfalse;
-	int         glWrapClampMode;
-	long hash;
+	byte       *resampledBuffer = NULL;
+	image_t    *image;
+	qboolean    isLightmap = qfalse, scaled = qfalse;
+	long        hash;
+	int         glWrapClampMode, mipWidth, mipHeight, miplevel;
+	qboolean    compressed = (!(picFormat == GL_RGBA8) || (picFormat == GL_SRGB8_ALPHA8_EXT));
+	qboolean    mipmap = !!(flags & IMGFLAG_MIPMAP);
+	qboolean    cubemap = !!(flags & IMGFLAG_CUBEMAP);
+	qboolean    picmip = !!(flags & IMGFLAG_PICMIP);
+	qboolean    lastMip;
+	GLenum textureTarget = cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
+	GLenum dataFormat;
 
 	if ( strlen( name ) >= MAX_QPATH ) {
 		ri.Error( ERR_DROP, "R_CreateImage: \"%s\" is too long", name );
@@ -2365,20 +2284,91 @@ image_t *R_CreateImageExt2( const char *name, byte *pic, int width, int height,
 
 	image->internalFormat = internalFormat;
 
-	Upload32(pic, 0, 0, image->width, image->height, picFormat, numMips, image);
+	// Possibly scale image before uploading.
+	// if compressed and uploading an image, skip picmips.
+	if (!cubemap)
+	{
+		if (!compressed)
+			scaled = RawImage_ScaleToPower2(&pic, &width, &height, type, flags, &resampledBuffer);
+		else if (pic && picmip)
+		{
+			for (miplevel = r_picmip->integer; miplevel > 0 && numMips > 1; miplevel--, numMips--)
+			{
+				int size = CalculateMipSize(width, height, picFormat);
+				width = MAX(1, width >> 1);
+				height = MAX(1, height >> 1);
+				pic += size;
+			}
+		}
+	}
+
+	image->uploadWidth = width;
+	image->uploadHeight = height;
 
-	if (image->flags & IMGFLAG_CUBEMAP)
+	// Allocate texture storage so we don't have to worry about it later.
+	dataFormat = PixelDataFormatFromInternalFormat(internalFormat);
+	mipWidth = width;
+	mipHeight = height;
+	miplevel = 0;
+	do
 	{
-		qglTextureParameterfEXT(image->texnum, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, glWrapClampMode);
-		qglTextureParameterfEXT(image->texnum, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, glWrapClampMode);
-		qglTextureParameteriEXT(image->texnum, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, glWrapClampMode);
+		lastMip = !mipmap || (mipWidth == 1 && mipHeight == 1);
+		if (cubemap)
+		{
+			int i;
+
+			for (i = 0; i < 6; i++)
+				qglTextureImage2DEXT(image->texnum, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, miplevel, internalFormat, mipWidth, mipHeight, 0, dataFormat, GL_UNSIGNED_BYTE, NULL);
+		}
+		else
+		{
+			qglTextureImage2DEXT(image->texnum, GL_TEXTURE_2D, miplevel, internalFormat, mipWidth, mipHeight, 0, dataFormat, GL_UNSIGNED_BYTE, NULL);
+		}
+
+		mipWidth  = MAX(1, mipWidth >> 1);
+		mipHeight = MAX(1, mipHeight >> 1);
+		miplevel++;
 	}
-	else
+	while (!lastMip);
+
+	// Upload data.
+	if (pic)
+		Upload32(pic, 0, 0, width, height, picFormat, numMips, image, scaled);
+
+	if (resampledBuffer != NULL)
+		ri.Hunk_FreeTempMemory(resampledBuffer);
+
+	// Set all necessary texture parameters.
+	qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_WRAP_S, glWrapClampMode);
+	qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_WRAP_T, glWrapClampMode);
+
+	if (cubemap)
+		qglTextureParameteriEXT(image->texnum, textureTarget, GL_TEXTURE_WRAP_R, glWrapClampMode);
+
+	if (textureFilterAnisotropic && !cubemap)
+		qglTextureParameteriEXT(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT,
+			mipmap ? (GLint)Com_Clamp(1, maxAnisotropy, r_ext_max_anisotropy->integer) : 1);
+
+	switch(internalFormat)
 	{
-		qglTextureParameterfEXT(image->texnum, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode);
-		qglTextureParameterfEXT(image->texnum, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode);
+		case GL_DEPTH_COMPONENT:
+		case GL_DEPTH_COMPONENT16_ARB:
+		case GL_DEPTH_COMPONENT24_ARB:
+		case GL_DEPTH_COMPONENT32_ARB:
+			// Fix for sampling depth buffer on old nVidia cards.
+			// from http://www.idevgames.com/forums/thread-4141-post-34844.html#pid34844
+			qglTextureParameterfEXT(image->texnum, textureTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
+			qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+			qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+			break;
+		default:
+			qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, mipmap ? gl_filter_min : GL_LINEAR);
+			qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, mipmap ? gl_filter_max : GL_LINEAR);
+			break;
 	}
 
+	GL_CheckErrors();
+
 	hash = generateHashValue( name );
 	image->next = hashTable[hash];
 	hashTable[hash] = image;
@@ -2389,6 +2379,7 @@ image_t *R_CreateImageExt2( const char *name, byte *pic, int width, int height,
 	return image;
 }
 
+
 /*
 ================
 R_CreateImage
@@ -2399,12 +2390,11 @@ Wrapper for R_CreateImageExt2(), for the old parameters.
 image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgType_t type, imgFlags_t flags, int internalFormat ) {
 	return R_CreateImageExt2(name, pic, width, height, GL_RGBA8, 0, type, flags, internalFormat, qfalse);
 }
-
 //----(SA)	end
 
 void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height )
 {
-	Upload32(pic, x, y, width, height, GL_RGBA8, 0, image);
+	Upload32(pic, x, y, width, height, GL_RGBA8, 0, image, qfalse);
 }
 
 //===================================================================
@@ -2429,9 +2419,8 @@ static imageExtToLoaderMap_t imageLoaders[ ] =
 	{ "pcx",  R_LoadPCX },
 	{ "bmp",  R_LoadBMP }
 };
- 
-static int numImageLoaders = ARRAY_LEN( imageLoaders );
 
+static int numImageLoaders = ARRAY_LEN( imageLoaders );
 
 /*
 =================

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