From 3190d8a82f7eae2fab0baaa38e5353a5e6909bf4 Mon Sep 17 00:00:00 2001
From: havoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Thu, 17 Nov 2005 15:17:14 +0000
Subject: [PATCH] made gl_max_size cvar only affect TEXF_PICMIP textures, this
 prevents it from breaking bloom like it did previously, and bloom now
 disables itself if the hardware doesn't support big enough textures (such as
 3Dfx Voodoo1/2/3/Rush/Banshee)

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5810 d7cf8633-e32d-0410-b094-e92efae38249
---
 gl_rmain.c    |  25 ++++++----
 gl_textures.c | 128 +++++++++++++++++++++++++++-----------------------
 glquake.h     |   4 ++
 r_textures.h  |   2 +-
 vid_shared.c  |  15 +++++-
 5 files changed, 104 insertions(+), 70 deletions(-)

diff --git a/gl_rmain.c b/gl_rmain.c
index 9373aa1a..0b719b97 100644
--- a/gl_rmain.c
+++ b/gl_rmain.c
@@ -746,9 +746,21 @@ static void R_SetFrustum(void)
 
 static void R_BlendView(void)
 {
+	int screenwidth, screenheight;
+	qboolean dobloom;
+	qboolean doblend;
 	rmeshstate_t m;
 
-	if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
+	// set the (poorly named) screenwidth and screenheight variables to
+	// a power of 2 at least as large as the screen, these will define the
+	// size of the texture to allocate
+	for (screenwidth = 1;screenwidth < vid.width;screenwidth *= 2);
+	for (screenheight = 1;screenheight < vid.height;screenheight *= 2);
+
+	doblend = r_refdef.viewblend[3] >= 0.01f;
+	dobloom = r_bloom.integer && screenwidth <= gl_max_texture_size && screenheight <= gl_max_texture_size && r_bloom_resolution.value >= 32 && r_bloom_power.integer >= 1 && r_bloom_power.integer < 100 && r_bloom_blur.value >= 0 && r_bloom_blur.value < 512;
+
+	if (!dobloom && !doblend)
 		return;
 
 	GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
@@ -760,16 +772,11 @@ static void R_BlendView(void)
 	varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
 	varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
 	varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
-	if (r_bloom.integer && r_bloom_resolution.value >= 32 && r_bloom_power.integer >= 1 && r_bloom_power.integer < 100 && r_bloom_blur.value >= 0 && r_bloom_blur.value < 512)
+	if (dobloom)
 	{
-		int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
+		int bloomwidth, bloomheight, x, dobloomblend, range;
 		float xoffset, yoffset, r;
 		renderstats.bloom++;
-		// set the (poorly named) screenwidth and screenheight variables to
-		// a power of 2 at least as large as the screen, these will define the
-		// size of the texture to allocate
-		for (screenwidth = 1;screenwidth < vid.width;screenwidth *= 2);
-		for (screenheight = 1;screenheight < vid.height;screenheight *= 2);
 		// allocate textures as needed
 		if (!r_bloom_texture_screen)
 			r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
@@ -940,7 +947,7 @@ static void R_BlendView(void)
 			renderstats.bloom_drawpixels += r_view_width * r_view_height;
 		}
 	}
-	if (r_refdef.viewblend[3] >= 0.01f)
+	if (doblend)
 	{
 		// apply a color tint to the whole view
 		memset(&m, 0, sizeof(m));
diff --git a/gl_textures.c b/gl_textures.c
index 537438fa..9fe27447 100644
--- a/gl_textures.c
+++ b/gl_textures.c
@@ -136,8 +136,6 @@ static int resizebuffersize = 0;
 static unsigned char *texturebuffer;
 static int texturebuffersize = 0;
 
-static int realmaxsize = 0;
-
 static textypeinfo_t *R_GetTexTypeInfo(int textype, int flags)
 {
 	if ((flags & (TEXF_PICMIP | TEXF_FRAGMENT)) == (TEXF_PICMIP | TEXF_FRAGMENT))
@@ -365,50 +363,81 @@ static void GL_TextureMode_f (void)
 	}
 }
 
