From bc69fba592f3f55d69447a7d64b7a9fc384b02e6 Mon Sep 17 00:00:00 2001
From: divverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Fri, 6 Aug 2010 19:22:21 +0000
Subject: [PATCH] use the DDPF_ALPHAPIXELS flag for DDS reading, at least works
 for ATI Compressonator

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10376 d7cf8633-e32d-0410-b094-e92efae38249
---
 gl_rmain.c    | 16 +++++++--------
 gl_textures.c | 55 ++++++++++++++++++++++++++++++++-------------------
 r_textures.h  |  2 +-
 3 files changed, 44 insertions(+), 29 deletions(-)

diff --git a/gl_rmain.c b/gl_rmain.c
index 219e04c9..032ff51a 100644
--- a/gl_rmain.c
+++ b/gl_rmain.c
@@ -6588,9 +6588,9 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
 		R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
 		//Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
 		if (r_savedds && qglGetCompressedTexImageARB && skinframe->base)
-			R_SaveTextureDDSFile(skinframe->base, va("dds/%s.dds", skinframe->basename), true);
+			R_SaveTextureDDSFile(skinframe->base, va("dds/%s.dds", skinframe->basename), true, skinframe->hasalpha);
 		if (r_savedds && qglGetCompressedTexImageARB && skinframe->fog)
-			R_SaveTextureDDSFile(skinframe->fog, va("dds/%s_mask.dds", skinframe->basename), true);
+			R_SaveTextureDDSFile(skinframe->fog, va("dds/%s_mask.dds", skinframe->basename), true, true);
 	}
 
 	if (r_loaddds)
@@ -6632,7 +6632,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
 			Mem_Free(pixels);
 		}
 		if (r_savedds && qglGetCompressedTexImageARB && skinframe->nmap)
-			R_SaveTextureDDSFile(skinframe->nmap, va("dds/%s_norm.dds", skinframe->basename), true);
+			R_SaveTextureDDSFile(skinframe->nmap, va("dds/%s_norm.dds", skinframe->basename), true, true);
 	}
 
 	// _luma is supported only for tenebrae compatibility
@@ -6642,7 +6642,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
 	{
 		skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_glow.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
 		if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow)
-			R_SaveTextureDDSFile(skinframe->glow, va("dds/%s_glow.dds", skinframe->basename), true);
+			R_SaveTextureDDSFile(skinframe->glow, va("dds/%s_glow.dds", skinframe->basename), true, true);
 		Mem_Free(pixels);pixels = NULL;
 	}
 
@@ -6651,7 +6651,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
 	{
 		skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_gloss.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
 		if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss)
-			R_SaveTextureDDSFile(skinframe->gloss, va("dds/%s_gloss.dds", skinframe->basename), true);
+			R_SaveTextureDDSFile(skinframe->gloss, va("dds/%s_gloss.dds", skinframe->basename), true, true);
 		Mem_Free(pixels);
 		pixels = NULL;
 	}
@@ -6661,7 +6661,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
 	{
 		skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
 		if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants)
-			R_SaveTextureDDSFile(skinframe->pants, va("dds/%s_pants.dds", skinframe->basename), true);
+			R_SaveTextureDDSFile(skinframe->pants, va("dds/%s_pants.dds", skinframe->basename), true, false);
 		Mem_Free(pixels);
 		pixels = NULL;
 	}
@@ -6671,7 +6671,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
 	{
 		skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
 		if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt)
-			R_SaveTextureDDSFile(skinframe->shirt, va("dds/%s_shirt.dds", skinframe->basename), true);
+			R_SaveTextureDDSFile(skinframe->shirt, va("dds/%s_shirt.dds", skinframe->basename), true, false);
 		Mem_Free(pixels);
 		pixels = NULL;
 	}
@@ -6681,7 +6681,7 @@ skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboole
 	{
 		skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va("%s_reflect", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_reflectmask.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
 		if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect)
-			R_SaveTextureDDSFile(skinframe->reflect, va("dds/%s_reflect.dds", skinframe->basename), true);
+			R_SaveTextureDDSFile(skinframe->reflect, va("dds/%s_reflect.dds", skinframe->basename), true, true);
 		Mem_Free(pixels);
 		pixels = NULL;
 	}
diff --git a/gl_textures.c b/gl_textures.c
index a44e3a29..527ec31b 100644
--- a/gl_textures.c
+++ b/gl_textures.c
@@ -31,7 +31,7 @@ cvar_t gl_texturecompression_sky = {CVAR_SAVE, "gl_texturecompression_sky", "0",
 cvar_t gl_texturecompression_lightcubemaps = {CVAR_SAVE, "gl_texturecompression_lightcubemaps", "1", "whether to compress light cubemaps (spotlights and other light projection images)"};
 cvar_t gl_texturecompression_reflectmask = {CVAR_SAVE, "gl_texturecompression_reflectmask", "1", "whether to compress reflection cubemap masks (mask of which areas of the texture should reflect the generic shiny cubemap)"};
 cvar_t gl_nopartialtextureupdates = {CVAR_SAVE, "gl_nopartialtextureupdates", "1", "use alternate path for dynamic lightmap updates that avoids a possibly slow code path in the driver"};
-cvar_t r_texture_dds_load_dxt1_noalpha = {0, "r_texture_dds_load_dxt1_noalpha", "0", "if set, alpha detection on DXT1 is turned off, and DXT1 textures are assumed to never have alpha"};
+cvar_t r_texture_dds_load_alphamode = {0, "r_texture_dds_load_alphamode", "0", "0: trust DDPF_ALPHAPIXELS flag, 1: texture format and brute force search if ambigous, 2: texture format only"};
 
 qboolean	gl_filter_force = false;
 int		gl_filter_min = GL_LINEAR_MIPMAP_LINEAR;
@@ -806,7 +806,7 @@ void R_Textures_Init (void)
 	Cvar_RegisterVariable (&gl_texturecompression_lightcubemaps);
 	Cvar_RegisterVariable (&gl_texturecompression_reflectmask);
 	Cvar_RegisterVariable (&gl_nopartialtextureupdates);
-	Cvar_RegisterVariable (&r_texture_dds_load_dxt1_noalpha);
+	Cvar_RegisterVariable (&r_texture_dds_load_alphamode);
 
 	R_RegisterModule("R_Textures", r_textures_start, r_textures_shutdown, r_textures_newmap, r_textures_devicelost, r_textures_devicerestored);
 }
