1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2013 - 2015, OpenJK contributors
7 
8 This file is part of the OpenJK source code.
9 
10 OpenJK is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 ===========================================================================
22 */
23 
24 // tr_image.c
25 #include "tr_local.h"
26 #include "../rd-common/tr_common.h"
27 #include "glext.h"
28 
29 #include <map>
30 
31 static byte			 s_intensitytable[256];
32 static unsigned char s_gammatable[256];
33 
34 int		gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
35 int		gl_filter_max = GL_LINEAR;
36 
37 //#define FILE_HASH_SIZE		1024	// actually the shader code still needs this (from another module, great),
38 //static	image_t*		hashTable[FILE_HASH_SIZE];
39 
40 /*
41 ** R_GammaCorrect
42 */
R_GammaCorrect(byte * buffer,int bufSize)43 void R_GammaCorrect( byte *buffer, int bufSize ) {
44 	int i;
45 
46 	for ( i = 0; i < bufSize; i++ ) {
47 		buffer[i] = s_gammatable[buffer[i]];
48 	}
49 }
50 
51 typedef struct textureMode_s {
52 	const char *name;
53 	int	minimize, maximize;
54 } textureMode_t;
55 
56 textureMode_t modes[] = {
57 	{"GL_NEAREST", GL_NEAREST, GL_NEAREST},
58 	{"GL_LINEAR", GL_LINEAR, GL_LINEAR},
59 	{"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
60 	{"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
61 	{"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
62 	{"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
63 };
64 
65 static const size_t numTextureModes = ARRAY_LEN(modes);
66 
67 /*
68 ===============
69 GL_TextureMode
70 ===============
71 */
GL_TextureMode(const char * string)72 void GL_TextureMode( const char *string ) {
73 	size_t	i;
74 	image_t	*glt;
75 
76 	for ( i = 0; i < numTextureModes ; i++ ) {
77 		if ( !Q_stricmp( modes[i].name, string ) ) {
78 			break;
79 		}
80 	}
81 
82 	if ( i == numTextureModes ) {
83 		ri.Printf( PRINT_ALL, "bad filter name\n" );
84 		for ( i = 0; i < numTextureModes ; i++ ) {
85 			ri.Printf( PRINT_ALL, "%s\n", modes[i].name );
86 		}
87 		return;
88 	}
89 
90 	gl_filter_min = modes[i].minimize;
91 	gl_filter_max = modes[i].maximize;
92 
93 	// If the level they requested is less than possible, set the max possible...
94 	if ( r_ext_texture_filter_anisotropic->value > glConfig.maxTextureFilterAnisotropy )
95 		ri.Cvar_SetValue( "r_ext_texture_filter_anisotropic", glConfig.maxTextureFilterAnisotropy );
96 
97 	// change all the existing mipmap texture objects
98 					 R_Images_StartIteration();
99 	while ( (glt   = R_Images_GetNextIteration()) != NULL)
100 	{
101 		if ( glt->mipmap ) {
102 			GL_Bind (glt);
103 			qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
104 			qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
105 
106 			if(glConfig.maxTextureFilterAnisotropy>0) {
107 				if(r_ext_texture_filter_anisotropic->integer>1) {
108 					qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, r_ext_texture_filter_anisotropic->value);
109 				} else {
110 					qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
111 				}
112 			}
113 		}
114 	}
115 }
116 
117 // makeup a nice clean, consistant name to query for and file under, for map<> usage...
118 //
GenerateImageMappingName(const char * name)119 static char *GenerateImageMappingName( const char *name )
120 {
121 	static char sName[MAX_QPATH];
122 	int		i=0;
123 	char	letter;
124 
125 	while (name[i] != '\0' && i<MAX_QPATH-1)
126 	{
127 		letter = tolower((unsigned char)name[i]);
128 		if (letter =='.') break;				// don't include extension
129 		if (letter =='\\') letter = '/';		// damn path names
130 		sName[i++] = letter;
131 	}
132 	sName[i]=0;
133 
134 	return &sName[0];
135 }
136 
R_BytesPerTex(int format)137 static float R_BytesPerTex (int format)
138 {
139 	switch ( format ) {
140 	case 1:
141 		//"I    "
142 		return 1;
143 		break;
144 	case 2:
145 		//"IA   "
146 		return 2;
147 		break;
148 	case 3:
149 		//"RGB  "
150 		return glConfig.colorBits/8.0f;
151 		break;
152 	case 4:
153 		//"RGBA "
154 		return glConfig.colorBits/8.0f;
155 		break;
156 
157 	case GL_RGBA4:
158 		//"RGBA4"
159 		return 2;
160 		break;
161 	case GL_RGB5:
162 		//"RGB5 "
163 		return 2;
164 		break;
165 
166 	case GL_RGBA8:
167 		//"RGBA8"
168 		return 4;
169 		break;
170 	case GL_RGB8:
171 		//"RGB8"
172 		return 4;
173 		break;
174 
175 	case GL_RGB4_S3TC:
176 		//"S3TC "
177 		return 0.33333f;
178 		break;
179 	case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
180 		//"DXT1 "
181 		return 0.33333f;
182 		break;
183 	case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
184 		//"DXT5 "
185 		return 1;
186 		break;
187 	default:
188 		//"???? "
189 		return 4;
190 	}
191 }
192 
193 /*
194 ===============
195 R_SumOfUsedImages
196 ===============
197 */
R_SumOfUsedImages(qboolean bUseFormat)198 float R_SumOfUsedImages( qboolean bUseFormat )
199 {
200 	int	total = 0;
201 	image_t *pImage;
202 
203 					  R_Images_StartIteration();
204 	while ( (pImage = R_Images_GetNextIteration()) != NULL)
205 	{
206 		if ( pImage->frameUsed == tr.frameCount- 1 ) {//it has already been advanced for the next frame, so...
207 			if (bUseFormat)
208 			{
209 				float  bytePerTex = R_BytesPerTex (pImage->internalFormat);
210 				total += bytePerTex * (pImage->width * pImage->height);
211 			}
212 			else
213 			{
214 				total += pImage->width * pImage->height;
215 			}
216 		}
217 	}
218 
219 	return total;
220 }
221 
222 /*
223 ===============
224 R_ImageList_f
225 ===============
226 */
R_ImageList_f(void)227 void R_ImageList_f( void ) {
228 	int		i=0;
229 	image_t	*image;
230 	int		texels=0;
231 	float	texBytes = 0.0f;
232 	const char *yesno[] = {"no ", "yes"};
233 
234 	ri.Printf( PRINT_ALL,  "\n      -w-- -h-- -mm- -if-- wrap --name-------\n");
235 
236 	int iNumImages = R_Images_StartIteration();
237 	while ( (image = R_Images_GetNextIteration()) != NULL)
238 	{
239 		texels   += image->width*image->height;
240 		texBytes += image->width*image->height * R_BytesPerTex (image->internalFormat);
241 		ri.Printf( PRINT_ALL,   "%4i: %4i %4i  %s ",
242 			i, image->width, image->height, yesno[image->mipmap] );
243 		switch ( image->internalFormat ) {
244 		case 1:
245 			ri.Printf( PRINT_ALL, "I    " );
246 			break;
247 		case 2:
248 			ri.Printf( PRINT_ALL, "IA   " );
249 			break;
250 		case 3:
251 			ri.Printf( PRINT_ALL, "RGB  " );
252 			break;
253 		case 4:
254 			ri.Printf( PRINT_ALL, "RGBA " );
255 			break;
256 		case GL_RGBA8:
257 			ri.Printf( PRINT_ALL, "RGBA8" );
258 			break;
259 		case GL_RGB8:
260 			ri.Printf( PRINT_ALL, "RGB8" );
261 			break;
262 		case GL_RGB4_S3TC:
263 			ri.Printf( PRINT_ALL, "S3TC " );
264 			break;
265 		case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
266 			ri.Printf( PRINT_ALL, "DXT1 " );
267 			break;
268 		case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
269 			ri.Printf( PRINT_ALL, "DXT5 " );
270 			break;
271 		case GL_RGBA4:
272 			ri.Printf( PRINT_ALL, "RGBA4" );
273 			break;
274 		case GL_RGB5:
275 			ri.Printf( PRINT_ALL, "RGB5 " );
276 			break;
277 		default:
278 			ri.Printf( PRINT_ALL, "???? " );
279 		}
280 
281 		switch ( image->wrapClampMode ) {
282 		case GL_REPEAT:
283 			ri.Printf( PRINT_ALL, "rept " );
284 			break;
285 		case GL_CLAMP:
286 			ri.Printf( PRINT_ALL, "clmp " );
287 			break;
288 		case GL_CLAMP_TO_EDGE:
289 			ri.Printf( PRINT_ALL, "clpE " );
290 			break;
291 		default:
292 			ri.Printf( PRINT_ALL, "%4i ", image->wrapClampMode );
293 			break;
294 		}
295 
296 		ri.Printf( PRINT_ALL, "%s\n", image->imgName );
297 		i++;
298 	}
299 	ri.Printf( PRINT_ALL,  " ---------\n");
300 	ri.Printf( PRINT_ALL,  "      -w-- -h-- -mm- -if- wrap --name-------\n");
301 	ri.Printf( PRINT_ALL,  " %i total texels (not including mipmaps)\n", texels );
302 	ri.Printf( PRINT_ALL,  " %.2fMB total texture mem (not including mipmaps)\n", texBytes/1048576.0f );
303 	ri.Printf( PRINT_ALL,  " %i total images\n\n", iNumImages );
304 }
305 
306 //=======================================================================
307 
308 
309 /*
310 ================
311 R_LightScaleTexture
312 
313 Scale up the pixel values in a texture to increase the
314 lighting range
315 ================
316 */
R_LightScaleTexture(unsigned * in,int inwidth,int inheight,qboolean only_gamma)317 void R_LightScaleTexture (unsigned *in, int inwidth, int inheight, qboolean only_gamma )
318 {
319 	if ( only_gamma )
320 	{
321 		if ( !glConfig.deviceSupportsGamma && !glConfigExt.doGammaCorrectionWithShaders )
322 		{
323 			int		i, c;
324 			byte	*p;
325 
326 			p = (byte *)in;
327 
328 			c = inwidth*inheight;
329 			for (i=0 ; i<c ; i++, p+=4)
330 			{
331 				p[0] = s_gammatable[p[0]];
332 				p[1] = s_gammatable[p[1]];
333 				p[2] = s_gammatable[p[2]];
334 			}
335 		}
336 	}
337 	else
338 	{
339 		int		i, c;
340 		byte	*p;
341 
342 		p = (byte *)in;
343 
344 		c = inwidth*inheight;
345 
346 		if ( glConfig.deviceSupportsGamma || glConfigExt.doGammaCorrectionWithShaders )
347 		{
348 			for (i=0 ; i<c ; i++, p+=4)
349 			{
350 				p[0] = s_intensitytable[p[0]];
351 				p[1] = s_intensitytable[p[1]];
352 				p[2] = s_intensitytable[p[2]];
353 			}
354 		}
355 		else
356 		{
357 			for (i=0 ; i<c ; i++, p+=4)
358 			{
359 				p[0] = s_gammatable[s_intensitytable[p[0]]];
360 				p[1] = s_gammatable[s_intensitytable[p[1]]];
361 				p[2] = s_gammatable[s_intensitytable[p[2]]];
362 			}
363 		}
364 	}
365 }
366 
367 
368 /*
369 ================
370 R_MipMap2
371 
372 Operates in place, quartering the size of the texture
373 Proper linear filter
374 ================
375 */
R_MipMap2(unsigned * in,int inWidth,int inHeight)376 static void R_MipMap2( unsigned *in, int inWidth, int inHeight ) {
377 	int			i, j, k;
378 	byte		*outpix;
379 	int			inWidthMask, inHeightMask;
380 	int			total;
381 	int			outWidth, outHeight;
382 	unsigned	*temp;
383 
384 	outWidth = inWidth >> 1;
385 	outHeight = inHeight >> 1;
386 	temp = (unsigned int *)Hunk_AllocateTempMemory( outWidth * outHeight * 4 );
387 
388 	inWidthMask = inWidth - 1;
389 	inHeightMask = inHeight - 1;
390 
391 	for ( i = 0 ; i < outHeight ; i++ ) {
392 		for ( j = 0 ; j < outWidth ; j++ ) {
393 			outpix = (byte *) ( temp + i * outWidth + j );
394 			for ( k = 0 ; k < 4 ; k++ ) {
395 				total =
396 					1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
397 					2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
398 					2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
399 					1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
400 
401 					2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
402 					4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
403 					4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
404 					2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
405 
406 					2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
407 					4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
408 					4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
409 					2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
410 
411 					1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
412 					2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
413 					2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
414 					1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k];
415 				outpix[k] = total / 36;
416 			}
417 		}
418 	}
419 
420 	memcpy( in, temp, outWidth * outHeight * 4 );
421 	Hunk_FreeTempMemory( temp );
422 }
423 
424 /*
425 ================
426 R_MipMap
427 
428 Operates in place, quartering the size of the texture
429 ================
430 */
R_MipMap(byte * in,int width,int height)431 static void R_MipMap (byte *in, int width, int height) {
432 	int		i, j;
433 	byte	*out;
434 	int		row;
435 
436 	if ( !r_simpleMipMaps->integer ) {
437 		R_MipMap2( (unsigned *)in, width, height );
438 		return;
439 	}
440 
441 	if ( width == 1 && height == 1 ) {
442 		return;
443 	}
444 
445 	row = width * 4;
446 	out = in;
447 	width >>= 1;
448 	height >>= 1;
449 
450 	if ( width == 0 || height == 0 ) {
451 		width += height;	// get largest
452 		for (i=0 ; i<width ; i++, out+=4, in+=8 ) {
453 			out[0] = ( in[0] + in[4] )>>1;
454 			out[1] = ( in[1] + in[5] )>>1;
455 			out[2] = ( in[2] + in[6] )>>1;
456 			out[3] = ( in[3] + in[7] )>>1;
457 		}
458 		return;
459 	}
460 
461 	for (i=0 ; i<height ; i++, in+=row) {
462 		for (j=0 ; j<width ; j++, out+=4, in+=8) {
463 			out[0] = (in[0] + in[4] + in[row+0] + in[row+4])>>2;
464 			out[1] = (in[1] + in[5] + in[row+1] + in[row+5])>>2;
465 			out[2] = (in[2] + in[6] + in[row+2] + in[row+6])>>2;
466 			out[3] = (in[3] + in[7] + in[row+3] + in[row+7])>>2;
467 		}
468 	}
469 }
470 
471 
472 /*
473 ==================
474 R_BlendOverTexture
475 
476 Apply a color blend over a set of pixels
477 ==================
478 */
R_BlendOverTexture(byte * data,int pixelCount,byte blend[4])479 static void R_BlendOverTexture( byte *data, int pixelCount, byte blend[4] ) {
480 	int		i;
481 	int		inverseAlpha;
482 	int		premult[3];
483 
484 	inverseAlpha = 255 - blend[3];
485 	premult[0] = blend[0] * blend[3];
486 	premult[1] = blend[1] * blend[3];
487 	premult[2] = blend[2] * blend[3];
488 
489 	for ( i = 0 ; i < pixelCount ; i++, data+=4 ) {
490 		data[0] = ( data[0] * inverseAlpha + premult[0] ) >> 9;
491 		data[1] = ( data[1] * inverseAlpha + premult[1] ) >> 9;
492 		data[2] = ( data[2] * inverseAlpha + premult[2] ) >> 9;
493 	}
494 }
495 
496 byte	mipBlendColors[16][4] = {
497 	{0,0,0,0},
498 	{255,0,0,128},
499 	{0,255,0,128},
500 	{0,0,255,128},
501 	{255,0,0,128},
502 	{0,255,0,128},
503 	{0,0,255,128},
504 	{255,0,0,128},
505 	{0,255,0,128},
506 	{0,0,255,128},
507 	{255,0,0,128},
508 	{0,255,0,128},
509 	{0,0,255,128},
510 	{255,0,0,128},
511 	{0,255,0,128},
512 	{0,0,255,128},
513 };
514 
515 
516 
517 
518 
519 class CStringComparator
520 {
521 public:
operator ()(const char * s1,const char * s2) const522 	bool operator()(const char *s1, const char *s2) const { return(strcmp(s1, s2) < 0); }
523 };
524 
525 typedef std::map <const char *, image_t *, CStringComparator> AllocatedImages_t;
526 AllocatedImages_t AllocatedImages;
527 AllocatedImages_t::iterator itAllocatedImages;
528 int giTextureBindNum = 1024;	// will be set to this anyway at runtime, but wtf?
529 
530 
531 // return = number of images in the list, for those interested
532 //
R_Images_StartIteration(void)533 int R_Images_StartIteration(void)
534 {
535 	itAllocatedImages = AllocatedImages.begin();
536 	return AllocatedImages.size();
537 }
538 
R_Images_GetNextIteration(void)539 image_t *R_Images_GetNextIteration(void)
540 {
541 	if (itAllocatedImages == AllocatedImages.end())
542 		return NULL;
543 
544 	image_t *pImage = (*itAllocatedImages).second;
545 	++itAllocatedImages;
546 	return pImage;
547 }
548 
549 // clean up anything to do with an image_t struct, but caller will have to clear the internal to an image_t struct ready for either struct free() or overwrite...
550 //
551 // (avoid using ri->xxxx stuff here in case running on dedicated)
552 //
R_Images_DeleteImageContents(image_t * pImage)553 static void R_Images_DeleteImageContents( image_t *pImage )
554 {
555 	assert(pImage);	// should never be called with NULL
556 	if (pImage)
557 	{
558 		qglDeleteTextures( 1, &pImage->texnum );
559 		Z_Free(pImage);
560 	}
561 }
562 
563 
564 
565 
566 
567 /*
568 ===============
569 Upload32
570 
571 ===============
572 */
Upload32(unsigned * data,GLenum format,qboolean mipmap,qboolean picmip,qboolean isLightmap,qboolean allowTC,int * pformat,word * pUploadWidth,word * pUploadHeight,bool bRectangle=false)573 static void Upload32( unsigned *data,
574 						 GLenum format,
575 						 qboolean mipmap,
576 						 qboolean picmip,
577 						 qboolean isLightmap,
578 						 qboolean allowTC,
579 						 int *pformat,
580 						 word *pUploadWidth, word *pUploadHeight, bool bRectangle = false )
581 {
582 	GLuint uiTarget = GL_TEXTURE_2D;
583 	if ( bRectangle )
584 	{
585 		uiTarget = GL_TEXTURE_RECTANGLE_ARB;
586 	}
587 
588 	if (format == GL_RGBA)
589 	{
590 		int			samples;
591 		int			i, c;
592 		byte		*scan;
593 		float		rMax = 0, gMax = 0, bMax = 0;
594 		int			width = *pUploadWidth;
595 		int			height = *pUploadHeight;
596 
597 		//
598 		// perform optional picmip operation
599 		//
600 		if ( picmip ) {
601 			for(i = 0; i < r_picmip->integer; i++) {
602 				R_MipMap( (byte *)data, width, height );
603 				width >>= 1;
604 				height >>= 1;
605 				if (width < 1) {
606 					width = 1;
607 				}
608 				if (height < 1) {
609 					height = 1;
610 				}
611 			}
612 		}
613 
614 		//
615 		// clamp to the current upper OpenGL limit
616 		// scale both axis down equally so we don't have to
617 		// deal with a half mip resampling
618 		//
619 		while ( width > glConfig.maxTextureSize	|| height > glConfig.maxTextureSize ) {
620 			R_MipMap( (byte *)data, width, height );
621 			width >>= 1;
622 			height >>= 1;
623 		}
624 
625 		//
626 		// scan the texture for each channel's max values
627 		// and verify if the alpha channel is being used or not
628 		//
629 		c = width*height;
630 		scan = ((byte *)data);
631 		samples = 3;
632 		for ( i = 0; i < c; i++ )
633 		{
634 			if ( scan[i*4+0] > rMax )
635 			{
636 				rMax = scan[i*4+0];
637 			}
638 			if ( scan[i*4+1] > gMax )
639 			{
640 				gMax = scan[i*4+1];
641 			}
642 			if ( scan[i*4+2] > bMax )
643 			{
644 				bMax = scan[i*4+2];
645 			}
646 			if ( scan[i*4 + 3] != 255 )
647 			{
648 				samples = 4;
649 				break;
650 			}
651 		}
652 
653 		// select proper internal format
654 		if ( samples == 3 )
655 		{
656 			if ( glConfig.textureCompression == TC_S3TC && allowTC )
657 			{
658 				*pformat = GL_RGB4_S3TC;
659 			}
660 			else if ( glConfig.textureCompression == TC_S3TC_DXT && allowTC )
661 			{	// Compress purely color - no alpha
662 				if ( r_texturebits->integer == 16 ) {
663 					*pformat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;	//this format cuts to 16 bit
664 				}
665 				else {//if we aren't using 16 bit then, use 32 bit compression
666 					*pformat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
667 				}
668 			}
669 			else if ( isLightmap && r_texturebitslm->integer > 0 )
670 			{
671 				int lmBits = r_texturebitslm->integer & 0x30; // 16 or 32
672 				// Allow different bit depth when we are a lightmap
673 				if ( lmBits == 16 )
674 					*pformat = GL_RGB5;
675 				else
676 					*pformat = GL_RGB8;
677 			}
678 			else if ( r_texturebits->integer == 16 )
679 			{
680 				*pformat = GL_RGB5;
681 			}
682 			else if ( r_texturebits->integer == 32 )
683 			{
684 				*pformat = GL_RGB8;
685 			}
686 			else
687 			{
688 				*pformat = 3;
689 			}
690 		}
691 		else if ( samples == 4 )
692 		{
693 			if ( glConfig.textureCompression == TC_S3TC_DXT && allowTC)
694 			{	// Compress both alpha and color
695 				*pformat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
696 			}
697 			else if ( r_texturebits->integer == 16 )
698 			{
699 				*pformat = GL_RGBA4;
700 			}
701 			else if ( r_texturebits->integer == 32 )
702 			{
703 				*pformat = GL_RGBA8;
704 			}
705 			else
706 			{
707 				*pformat = 4;
708 			}
709 		}
710 
711 		*pUploadWidth = width;
712 		*pUploadHeight = height;
713 
714 		// copy or resample data as appropriate for first MIP level
715 		if (!mipmap)
716 		{
717 			qglTexImage2D( uiTarget, 0, *pformat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
718 			goto done;
719 		}
720 
721 		R_LightScaleTexture (data, width, height, (qboolean)!mipmap );
722 
723 		qglTexImage2D( uiTarget, 0, *pformat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
724 
725 		if (mipmap)
726 		{
727 			int		miplevel;
728 
729 			miplevel = 0;
730 			while (width > 1 || height > 1)
731 			{
732 				R_MipMap( (byte *)data, width, height );
733 				width >>= 1;
734 				height >>= 1;
735 				if (width < 1)
736 					width = 1;
737 				if (height < 1)
738 					height = 1;
739 				miplevel++;
740 
741 				if ( r_colorMipLevels->integer )
742 				{
743 					R_BlendOverTexture( (byte *)data, width * height, mipBlendColors[miplevel] );
744 				}
745 
746 				qglTexImage2D( uiTarget, miplevel, *pformat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
747 			}
748 		}
749 	}
750 	else
751 	{
752 	}
753 
754 done:
755 
756 	if (mipmap)
757 	{
758 		qglTexParameterf(uiTarget, GL_TEXTURE_MIN_FILTER, gl_filter_min);
759 		qglTexParameterf(uiTarget, GL_TEXTURE_MAG_FILTER, gl_filter_max);
760 		if(r_ext_texture_filter_anisotropic->integer>1 && glConfig.maxTextureFilterAnisotropy>0)
761 		{
762 			qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, r_ext_texture_filter_anisotropic->value );
763 		}
764 	}
765 	else
766 	{
767 		qglTexParameterf(uiTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
768 		qglTexParameterf(uiTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
769 	}
770 
771 	GL_CheckErrors();
772 }
773 
GL_ResetBinds(void)774 static void GL_ResetBinds(void)
775 {
776 	memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) );
777 	if ( qglActiveTextureARB ) {
778 		GL_SelectTexture( 1 );
779 		qglBindTexture( GL_TEXTURE_2D, 0 );
780 		GL_SelectTexture( 0 );
781 		qglBindTexture( GL_TEXTURE_2D, 0 );
782 	} else {
783 		qglBindTexture( GL_TEXTURE_2D, 0 );
784 	}
785 }
786 
787 
788 // special function used in conjunction with "devmapbsp"...
789 //
790 // (avoid using ri->xxxx stuff here in case running on dedicated)
791 //
R_Images_DeleteLightMaps(void)792 void R_Images_DeleteLightMaps(void)
793 {
794 	for (AllocatedImages_t::iterator itImage = AllocatedImages.begin(); itImage != AllocatedImages.end(); /* empty */)
795 	{
796 		image_t *pImage = (*itImage).second;
797 
798 		if (pImage->imgName[0] == '*' && strstr(pImage->imgName,"lightmap"))	// loose check, but should be ok
799 		{
800 			R_Images_DeleteImageContents(pImage);
801 
802 			AllocatedImages.erase(itImage++);
803 		}
804 		else
805 		{
806 			++itImage;
807 		}
808 	}
809 
810 	GL_ResetBinds();
811 }
812 
813 // special function currently only called by Dissolve code...
814 //
R_Images_DeleteImage(image_t * pImage)815 void R_Images_DeleteImage(image_t *pImage)
816 {
817 	// Even though we supply the image handle, we need to get the corresponding iterator entry...
818 	//
819 	AllocatedImages_t::iterator itImage = AllocatedImages.find(pImage->imgName);
820 	if (itImage != AllocatedImages.end())
821 	{
822 		R_Images_DeleteImageContents(pImage);
823 		AllocatedImages.erase(itImage);
824 	}
825 	else
826 	{
827 		assert(0);
828 	}
829 }
830 
831 // called only at app startup, vid_restart, app-exit
832 //
R_Images_Clear(void)833 void R_Images_Clear(void)
834 {
835 	image_t *pImage;
836 	//	int iNumImages =
837 					  R_Images_StartIteration();
838 	while ( (pImage = R_Images_GetNextIteration()) != NULL)
839 	{
840 		R_Images_DeleteImageContents(pImage);
841 	}
842 
843 	AllocatedImages.clear();
844 
845 	giTextureBindNum = 1024;
846 }
847 
848 
RE_RegisterImages_Info_f(void)849 void RE_RegisterImages_Info_f( void )
850 {
851 	image_t *pImage	= NULL;
852 	int iImage		= 0;
853 	int iTexels		= 0;
854 
855 	int iNumImages	= R_Images_StartIteration();
856 	while ( (pImage	= R_Images_GetNextIteration()) != NULL)
857 	{
858 		ri.Printf( PRINT_ALL, "%d: (%4dx%4dy) \"%s\"",iImage, pImage->width, pImage->height, pImage->imgName);
859 		ri.Printf( PRINT_DEVELOPER, S_COLOR_RED ", levused %d",pImage->iLastLevelUsedOn);
860 		ri.Printf( PRINT_ALL, "\n");
861 
862 		iTexels += pImage->width * pImage->height;
863 		iImage++;
864 	}
865 	ri.Printf( PRINT_ALL, "%d Images. %d (%.2fMB) texels total, (not including mipmaps)\n",iNumImages, iTexels, (float)iTexels / 1024.0f / 1024.0f);
866 	ri.Printf( PRINT_DEVELOPER, S_COLOR_RED "RE_RegisterMedia_GetLevel(): %d",RE_RegisterMedia_GetLevel());
867 }
868 
869 // currently, this just goes through all the images and dumps any not referenced on this level...
870 //
RE_RegisterImages_LevelLoadEnd(void)871 qboolean RE_RegisterImages_LevelLoadEnd(void)
872 {
873 	ri.Printf( PRINT_DEVELOPER, S_COLOR_RED "RE_RegisterImages_LevelLoadEnd():\n");
874 
875 //	int iNumImages = AllocatedImages.size();	// more for curiosity, really.
876 
877 	qboolean imageDeleted = qtrue;
878 	for (AllocatedImages_t::iterator itImage = AllocatedImages.begin(); itImage != AllocatedImages.end(); /* blank */)
879 	{
880 		qboolean bEraseOccured = qfalse;
881 
882 		image_t *pImage = (*itImage).second;
883 
884 		// don't un-register system shaders (*fog, *dlight, *white, *default), but DO de-register lightmaps ("*<mapname>/lightmap%d")
885 		if (pImage->imgName[0] != '*' || strchr(pImage->imgName,'/'))
886 		{
887 			// image used on this level?
888 			//
889 			if ( pImage->iLastLevelUsedOn != RE_RegisterMedia_GetLevel() )
890 			{
891 				// nope, so dump it...
892 				//
893 				ri.Printf( PRINT_DEVELOPER, S_COLOR_RED "Dumping image \"%s\"\n",pImage->imgName);
894 
895 				R_Images_DeleteImageContents(pImage);
896 
897 				AllocatedImages.erase(itImage++);
898 				bEraseOccured = qtrue;
899 				imageDeleted = qtrue;
900 			}
901 		}
902 
903 		if ( !bEraseOccured )
904 		{
905 			++itImage;
906 		}
907 	}
908 
909 
910 	// this check can be deleted AFAIC, it seems to be just a quake thing...
911 	//
912 //	iNumImages = R_Images_StartIteration();
913 //	if (iNumImages > MAX_DRAWIMAGES)
914 //	{
915 //		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "Level uses %d images, old limit was MAX_DRAWIMAGES (%d)\n", iNumImages, MAX_DRAWIMAGES);
916 //	}
917 
918 	ri.Printf( PRINT_DEVELOPER, S_COLOR_RED "RE_RegisterImages_LevelLoadEnd(): Ok\n");
919 
920 	GL_ResetBinds();
921 
922 	return imageDeleted;
923 }
924 
925 
926 
927 // returns image_t struct if we already have this, else NULL. No disk-open performed
928 //	(important for creating default images).
929 //
930 // This is called by both R_FindImageFile and anything that creates default images...
931 //
R_FindImageFile_NoLoad(const char * name,qboolean mipmap,qboolean allowPicmip,qboolean allowTC,int glWrapClampMode)932 static image_t *R_FindImageFile_NoLoad(const char *name, qboolean mipmap, qboolean allowPicmip, qboolean allowTC, int glWrapClampMode )
933 {
934 	if (!name) {
935 		return NULL;
936 	}
937 
938 	char *pName = GenerateImageMappingName(name);
939 
940 	//
941 	// see if the image is already loaded
942 	//
943 	AllocatedImages_t::iterator itAllocatedImage = AllocatedImages.find(pName);
944 	if (itAllocatedImage != AllocatedImages.end())
945 	{
946 		image_t *pImage = (*itAllocatedImage).second;
947 
948 		// the white image can be used with any set of parms, but other mismatches are errors...
949 		//
950 		if ( strcmp( pName, "*white" ) ) {
951 			if ( pImage->mipmap != !!mipmap ) {
952 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: reused image %s with mixed mipmap parm\n", pName );
953 			}
954 			if ( pImage->allowPicmip != !!allowPicmip ) {
955 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: reused image %s with mixed allowPicmip parm\n", pName );
956 			}
957 			if ( pImage->wrapClampMode != glWrapClampMode ) {
958 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: reused image %s with mixed glWrapClampMode parm\n", pName );
959 			}
960 		}
961 
962 		pImage->iLastLevelUsedOn = RE_RegisterMedia_GetLevel();
963 
964 		return pImage;
965 	}
966 
967 	return NULL;
968 }
969 
970 
971 
972 /*
973 ================
974 R_CreateImage
975 
976 This is the only way any image_t are created
977 ================
978 */
R_CreateImage(const char * name,const byte * pic,int width,int height,GLenum format,qboolean mipmap,qboolean allowPicmip,qboolean allowTC,int glWrapClampMode,bool bRectangle)979 image_t *R_CreateImage( const char *name, const byte *pic, int width, int height,
980 					   GLenum format, qboolean mipmap, qboolean allowPicmip, qboolean allowTC, int glWrapClampMode, bool bRectangle )
981 {
982 	image_t		*image;
983 	qboolean	isLightmap = qfalse;
984 
985 	if (strlen(name) >= MAX_QPATH ) {
986 		Com_Error (ERR_DROP, "R_CreateImage: \"%s\" is too long\n", name);
987 	}
988 
989 	if(glConfig.clampToEdgeAvailable && glWrapClampMode == GL_CLAMP) {
990 		glWrapClampMode = GL_CLAMP_TO_EDGE;
991 	}
992 
993 	if (name[0] == '*')
994 	{
995 		const char *psLightMapNameSearchPos = strrchr(name,'/');
996 		if (  psLightMapNameSearchPos && !strncmp( psLightMapNameSearchPos+1, "lightmap", 8 ) ) {
997 			isLightmap = qtrue;
998 		}
999 	}
1000 
1001 	if ( (width&(width-1)) || (height&(height-1)) )
1002 	{
1003 		Com_Error( ERR_FATAL, "R_CreateImage: %s dimensions (%i x %i) not power of 2!\n",name,width,height);
1004 	}
1005 
1006 	image = R_FindImageFile_NoLoad(name, mipmap, allowPicmip, allowTC, glWrapClampMode );
1007 	if (image) {
1008 		return image;
1009 	}
1010 
1011 	image = (image_t*) Z_Malloc( sizeof( image_t ), TAG_IMAGE_T, qtrue );
1012 //	memset(image,0,sizeof(*image));	// qtrue above does this
1013 
1014 	image->texnum = 1024 + giTextureBindNum++;	// ++ is of course staggeringly important...
1015 
1016 	// record which map it was used on...
1017 	//
1018 	image->iLastLevelUsedOn = RE_RegisterMedia_GetLevel();
1019 
1020 	image->mipmap = !!mipmap;
1021 	image->allowPicmip = !!allowPicmip;
1022 
1023 	Q_strncpyz(image->imgName, name, sizeof(image->imgName));
1024 
1025 	image->width = width;
1026 	image->height = height;
1027 	image->wrapClampMode = glWrapClampMode;
1028 
1029 	if ( qglActiveTextureARB ) {
1030 		GL_SelectTexture( 0 );
1031 	}
1032 
1033 	GLuint uiTarget = GL_TEXTURE_2D;
1034 	if ( bRectangle )
1035 	{
1036 		qglDisable( uiTarget );
1037 		uiTarget = GL_TEXTURE_RECTANGLE_ARB;
1038 		qglEnable( uiTarget );
1039 		glWrapClampMode = GL_CLAMP_TO_EDGE;	// default mode supported by rectangle.
1040 		qglBindTexture( uiTarget, image->texnum );
1041 	}
1042 	else
1043 	{
1044 		GL_Bind(image);
1045 	}
1046 
1047 	Upload32( (unsigned *)pic,	format,
1048 								(qboolean)image->mipmap,
1049 								allowPicmip,
1050 								isLightmap,
1051 								allowTC,
1052 								&image->internalFormat,
1053 								&image->width,
1054 								&image->height, bRectangle );
1055 
1056 	qglTexParameterf( uiTarget, GL_TEXTURE_WRAP_S, glWrapClampMode );
1057 	qglTexParameterf( uiTarget, GL_TEXTURE_WRAP_T, glWrapClampMode );
1058 
1059 	qglBindTexture( uiTarget, 0 );	//jfm: i don't know why this is here, but it breaks lightmaps when there's only 1
1060 	glState.currenttextures[glState.currenttmu] = 0;	//mark it not bound
1061 
1062 	const char *psNewName = GenerateImageMappingName(name);
1063 	Q_strncpyz(image->imgName, psNewName, sizeof(image->imgName));
1064 	AllocatedImages[ image->imgName ] = image;
1065 
1066 	if ( bRectangle )
1067 	{
1068 		qglDisable( uiTarget );
1069 		qglEnable( GL_TEXTURE_2D );
1070 	}
1071 
1072 	return image;
1073 }
1074 
1075 /*
1076 ===============
1077 R_FindImageFile
1078 
1079 Finds or loads the given image.
1080 Returns NULL if it fails, not a default image.
1081 ==============
1082 */
R_FindImageFile(const char * name,qboolean mipmap,qboolean allowPicmip,qboolean allowTC,int glWrapClampMode)1083 image_t	*R_FindImageFile( const char *name, qboolean mipmap, qboolean allowPicmip, qboolean allowTC, int glWrapClampMode ) {
1084 	image_t	*image;
1085 	int		width, height;
1086 	byte	*pic;
1087 
1088 	if (!name || ri.Cvar_VariableIntegerValue( "dedicated" ) )	// stop ghoul2 horribleness as regards image loading from server
1089 	{
1090 		return NULL;
1091 	}
1092 
1093 	// need to do this here as well as in R_CreateImage, or R_FindImageFile_NoLoad() may complain about
1094 	//	different clamp parms used...
1095 	//
1096 	if(glConfig.clampToEdgeAvailable && glWrapClampMode == GL_CLAMP) {
1097 		glWrapClampMode = GL_CLAMP_TO_EDGE;
1098 	}
1099 
1100 	image = R_FindImageFile_NoLoad(name, mipmap, allowPicmip, allowTC, glWrapClampMode );
1101 	if (image) {
1102 		return image;
1103 	}
1104 
1105 	//
1106 	// load the pic from disk
1107 	//
1108 	R_LoadImage( name, &pic, &width, &height );
1109 	if ( pic == NULL ) {                                    // if we dont get a successful load
1110 		return NULL;                                        // bail
1111 	}
1112 
1113 
1114 	// refuse to find any files not power of 2 dims...
1115 	//
1116 	if ( (width&(width-1)) || (height&(height-1)) )
1117 	{
1118 		ri.Printf( PRINT_ALL, "Refusing to load non-power-2-dims(%d,%d) pic \"%s\"...\n", width,height,name );
1119 		return NULL;
1120 	}
1121 
1122 	image = R_CreateImage( ( char * ) name, pic, width, height, GL_RGBA, mipmap, allowPicmip, allowTC, glWrapClampMode );
1123 	Z_Free( pic );
1124 	return image;
1125 }
1126 
1127 
1128 /*
1129 ================
1130 R_CreateDlightImage
1131 ================
1132 */
1133 #define	DLIGHT_SIZE	16
R_CreateDlightImage(void)1134 static void R_CreateDlightImage( void )
1135 {
1136 	int		width, height;
1137 	byte	*pic;
1138 
1139 	R_LoadImage("gfx/2d/dlight", &pic, &width, &height);
1140 	if (pic)
1141 	{
1142 		tr.dlightImage = R_CreateImage("*dlight", pic, width, height, GL_RGBA, qfalse, qfalse, qfalse, GL_CLAMP );
1143 		Z_Free(pic);
1144 	}
1145 	else
1146 	{	// if we dont get a successful load
1147 		int		x,y;
1148 		byte	data[DLIGHT_SIZE][DLIGHT_SIZE][4];
1149 		int		b;
1150 
1151 		// make a centered inverse-square falloff blob for dynamic lighting
1152 		for (x=0 ; x<DLIGHT_SIZE ; x++) {
1153 			for (y=0 ; y<DLIGHT_SIZE ; y++) {
1154 				float	d;
1155 
1156 				d = ( DLIGHT_SIZE/2 - 0.5f - x ) * ( DLIGHT_SIZE/2 - 0.5f - x ) +
1157 					( DLIGHT_SIZE/2 - 0.5f - y ) * ( DLIGHT_SIZE/2 - 0.5f - y );
1158 				b = 4000 / d;
1159 				if (b > 255) {
1160 					b = 255;
1161 				} else if ( b < 75 ) {
1162 					b = 0;
1163 				}
1164 				data[y][x][0] =
1165 					data[y][x][1] =
1166 					data[y][x][2] = b;
1167 				data[y][x][3] = 255;
1168 			}
1169 		}
1170 		tr.dlightImage = R_CreateImage("*dlight", (byte *)data, DLIGHT_SIZE, DLIGHT_SIZE, GL_RGBA, qfalse, qfalse, qfalse, GL_CLAMP );
1171 	}
1172 }
1173 
1174 
1175 /*
1176 =================
1177 R_InitFogTable
1178 =================
1179 */
R_InitFogTable(void)1180 void R_InitFogTable( void ) {
1181 	int		i;
1182 	float	d;
1183 	float	exp;
1184 
1185 	exp = 0.5;
1186 
1187 	for ( i = 0 ; i < FOG_TABLE_SIZE ; i++ ) {
1188 		d = pow ( (float)i/(FOG_TABLE_SIZE-1), exp );
1189 
1190 		tr.fogTable[i] = d;
1191 	}
1192 }
1193 
1194 /*
1195 ================
1196 R_FogFactor
1197 
1198 Returns a 0.0 to 1.0 fog density value
1199 This is called for each texel of the fog texture on startup
1200 and for each vertex of transparent shaders in fog dynamically
1201 ================
1202 */
R_FogFactor(float s,float t)1203 float	R_FogFactor( float s, float t ) {
1204 	float	d;
1205 
1206 	s -= 1.0/512;
1207 	if ( s < 0 ) {
1208 		return 0;
1209 	}
1210 	if ( t < 1.0/32 ) {
1211 		return 0;
1212 	}
1213 	if ( t < 31.0/32 ) {
1214 		s *= (t - 1.0f/32.0f) / (30.0f/32.0f);
1215 	}
1216 
1217 	// we need to leave a lot of clamp range
1218 	s *= 8;
1219 
1220 	if ( s > 1.0 ) {
1221 		s = 1.0;
1222 	}
1223 
1224 	d = tr.fogTable[ (int)(s * (FOG_TABLE_SIZE-1)) ];
1225 
1226 	return d;
1227 }
1228 
1229 /*
1230 ================
1231 R_CreateFogImage
1232 ================
1233 */
1234 #define	FOG_S	256
1235 #define	FOG_T	32
R_CreateFogImage(void)1236 static void R_CreateFogImage( void ) {
1237 	int		x,y;
1238 	byte	*data;
1239 	float	d;
1240 	float	borderColor[4];
1241 
1242 	data = (unsigned char *)Hunk_AllocateTempMemory( FOG_S * FOG_T * 4 );
1243 
1244 	// S is distance, T is depth
1245 	for (x=0 ; x<FOG_S ; x++) {
1246 		for (y=0 ; y<FOG_T ; y++) {
1247 			d = R_FogFactor( ( x + 0.5f ) / FOG_S, ( y + 0.5f ) / FOG_T );
1248 
1249 			data[(y*FOG_S+x)*4+0] =
1250 			data[(y*FOG_S+x)*4+1] =
1251 			data[(y*FOG_S+x)*4+2] = 255;
1252 			data[(y*FOG_S+x)*4+3] = 255*d;
1253 		}
1254 	}
1255 	// standard openGL clamping doesn't really do what we want -- it includes
1256 	// the border color at the edges.  OpenGL 1.2 has clamp-to-edge, which does
1257 	// what we want.
1258 	tr.fogImage = R_CreateImage("*fog", (byte *)data, FOG_S, FOG_T, GL_RGBA, qfalse, qfalse, qfalse, GL_CLAMP );
1259 	Hunk_FreeTempMemory( data );
1260 
1261 	borderColor[0] = 1.0;
1262 	borderColor[1] = 1.0;
1263 	borderColor[2] = 1.0;
1264 	borderColor[3] = 1;
1265 
1266 	qglTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor );
1267 }
1268 
1269 /*
1270 ==================
1271 R_CreateDefaultImage
1272 ==================
1273 */
1274 #define	DEFAULT_SIZE	16
R_CreateDefaultImage(void)1275 static void R_CreateDefaultImage( void ) {
1276 	int		x;
1277 	byte	data[DEFAULT_SIZE][DEFAULT_SIZE][4];
1278 
1279 	// the default image will be a box, to allow you to see the mapping coordinates
1280 	memset( data, 32, sizeof( data ) );
1281 	for ( x = 0 ; x < DEFAULT_SIZE ; x++ ) {
1282 		data[0][x][0] =
1283 		data[0][x][1] =
1284 		data[0][x][2] =
1285 		data[0][x][3] = 255;
1286 
1287 		data[x][0][0] =
1288 		data[x][0][1] =
1289 		data[x][0][2] =
1290 		data[x][0][3] = 255;
1291 
1292 		data[DEFAULT_SIZE-1][x][0] =
1293 		data[DEFAULT_SIZE-1][x][1] =
1294 		data[DEFAULT_SIZE-1][x][2] =
1295 		data[DEFAULT_SIZE-1][x][3] = 255;
1296 
1297 		data[x][DEFAULT_SIZE-1][0] =
1298 		data[x][DEFAULT_SIZE-1][1] =
1299 		data[x][DEFAULT_SIZE-1][2] =
1300 		data[x][DEFAULT_SIZE-1][3] = 255;
1301 	}
1302 	tr.defaultImage = R_CreateImage("*default", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, GL_RGBA, qtrue, qfalse, qfalse, GL_REPEAT );
1303 }
1304 
1305 /*
1306 ==================
1307 R_CreateBuiltinImages
1308 ==================
1309 */
R_CreateBuiltinImages(void)1310 void R_CreateBuiltinImages( void ) {
1311 	int		x,y;
1312 	byte	data[DEFAULT_SIZE][DEFAULT_SIZE][4];
1313 
1314 	R_CreateDefaultImage();
1315 
1316 	// we use a solid white image instead of disabling texturing
1317 	memset( data, 255, sizeof( data ) );
1318 	tr.whiteImage = R_CreateImage("*white", (byte *)data, 8, 8, GL_RGBA, qfalse, qfalse, qfalse, GL_REPEAT);
1319 
1320 	tr.screenImage = R_CreateImage("*screen", (byte *)data, 8, 8, GL_RGBA, qfalse, qfalse, qfalse, GL_REPEAT );
1321 
1322 	// Create the scene glow image. - AReis
1323 	tr.screenGlow = 1024 + giTextureBindNum++;
1324 	qglDisable( GL_TEXTURE_2D );
1325 	qglEnable( GL_TEXTURE_RECTANGLE_ARB );
1326 	qglBindTexture( GL_TEXTURE_RECTANGLE_ARB, tr.screenGlow );
1327 	qglTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA16, glConfig.vidWidth, glConfig.vidHeight, 0, GL_RGB, GL_FLOAT, 0 );
1328 	qglTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
1329 	qglTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1330 	qglTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP );
1331 	qglTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP );
1332 
1333 	// Create the scene image. - AReis
1334 	tr.sceneImage = 1024 + giTextureBindNum++;
1335 	qglBindTexture( GL_TEXTURE_RECTANGLE_ARB, tr.sceneImage );
1336 	qglTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA16, glConfig.vidWidth, glConfig.vidHeight, 0, GL_RGB, GL_FLOAT, 0 );
1337 	qglTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
1338 	qglTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1339 	qglTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP );
1340 	qglTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP );
1341 
1342 	// Create the minimized scene blur image.
1343 	if ( r_DynamicGlowWidth->integer > glConfig.vidWidth  )
1344 	{
1345 		r_DynamicGlowWidth->integer = glConfig.vidWidth;
1346 	}
1347 	if ( r_DynamicGlowHeight->integer > glConfig.vidHeight  )
1348 	{
1349 		r_DynamicGlowHeight->integer = glConfig.vidHeight;
1350 	}
1351 	tr.blurImage = 1024 + giTextureBindNum++;
1352 	qglBindTexture( GL_TEXTURE_RECTANGLE_ARB, tr.blurImage );
1353 	qglTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA16, r_DynamicGlowWidth->integer, r_DynamicGlowHeight->integer, 0, GL_RGB, GL_FLOAT, 0 );
1354 	qglTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
1355 	qglTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1356 	qglTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP );
1357 	qglTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP );
1358 	qglDisable( GL_TEXTURE_RECTANGLE_ARB );
1359 
1360 	if ( glConfigExt.doGammaCorrectionWithShaders )
1361 	{
1362 		qglEnable( GL_TEXTURE_3D );
1363 		tr.gammaCorrectLUTImage = 1024 + giTextureBindNum++;
1364 		qglBindTexture(GL_TEXTURE_3D, tr.gammaCorrectLUTImage);
1365 		qglTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 64, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1366 		qglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1367 		qglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1368 		qglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1369 		qglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
1370 		qglTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1371 		qglDisable(GL_TEXTURE_3D);
1372 	}
1373 
1374 	qglEnable(GL_TEXTURE_2D);
1375 
1376 	// with overbright bits active, we need an image which is some fraction of full color,
1377 	// for default lightmaps, etc
1378 	for (x=0 ; x<DEFAULT_SIZE ; x++) {
1379 		for (y=0 ; y<DEFAULT_SIZE ; y++) {
1380 			data[y][x][0] =
1381 			data[y][x][1] =
1382 			data[y][x][2] = tr.identityLightByte;
1383 			data[y][x][3] = 255;
1384 		}
1385 	}
1386 
1387 	tr.identityLightImage = R_CreateImage("*identityLight", (byte *)data, 8, 8, GL_RGBA, qfalse, qfalse, qfalse, GL_REPEAT);
1388 
1389 	for(x=0;x<NUM_SCRATCH_IMAGES;x++) {
1390 		// scratchimage is usually used for cinematic drawing
1391 		tr.scratchImage[x] = R_CreateImage(va("*scratch%d",x), (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, GL_RGBA, qfalse, qtrue, qfalse, GL_CLAMP);
1392 	}
1393 
1394 	R_CreateDlightImage();
1395 
1396 	R_CreateFogImage();
1397 }
1398 
1399 
1400 /*
1401 ===============
1402 R_SetColorMappings
1403 ===============
1404 */
R_SetColorMappings(void)1405 void R_SetColorMappings( void ) {
1406 	int		i, j;
1407 	float	g;
1408 	int		inf;
1409 	int		shift;
1410 
1411 	// setup the overbright lighting
1412 	tr.overbrightBits = r_overBrightBits->integer;
1413 	if ( !glConfig.deviceSupportsGamma && !glConfigExt.doGammaCorrectionWithShaders ) {
1414 		tr.overbrightBits = 0;		// need hardware gamma for overbright
1415 	}
1416 
1417 	// never overbright in windowed mode
1418 	if ( !glConfig.isFullscreen )
1419 	{
1420 		tr.overbrightBits = 0;
1421 	}
1422 
1423 	if ( tr.overbrightBits > 1 ) {
1424 		tr.overbrightBits = 1;
1425 	}
1426 
1427 	if ( tr.overbrightBits < 0 ) {
1428 		tr.overbrightBits = 0;
1429 	}
1430 
1431 	tr.identityLight = 1.0f / ( 1 << tr.overbrightBits );
1432 	tr.identityLightByte = 255 * tr.identityLight;
1433 
1434 
1435 	if ( r_intensity->value < 1.0f ) {
1436 		ri.Cvar_Set( "r_intensity", "1" );
1437 	}
1438 
1439 	if ( r_gamma->value < 0.5f ) {
1440 		ri.Cvar_Set( "r_gamma", "0.5" );
1441 	} else if ( r_gamma->value > 3.0f ) {
1442 		ri.Cvar_Set( "r_gamma", "3.0" );
1443 	}
1444 
1445 	g = r_gamma->value;
1446 
1447 	shift = tr.overbrightBits;
1448 
1449 	if ( !glConfigExt.doGammaCorrectionWithShaders )
1450 	{
1451 		for ( i = 0; i < 256; i++ ) {
1452 			if ( g == 1 ) {
1453 				inf = i;
1454 			} else {
1455 				inf = 255 * pow ( i/255.0f, 1.0f / g ) + 0.5f;
1456 			}
1457 			inf <<= shift;
1458 			if (inf < 0) {
1459 				inf = 0;
1460 			}
1461 			if (inf > 255) {
1462 				inf = 255;
1463 			}
1464 			s_gammatable[i] = inf;
1465 		}
1466 
1467 		if ( glConfig.deviceSupportsGamma )
1468 		{
1469 			ri.WIN_SetGamma( &glConfig, s_gammatable, s_gammatable, s_gammatable );
1470 		}
1471 	}
1472 
1473 	for (i=0 ; i<256 ; i++) {
1474 		j = i * r_intensity->value;
1475 		if (j > 255) {
1476 			j = 255;
1477 		}
1478 		s_intensitytable[i] = j;
1479 	}
1480 }
1481 
R_SetGammaCorrectionLUT()1482 void R_SetGammaCorrectionLUT()
1483 {
1484 	if ( glConfigExt.doGammaCorrectionWithShaders )
1485 	{
1486 		int inf;
1487 		int shift = tr.overbrightBits;
1488 		float g = r_gamma->value;
1489 		byte gammaCorrected[64];
1490 
1491 		for ( int i = 0; i < 64; i++ )
1492 		{
1493 			if ( g == 1.0f )
1494 			{
1495 				inf = (int)(((float)i / 63.0f) * 255.0f + 0.5f);
1496 			}
1497 			else
1498 			{
1499 				inf = (int)(255.0f * pow((float)i / 63.0f, 1.0f / g) + 0.5f);
1500 			}
1501 
1502 			gammaCorrected[i] = Com_Clampi(0, 255, inf << shift);
1503 		}
1504 
1505 		byte *lutTable = (byte *)ri.Hunk_AllocateTempMemory(64 * 64 * 64 * 3);
1506 		byte *write = lutTable;
1507 		for ( int z = 0; z < 64; z++ )
1508 		{
1509 			for ( int y = 0; y < 64; y++ )
1510 			{
1511 				for ( int x = 0; x < 64; x++ )
1512 				{
1513 					*write++ = gammaCorrected[x];
1514 					*write++ = gammaCorrected[y];
1515 					*write++ = gammaCorrected[z];
1516 				}
1517 			}
1518 		}
1519 
1520 		qglBindTexture(GL_TEXTURE_3D, tr.gammaCorrectLUTImage);
1521 		qglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1522 		qglTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 64, 64, 64, GL_RGB, GL_UNSIGNED_BYTE, lutTable);
1523 
1524 		ri.Hunk_FreeTempMemory(lutTable);
1525 	}
1526 }
1527 
1528 /*
1529 ===============
1530 R_InitImages
1531 ===============
1532 */
R_InitImages(void)1533 void	R_InitImages( void ) {
1534 	//memset(hashTable, 0, sizeof(hashTable));	// DO NOT DO THIS NOW (because of image cacheing)	-ste.
1535 	// build brightness translation tables
1536 	R_SetColorMappings();
1537 
1538 	// create default texture and white texture
1539 	R_CreateBuiltinImages();
1540 
1541 	R_SetGammaCorrectionLUT();
1542 }
1543 
1544 /*
1545 ===============
1546 R_DeleteTextures
1547 ===============
1548 */
1549 // (only gets called during vid_restart now (and app exit), not during map load)
1550 //
R_DeleteTextures(void)1551 void R_DeleteTextures( void ) {
1552 
1553 	R_Images_Clear();
1554 	GL_ResetBinds();
1555 }
1556 
1557