+static void GL_Texture_CalcImageSize(int texturetype, int flags, int inwidth, int inheight, int indepth, int *outwidth, int *outheight, int *outdepth)
+{
+	int picmip = 0, maxsize = 0, width2 = 1, height2 = 1, depth2 = 1;
+
+	if (gl_max_size.integer > gl_max_texture_size)
+		Cvar_SetValue("gl_max_size", gl_max_texture_size);
+
+	switch (texturetype)
+	{
+	default:
+	case GLTEXTURETYPE_1D:
+	case GLTEXTURETYPE_2D:
+		maxsize = gl_max_texture_size;
+		break;
+	case GLTEXTURETYPE_3D:
+		maxsize = gl_max_3d_texture_size;
+		break;
+	case GLTEXTURETYPE_CUBEMAP:
+		maxsize = gl_max_cube_map_texture_size;
+		break;
+	}
+
+	if (flags & TEXF_PICMIP)
+	{
+		maxsize = min(maxsize, gl_max_size.integer);
+		picmip = gl_picmip.integer;
+	}
+
+	if (outwidth)
+	{
+		for (width2 = 1;width2 < inwidth;width2 <<= 1);
+		for (width2 >>= picmip;width2 > maxsize;width2 >>= 1);
+		*outwidth = max(1, width2);
+	}
+	if (outheight)
+	{
+		for (height2 = 1;height2 < inheight;height2 <<= 1);
+		for (height2 >>= picmip;height2 > maxsize;height2 >>= 1);
+		*outheight = max(1, height2);
+	}
+	if (outdepth)
+	{
+		for (depth2 = 1;depth2 < indepth;depth2 <<= 1);
+		for (depth2 >>= picmip;depth2 > maxsize;depth2 >>= 1);
+		*outdepth = max(1, depth2);
+	}
+}
+
+
 static int R_CalcTexelDataSize (gltexture_t *glt)
 {
-	int width2, height2, depth2, size, picmip;
+	int width2, height2, depth2, size;
+
 	if (glt->flags & TEXF_FRAGMENT)
-		size = glt->width * glt->height * glt->depth;
-	else
+		return glt->width * glt->height * glt->depth * glt->textype->internalbytesperpixel * glt->image->sides;
+
+	GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->width, glt->height, glt->depth, &width2, &height2, &depth2);
+
+	size = width2 * height2 * depth2;
+
+	if (glt->flags & TEXF_MIPMAP)
 	{
-		picmip = 0;
-		if (glt->flags & TEXF_PICMIP)
-			picmip = gl_picmip.integer;
-		if (gl_max_size.integer > realmaxsize)
-			Cvar_SetValue("gl_max_size", realmaxsize);
-		// calculate final size
-		for (width2 = 1;width2 < glt->width;width2 <<= 1);
-		for (height2 = 1;height2 < glt->height;height2 <<= 1);
-		for (depth2 = 1;depth2 < glt->depth;depth2 <<= 1);
-		for (width2 >>= picmip;width2 > gl_max_size.integer;width2 >>= 1);
-		for (height2 >>= picmip;height2 > gl_max_size.integer;height2 >>= 1);
-		for (depth2 >>= picmip;depth2 > gl_max_size.integer;depth2 >>= 1);
-		if (width2 < 1) width2 = 1;
-		if (height2 < 1) height2 = 1;
-		if (depth2 < 1) depth2 = 1;
-
-		size = 0;
-		if (glt->flags & TEXF_MIPMAP)
+		while (width2 > 1 || height2 > 1 || depth2 > 1)
 		{
-			while (width2 > 1 || height2 > 1 || depth2 > 1)
-			{
-				size += width2 * height2 * depth2;
-				if (width2 > 1)
-					width2 >>= 1;
-				if (height2 > 1)
-					height2 >>= 1;
-				if (depth2 > 1)
-					depth2 >>= 1;
-			}
-			size++; // count the last 1x1 mipmap
+			if (width2 > 1)
+				width2 >>= 1;
+			if (height2 > 1)
+				height2 >>= 1;
+			if (depth2 > 1)
+				depth2 >>= 1;
+			size += width2 * height2 * depth2;
 		}
-		else
-			size = width2 * height2 * depth2;
 	}