@@ -1597,7 +1597,7 @@ rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char
     return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, R_ShadowMapTextureFlags(precision, filter), -1, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
 }
 
-int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed)
+int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha)
 {
 	gltexture_t *glt = (gltexture_t *)rt;
 	unsigned char *dds;
@@ -1672,13 +1672,15 @@ int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipunco
 	else
 	{
 		dds_flags = 0x100F; // DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH
-		dds_format_flags = 0x41; // DDPF_RGB | DDPF_ALPHAPIXELS
+		dds_format_flags = 0x40; // DDPF_RGB
 	}
 	if (mipmaps)
 	{
 		dds_flags |= 0x20000; // DDSD_MIPMAPCOUNT
 		dds_caps1 |= 0x400008; // DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
 	}
+	if(hasalpha)
+		dds_format_flags |= 0x1; // DDPF_ALPHAPIXELS
 	memcpy(dds, "DDS ", 4);
 	StoreLittleLong(dds+4, ddssize);
 	StoreLittleLong(dds+8, dds_flags);
@@ -1759,6 +1761,10 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
 	dds_height = BuffLittleLong(dds+12);
 	ddspixels = dds + 128;
 
+	if(r_texture_dds_load_alphamode.integer == 0)
+		if(!(dds_format_flags & 0x1)) // DDPF_ALPHAPIXELS
+			flags &= ~TEXF_ALPHA;
+
 	//flags &= ~TEXF_ALPHA; // disabled, as we DISABLE TEXF_ALPHA in the alpha detection, not enable it!
 	if ((dds_format_flags & 0x40) && BuffLittleLong(dds+88) == 32)
 	{
@@ -1773,12 +1779,15 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
 			Con_Printf("^1%s: invalid BGRA DDS image\n", filename);
 			return NULL;
 		}
-		// check alpha
-		for (i = 3;i < size;i += 4)
-			if (ddspixels[i] < 255)
-				break;
-		if (i >= size)
-			flags &= ~TEXF_ALPHA;
+		if((r_texture_dds_load_alphamode.integer == 1) && (flags & TEXF_ALPHA))
+		{
+			// check alpha
+			for (i = 3;i < size;i += 4)
+				if (ddspixels[i] < 255)
+					break;
+			if (i >= size)
+				flags &= ~TEXF_ALPHA;
+		}
 	}
 	else if (!memcmp(dds+84, "DXT1", 4))
 	{
@@ -1796,19 +1805,23 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
 			Con_Printf("^1%s: invalid DXT1 DDS image\n", filename);
 			return NULL;
 		}
-		if(r_texture_dds_load_dxt1_noalpha.integer)
+		if(r_texture_dds_load_alphamode.integer && (flags & TEXF_ALPHA))
 		{
-			flags &= ~TEXF_ALPHA;
-		}
-		else
-		{
-			for (i = 0;i < size;i += bytesperblock)
-				if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
-					break;
-			if (i < size)
-				textype = TEXTYPE_DXT1A;
+			if(r_texture_dds_load_alphamode.integer == 1)
+			{
+				// check alpha
+				for (i = 0;i < size;i += bytesperblock)
+					if (ddspixels[i+0] + ddspixels[i+1] * 256 <= ddspixels[i+2] + ddspixels[i+3] * 256)
+						break;
+				if (i < size)
+					textype = TEXTYPE_DXT1A;
+				else
+					flags &= ~TEXF_ALPHA;
+			}
 			else
+			{
 				flags &= ~TEXF_ALPHA;
+			}
 		}
 	}
 	else if (!memcmp(dds+84, "DXT3", 4))
@@ -1823,6 +1836,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
 			Con_Printf("^1%s: invalid DXT3 DDS image\n", filename);
 			return NULL;
 		}
+		// we currently always assume alpha
 	}
 	else if (!memcmp(dds+84, "DXT5", 4))
 	{
@@ -1836,6 +1850,7 @@ rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filen
 			Con_Printf("^1%s: invalid DXT5 DDS image\n", filename);
 			return NULL;
 		}
+		// we currently always assume alpha
 	}
 	else
 	{
diff --git a/r_textures.h b/r_textures.h
index 0d7ca047..c433a04b 100644
--- a/r_textures.h
+++ b/r_textures.h
@@ -134,7 +134,7 @@ rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char
 rtexture_t *R_LoadTextureDDSFile(rtexturepool_t *rtexturepool, const char *filename, int flags, qboolean *hasalphaflag, float *avgcolor, int miplevel);
 
 // saves a texture to a DDS file
-int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed);
+int R_SaveTextureDDSFile(rtexture_t *rt, const char *filename, qboolean skipuncompressed, qboolean hasalpha);
 
 // free a texture
 void R_FreeTexture(rtexture_t *rt);
-- 
2.39.5