-	size *= glt->textype->internalbytesperpixel * glt->image->sides;
 
-	return size;
+	return size * glt->textype->internalbytesperpixel * glt->image->sides;
 }
 
 void R_TextureStats_Print(qboolean printeach, qboolean printpool, qboolean printtotal)
@@ -465,15 +494,12 @@ static void R_TextureStats_f(void)
 
 static void r_textures_start(void)
 {
-	// deal with size limits of various drivers (3dfx in particular)
-	qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &realmaxsize);
-	CHECKGLERROR
 	// LordHavoc: allow any alignment
 	qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 	CHECKGLERROR
 
 	// use the largest scrap texture size we can (not sure if this is really a good idea)
-	for (block_size = 1;block_size < realmaxsize && block_size < gl_max_scrapsize.integer;block_size <<= 1);
+	for (block_size = 1;block_size * 2 <= gl_max_texture_size && block_size * 2 <= gl_max_scrapsize.integer;block_size *= 2);
 
 	texturemempool = Mem_AllocPool("texture management", 0, NULL);
 
@@ -865,7 +891,7 @@ static void R_Upload(gltexture_t *glt, unsigned char *data)
 
 static void R_FindImageForTexture(gltexture_t *glt)
 {
-	int i, j, best, best2, x, y, z, w, h, d, picmip;
+	int i, j, best, best2, x, y, z, w, h, d;
 	textypeinfo_t *texinfo;
 	gltexturepool_t *pool;
 	gltextureimage_t *image, **imagechainpointer;
@@ -966,21 +992,7 @@ static void R_FindImageForTexture(gltexture_t *glt)
 		image->type = GLIMAGETYPE_TILE;
 		image->blockallocation = NULL;
 
-		picmip = 0;
-		if (glt->flags & TEXF_PICMIP)
-			picmip = gl_picmip.integer;
-		// calculate final size
-		if (gl_max_size.integer > realmaxsize)
-			Cvar_SetValue("gl_max_size", realmaxsize);
-		for (image->width = 1;image->width < glt->width;image->width <<= 1);
-		for (image->height = 1;image->height < glt->height;image->height <<= 1);
-		for (image->depth = 1;image->depth < glt->depth;image->depth <<= 1);
-		for (image->width >>= picmip;image->width > gl_max_size.integer;image->width >>= 1);
-		for (image->height >>= picmip;image->height > gl_max_size.integer;image->height >>= 1);
-		for (image->depth >>= picmip;image->depth > gl_max_size.integer;image->depth >>= 1);
-		if (image->width < 1) image->width = 1;
-		if (image->height < 1) image->height = 1;
-		if (image->depth < 1) image->depth = 1;
+		GL_Texture_CalcImageSize(glt->texturetype, glt->flags, glt->width, glt->height, glt->depth, &image->width, &image->height, &image->depth);
 	}
 	image->texturetype = glt->texturetype;
 	image->glinternalformat = texinfo->glinternalformat;
diff --git a/glquake.h b/glquake.h
index 20f2b6d0..764fe465 100644
--- a/glquake.h
+++ b/glquake.h
@@ -224,6 +224,8 @@ extern int gl_max_anisotropy;
 #define GL_POLYGON_SMOOTH                       0x0B41
 #endif
 
+extern int gl_max_texture_size;
+
 // GL_ARB_multitexture
 extern int gl_textureunits;
 extern void (GLAPIENTRY *qglMultiTexCoord1f) (GLenum, GLfloat);
@@ -322,6 +324,7 @@ extern int gl_textureshader;
 #endif
 
 extern int gl_texture3d;
+extern int gl_max_3d_texture_size;
 #ifndef GL_TEXTURE_3D
 #define GL_PACK_SKIP_IMAGES			0x806B
 #define GL_PACK_IMAGE_HEIGHT			0x806C
@@ -339,6 +342,7 @@ extern void (GLAPIENTRY *qglCopyTexSubImage3D)(GLenum target, GLint level, GLint
 #endif
 
 extern int gl_texturecubemap;
+extern int gl_max_cube_map_texture_size;
 #ifndef GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
 #define GL_NORMAL_MAP_ARB			    0x8511
 #define GL_REFLECTION_MAP_ARB		    0x8512
diff --git a/r_textures.h b/r_textures.h
index 44d574ea..6a0c46bf 100644
--- a/r_textures.h
+++ b/r_textures.h
@@ -19,7 +19,7 @@
 #define TEXF_FORCENEAREST 0x00000040
 // indicates texture should be uploaded using GL_LINEAR or GL_LINEAR_MIPMAP_NEAREST or GL_LINEAR_MIPMAP_LINEAR mode
 #define TEXF_FORCELINEAR 0x00000080
-// indicates texture should be affected by gl_picmip
+// indicates texture should be affected by gl_picmip and gl_max_size cvar
 #define TEXF_PICMIP 0x00000100
 // used for checking if textures mismatch
 #define TEXF_IMPORTANTBITS (TEXF_ALPHA | TEXF_MIPMAP | TEXF_FRAGMENT | TEXF_CLAMP | TEXF_FORCENEAREST | TEXF_FORCELINEAR | TEXF_PICMIP)
diff --git a/vid_shared.c b/vid_shared.c
index f9621dc3..75c7c2cc 100644
--- a/vid_shared.c
+++ b/vid_shared.c
@@ -15,6 +15,10 @@ qboolean in_client_mouse = true;
 // AK where should it be placed ?
 float in_mouse_x, in_mouse_y;
 
+// value of GL_MAX_TEXTURE_<various>_SIZE
+int gl_max_texture_size = 0;
+int gl_max_3d_texture_size = 0;
+int gl_max_cube_map_texture_size = 0;
 // GL_ARB_multitexture
 int gl_textureunits = 1;
 // GL_ARB_texture_env_combine or GL_EXT_texture_env_combine
@@ -608,6 +612,9 @@ void VID_CheckExtensions(void)
 
 	// reset all the gl extension variables here
 	// this should match the declarations
+	gl_max_texture_size = 0;
+	gl_max_3d_texture_size = 0;
+	gl_max_cube_map_texture_size = 0;
 	gl_textureunits = 1;
 	gl_combine_extension = false;
 	gl_supportslockarrays = false;
@@ -633,6 +640,8 @@ void VID_CheckExtensions(void)
 	Con_Printf("GL_EXTENSIONS: %s\n", gl_extensions);
 	Con_Printf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
 
+	qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl_max_texture_size);
+
 	Con_Print("Checking OpenGL extensions...\n");
 
 // COMMANDLINEOPTION: GL: -nodrawrangeelements disables GL_EXT_draw_range_elements (renders faster)
@@ -651,9 +660,11 @@ void VID_CheckExtensions(void)
 	}
 
 // COMMANDLINEOPTION: GL: -notexture3d disables GL_EXT_texture3D (required for spherical lights, otherwise they render as a column)
-	gl_texture3d = GL_CheckExtension("GL_EXT_texture3D", texture3dextfuncs, "-notexture3d", false);
+	if ((gl_texture3d = GL_CheckExtension("GL_EXT_texture3D", texture3dextfuncs, "-notexture3d", false)))
+		qglGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &gl_max_3d_texture_size);
 // COMMANDLINEOPTION: GL: -nocubemap disables GL_ARB_texture_cube_map (required for bumpmapping)
-	gl_texturecubemap = GL_CheckExtension("GL_ARB_texture_cube_map", NULL, "-nocubemap", false);
+	if ((gl_texturecubemap = GL_CheckExtension("GL_ARB_texture_cube_map", NULL, "-nocubemap", false)))
+		qglGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &gl_max_cube_map_texture_size);
 // COMMANDLINEOPTION: GL: -nocva disables GL_EXT_compiled_vertex_array (renders faster)
 	gl_supportslockarrays = GL_CheckExtension("GL_EXT_compiled_vertex_array", compiledvertexarrayfuncs, "-nocva", false);
 // COMMANDLINEOPTION: GL: -noedgeclamp disables GL_EXT_texture_edge_clamp or GL_SGIS_texture_edge_clamp (recommended, some cards do not support the other texture clamp method)
-- 
2.39.5