1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 // tr_image.c
23 #include "tr_local.h"
24 
25 static byte			 s_intensitytable[256];
26 static unsigned char s_gammatable[256];
27 
28 int		gl_filter_min = GL_LINEAR_MIPMAP_NEAREST;
29 int		gl_filter_max = GL_LINEAR;
30 
31 #define FILE_HASH_SIZE		1024
32 static	image_t*		hashTable[FILE_HASH_SIZE];
33 
34 /*
35 ** R_GammaCorrect
36 */
R_GammaCorrect(byte * buffer,int bufSize)37 void R_GammaCorrect( byte *buffer, int bufSize ) {
38 	int i;
39 
40 	for ( i = 0; i < bufSize; i++ ) {
41 		buffer[i] = s_gammatable[buffer[i]];
42 	}
43 }
44 
45 typedef struct {
46 	char *name;
47 	int	minimize, maximize;
48 } textureMode_t;
49 
50 textureMode_t modes[] = {
51 	{"GL_NEAREST", GL_NEAREST, GL_NEAREST},
52 	{"GL_LINEAR", GL_LINEAR, GL_LINEAR},
53 	{"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
54 	{"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
55 	{"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
56 	{"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
57 };
58 
59 /*
60 ================
61 return a hash value for the filename
62 ================
63 */
generateHashValue(const char * fname)64 static long generateHashValue( const char *fname ) {
65 	int		i;
66 	long	hash;
67 	char	letter;
68 
69 	hash = 0;
70 	i = 0;
71 	while (fname[i] != '\0') {
72 		letter = tolower(fname[i]);
73 		if (letter =='.') break;				// don't include extension
74 		if (letter =='\\') letter = '/';		// damn path names
75 		hash+=(long)(letter)*(i+119);
76 		i++;
77 	}
78 	hash &= (FILE_HASH_SIZE-1);
79 	return hash;
80 }
81 
82 /*
83 ===============
84 GL_TextureMode
85 ===============
86 */
GL_TextureMode(const char * string)87 void GL_TextureMode( const char *string ) {
88 	int		i;
89 	image_t	*glt;
90 
91 	for ( i=0 ; i< 6 ; i++ ) {
92 		if ( !Q_stricmp( modes[i].name, string ) ) {
93 			break;
94 		}
95 	}
96 
97 	// hack to prevent trilinear from being set on voodoo,
98 	// because their driver freaks...
99 	if ( i == 5 && glConfig.hardwareType == GLHW_3DFX_2D3D ) {
100 		ri.Printf( PRINT_ALL, "Refusing to set trilinear on a voodoo.\n" );
101 		i = 3;
102 	}
103 
104 
105 	if ( i == 6 ) {
106 		ri.Printf (PRINT_ALL, "bad filter name\n");
107 		return;
108 	}
109 
110 	gl_filter_min = modes[i].minimize;
111 	gl_filter_max = modes[i].maximize;
112 
113 	// change all the existing mipmap texture objects
114 	for ( i = 0 ; i < tr.numImages ; i++ ) {
115 		glt = tr.images[ i ];
116 		if ( glt->mipmap ) {
117 			GL_Bind (glt);
118 			qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
119 			qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
120 		}
121 	}
122 }
123 
124 /*
125 ===============
126 R_SumOfUsedImages
127 ===============
128 */
R_SumOfUsedImages(void)129 int R_SumOfUsedImages( void ) {
130 	int	total;
131 	int i;
132 
133 	total = 0;
134 	for ( i = 0; i < tr.numImages; i++ ) {
135 		if ( tr.images[i]->frameUsed == tr.frameCount ) {
136 			total += tr.images[i]->uploadWidth * tr.images[i]->uploadHeight;
137 		}
138 	}
139 
140 	return total;
141 }
142 
143 /*
144 ===============
145 R_ImageList_f
146 ===============
147 */
R_ImageList_f(void)148 void R_ImageList_f( void ) {
149 	int		i;
150 	image_t	*image;
151 	int		texels;
152 	const char *yesno[] = {
153 		"no ", "yes"
154 	};
155 
156 	ri.Printf (PRINT_ALL, "\n      -w-- -h-- -mm- -TMU- -if-- wrap --name-------\n");
157 	texels = 0;
158 
159 	for ( i = 0 ; i < tr.numImages ; i++ ) {
160 		image = tr.images[ i ];
161 
162 		texels += image->uploadWidth*image->uploadHeight;
163 		ri.Printf (PRINT_ALL,  "%4i: %4i %4i  %s   %d   ",
164 			i, image->uploadWidth, image->uploadHeight, yesno[image->mipmap], image->TMU );
165 		switch ( image->internalFormat ) {
166 		case 1:
167 			ri.Printf( PRINT_ALL, "I    " );
168 			break;
169 		case 2:
170 			ri.Printf( PRINT_ALL, "IA   " );
171 			break;
172 		case 3:
173 			ri.Printf( PRINT_ALL, "RGB  " );
174 			break;
175 		case 4:
176 			ri.Printf( PRINT_ALL, "RGBA " );
177 			break;
178 		case GL_RGBA8:
179 			ri.Printf( PRINT_ALL, "RGBA8" );
180 			break;
181 		case GL_RGB8:
182 			ri.Printf( PRINT_ALL, "RGB8" );
183 			break;
184 		case GL_RGB4_S3TC:
185 		case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
186 			ri.Printf( PRINT_ALL, "S3TC " );
187 			break;
188 		case GL_RGBA4:
189 			ri.Printf( PRINT_ALL, "RGBA4" );
190 			break;
191 		case GL_RGB5:
192 			ri.Printf( PRINT_ALL, "RGB5 " );
193 			break;
194 		default:
195 			ri.Printf( PRINT_ALL, "???? " );
196 		}
197 
198 		switch ( image->wrapClampMode ) {
199 		case GL_REPEAT:
200 			ri.Printf( PRINT_ALL, "rept " );
201 			break;
202 		case GL_CLAMP_TO_EDGE:
203 			ri.Printf( PRINT_ALL, "clmp " );
204 			break;
205 		default:
206 			ri.Printf( PRINT_ALL, "%4i ", image->wrapClampMode );
207 			break;
208 		}
209 
210 		ri.Printf( PRINT_ALL, " %s\n", image->imgName );
211 	}
212 	ri.Printf (PRINT_ALL, " ---------\n");
213 	ri.Printf (PRINT_ALL, " %i total texels (not including mipmaps)\n", texels);
214 	ri.Printf (PRINT_ALL, " %i total images\n\n", tr.numImages );
215 }
216 
217 //=======================================================================
218 
219 /*
220 ================
221 ResampleTexture
222 
223 Used to resample images in a more general than quartering fashion.
224 
225 This will only be filtered properly if the resampled size
226 is greater than half the original size.
227 
228 If a larger shrinking is needed, use the mipmap function
229 before or after.
230 ================
231 */
ResampleTexture(unsigned * in,int inwidth,int inheight,unsigned * out,int outwidth,int outheight)232 static void ResampleTexture( unsigned *in, int inwidth, int inheight, unsigned *out,
233 							int outwidth, int outheight ) {
234 	int		i, j;
235 	unsigned	*inrow, *inrow2;
236 	unsigned	frac, fracstep;
237 	unsigned	p1[2048], p2[2048];
238 	byte		*pix1, *pix2, *pix3, *pix4;
239 
240 	if (outwidth>2048)
241 		ri.Error(ERR_DROP, "ResampleTexture: max width");
242 
243 	fracstep = inwidth*0x10000/outwidth;
244 
245 	frac = fracstep>>2;
246 	for ( i=0 ; i<outwidth ; i++ ) {
247 		p1[i] = 4*(frac>>16);
248 		frac += fracstep;
249 	}
250 	frac = 3*(fracstep>>2);
251 	for ( i=0 ; i<outwidth ; i++ ) {
252 		p2[i] = 4*(frac>>16);
253 		frac += fracstep;
254 	}
255 
256 	for (i=0 ; i<outheight ; i++, out += outwidth) {
257 		inrow = in + inwidth*(int)((i+0.25)*inheight/outheight);
258 		inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight);
259 		frac = fracstep >> 1;
260 		for (j=0 ; j<outwidth ; j++) {
261 			pix1 = (byte *)inrow + p1[j];
262 			pix2 = (byte *)inrow + p2[j];
263 			pix3 = (byte *)inrow2 + p1[j];
264 			pix4 = (byte *)inrow2 + p2[j];
265 			((byte *)(out+j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>2;
266 			((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2;
267 			((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2;
268 			((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2;
269 		}
270 	}
271 }
272 
273 /*
274 ================
275 R_LightScaleTexture
276 
277 Scale up the pixel values in a texture to increase the
278 lighting range
279 ================
280 */
R_LightScaleTexture(unsigned * in,int inwidth,int inheight,qboolean only_gamma)281 void R_LightScaleTexture (unsigned *in, int inwidth, int inheight, qboolean only_gamma )
282 {
283 	if ( only_gamma )
284 	{
285 		if ( !glConfig.deviceSupportsGamma )
286 		{
287 			int		i, c;
288 			byte	*p;
289 
290 			p = (byte *)in;
291 
292 			c = inwidth*inheight;
293 			for (i=0 ; i<c ; i++, p+=4)
294 			{
295 				p[0] = s_gammatable[p[0]];
296 				p[1] = s_gammatable[p[1]];
297 				p[2] = s_gammatable[p[2]];
298 			}
299 		}
300 	}
301 	else
302 	{
303 		int		i, c;
304 		byte	*p;
305 
306 		p = (byte *)in;
307 
308 		c = inwidth*inheight;
309 
310 		if ( glConfig.deviceSupportsGamma )
311 		{
312 			for (i=0 ; i<c ; i++, p+=4)
313 			{
314 				p[0] = s_intensitytable[p[0]];
315 				p[1] = s_intensitytable[p[1]];
316 				p[2] = s_intensitytable[p[2]];
317 			}
318 		}
319 		else
320 		{
321 			for (i=0 ; i<c ; i++, p+=4)
322 			{
323 				p[0] = s_gammatable[s_intensitytable[p[0]]];
324 				p[1] = s_gammatable[s_intensitytable[p[1]]];
325 				p[2] = s_gammatable[s_intensitytable[p[2]]];
326 			}
327 		}
328 	}
329 }
330 
331 
332 /*
333 ================
334 R_MipMap2
335 
336 Operates in place, quartering the size of the texture
337 Proper linear filter
338 ================
339 */
R_MipMap2(unsigned * in,int inWidth,int inHeight)340 static void R_MipMap2( unsigned *in, int inWidth, int inHeight ) {
341 	int			i, j, k;
342 	byte		*outpix;
343 	int			inWidthMask, inHeightMask;
344 	int			total;
345 	int			outWidth, outHeight;
346 	unsigned	*temp;
347 
348 	outWidth = inWidth >> 1;
349 	outHeight = inHeight >> 1;
350 	temp = ri.Hunk_AllocateTempMemory( outWidth * outHeight * 4 );
351 
352 	inWidthMask = inWidth - 1;
353 	inHeightMask = inHeight - 1;
354 
355 	for ( i = 0 ; i < outHeight ; i++ ) {
356 		for ( j = 0 ; j < outWidth ; j++ ) {
357 			outpix = (byte *) ( temp + i * outWidth + j );
358 			for ( k = 0 ; k < 4 ; k++ ) {
359 				total =
360 					1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
361 					2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
362 					2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
363 					1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
364 
365 					2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
366 					4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
367 					4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
368 					2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
369 
370 					2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
371 					4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
372 					4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
373 					2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
374 
375 					1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
376 					2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
377 					2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
378 					1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k];
379 				outpix[k] = total / 36;
380 			}
381 		}
382 	}
383 
384 	Com_Memcpy( in, temp, outWidth * outHeight * 4 );
385 	ri.Hunk_FreeTempMemory( temp );
386 }
387 
388 /*
389 ================
390 R_MipMap
391 
392 Operates in place, quartering the size of the texture
393 ================
394 */
R_MipMap(byte * in,int width,int height)395 static void R_MipMap (byte *in, int width, int height) {
396 	int		i, j;
397 	byte	*out;
398 	int		row;
399 
400 	if ( !r_simpleMipMaps->integer ) {
401 		R_MipMap2( (unsigned *)in, width, height );
402 		return;
403 	}
404 
405 	if ( width == 1 && height == 1 ) {
406 		return;
407 	}
408 
409 	row = width * 4;
410 	out = in;
411 	width >>= 1;
412 	height >>= 1;
413 
414 	if ( width == 0 || height == 0 ) {
415 		width += height;	// get largest
416 		for (i=0 ; i<width ; i++, out+=4, in+=8 ) {
417 			out[0] = ( in[0] + in[4] )>>1;
418 			out[1] = ( in[1] + in[5] )>>1;
419 			out[2] = ( in[2] + in[6] )>>1;
420 			out[3] = ( in[3] + in[7] )>>1;
421 		}
422 		return;
423 	}
424 
425 	for (i=0 ; i<height ; i++, in+=row) {
426 		for (j=0 ; j<width ; j++, out+=4, in+=8) {
427 			out[0] = (in[0] + in[4] + in[row+0] + in[row+4])>>2;
428 			out[1] = (in[1] + in[5] + in[row+1] + in[row+5])>>2;
429 			out[2] = (in[2] + in[6] + in[row+2] + in[row+6])>>2;
430 			out[3] = (in[3] + in[7] + in[row+3] + in[row+7])>>2;
431 		}
432 	}
433 }
434 
435 
436 /*
437 ==================
438 R_BlendOverTexture
439 
440 Apply a color blend over a set of pixels
441 ==================
442 */
R_BlendOverTexture(byte * data,int pixelCount,byte blend[4])443 static void R_BlendOverTexture( byte *data, int pixelCount, byte blend[4] ) {
444 	int		i;
445 	int		inverseAlpha;
446 	int		premult[3];
447 
448 	inverseAlpha = 255 - blend[3];
449 	premult[0] = blend[0] * blend[3];
450 	premult[1] = blend[1] * blend[3];
451 	premult[2] = blend[2] * blend[3];
452 
453 	for ( i = 0 ; i < pixelCount ; i++, data+=4 ) {
454 		data[0] = ( data[0] * inverseAlpha + premult[0] ) >> 9;
455 		data[1] = ( data[1] * inverseAlpha + premult[1] ) >> 9;
456 		data[2] = ( data[2] * inverseAlpha + premult[2] ) >> 9;
457 	}
458 }
459 
460 byte	mipBlendColors[16][4] = {
461 	{0,0,0,0},
462 	{255,0,0,128},
463 	{0,255,0,128},
464 	{0,0,255,128},
465 	{255,0,0,128},
466 	{0,255,0,128},
467 	{0,0,255,128},
468 	{255,0,0,128},
469 	{0,255,0,128},
470 	{0,0,255,128},
471 	{255,0,0,128},
472 	{0,255,0,128},
473 	{0,0,255,128},
474 	{255,0,0,128},
475 	{0,255,0,128},
476 	{0,0,255,128},
477 };
478 
479 
480 /*
481 ===============
482 Upload32
483 
484 ===============
485 */
486 extern qboolean charSet;
Upload32(unsigned * data,int width,int height,qboolean mipmap,qboolean picmip,qboolean lightMap,int * format,int * pUploadWidth,int * pUploadHeight)487 static void Upload32( unsigned *data,
488 						  int width, int height,
489 						  qboolean mipmap,
490 						  qboolean picmip,
491 							qboolean lightMap,
492 						  int *format,
493 						  int *pUploadWidth, int *pUploadHeight )
494 {
495 	int			samples;
496 	unsigned	*scaledBuffer = NULL;
497 	unsigned	*resampledBuffer = NULL;
498 	int			scaled_width, scaled_height;
499 	int			i, c;
500 	byte		*scan;
501 	GLenum		internalFormat = GL_RGB;
502 	GLenum		temp_GLformat = GL_RGBA;
503 	GLenum		temp_GLtype = GL_UNSIGNED_BYTE;
504 	float		rMax = 0, gMax = 0, bMax = 0;
505 
506 	//
507 	// convert to exact power of 2 sizes
508 	//
509 	for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1)
510 		;
511 	for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1)
512 		;
513 	if ( r_roundImagesDown->integer && scaled_width > width )
514 		scaled_width >>= 1;
515 	if ( r_roundImagesDown->integer && scaled_height > height )
516 		scaled_height >>= 1;
517 
518 	if ( scaled_width != width || scaled_height != height ) {
519 		resampledBuffer = ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 );
520 		ResampleTexture (data, width, height, resampledBuffer, scaled_width, scaled_height);
521 		data = resampledBuffer;
522 		width = scaled_width;
523 		height = scaled_height;
524 	}
525 
526 	//
527 	// perform optional picmip operation
528 	//
529 	if ( picmip ) {
530 		scaled_width >>= r_picmip->integer;
531 		scaled_height >>= r_picmip->integer;
532 	}
533 
534 	//
535 	// clamp to minimum size
536 	//
537 	if (scaled_width < 1) {
538 		scaled_width = 1;
539 	}
540 	if (scaled_height < 1) {
541 		scaled_height = 1;
542 	}
543 
544 	//
545 	// clamp to the current upper OpenGL limit
546 	// scale both axis down equally so we don't have to
547 	// deal with a half mip resampling
548 	//
549 	while ( scaled_width > glConfig.maxTextureSize
550 		|| scaled_height > glConfig.maxTextureSize ) {
551 		scaled_width >>= 1;
552 		scaled_height >>= 1;
553 	}
554 
555 	scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height );
556 
557 	//
558 	// scan the texture for each channel's max values
559 	// and verify if the alpha channel is being used or not
560 	//
561 	c = width*height;
562 	scan = ((byte *)data);
563 	samples = 3;
564 
565 	if( r_greyscale->integer )
566 	{
567 		for ( i = 0; i < c; i++ )
568 		{
569 			byte luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
570 			scan[i*4] = luma;
571 			scan[i*4 + 1] = luma;
572 			scan[i*4 + 2] = luma;
573 		}
574 	}
575 	else if( r_greyscale->value )
576 	{
577 		for ( i = 0; i < c; i++ )
578 		{
579 			float luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]);
580 			scan[i*4] = LERP(scan[i*4], luma, r_greyscale->value);
581 			scan[i*4 + 1] = LERP(scan[i*4 + 1], luma, r_greyscale->value);
582 			scan[i*4 + 2] = LERP(scan[i*4 + 2], luma, r_greyscale->value);
583 		}
584 	}
585 
586 	if(lightMap)
587 	{
588 		if(r_greyscale->integer)
589 			internalFormat = GL_LUMINANCE;
590 		else if(r_monolightmaps->integer)
591 			internalFormat = GL_LUMINANCE;
592 		else
593 			internalFormat = GL_RGB;
594 	}
595 	else
596 	{
597 		for ( i = 0; i < c; i++ )
598 		{
599 			if ( scan[i*4+0] > rMax )
600 			{
601 				rMax = scan[i*4+0];
602 			}
603 			if ( scan[i*4+1] > gMax )
604 			{
605 				gMax = scan[i*4+1];
606 			}
607 			if ( scan[i*4+2] > bMax )
608 			{
609 				bMax = scan[i*4+2];
610 			}
611 			if ( scan[i*4 + 3] != 255 )
612 			{
613 				samples = 4;
614 				break;
615 			}
616 		}
617 		// select proper internal format
618 		if ( samples == 3 )
619 		{
620 			if(r_greyscale->integer)
621 			{
622 				if(r_texturebits->integer == 16)
623 					internalFormat = GL_LUMINANCE8;
624 				else if(r_texturebits->integer == 32)
625 					internalFormat = GL_LUMINANCE16;
626 				else
627 					internalFormat = GL_LUMINANCE;
628 			}
629 			else
630 			{
631 				if ( glConfig.textureCompression == TC_S3TC_ARB )
632 				{
633 					internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
634 				}
635 				else if ( glConfig.textureCompression == TC_S3TC )
636 				{
637 					internalFormat = GL_RGB4_S3TC;
638 				}
639 				else if ( r_texturebits->integer == 16 )
640 				{
641 					internalFormat = GL_RGB5;
642 				}
643 				else if ( r_texturebits->integer == 15 )
644 				{
645 					internalFormat = GL_RGB5;
646 				}
647 				else if ( r_texturebits->integer == 12 )
648 				{
649 					internalFormat = GL_RGB4;
650 				}
651 				else if ( r_texturebits->integer == 6 )
652 				{
653 					internalFormat = GL_R3_G3_B2;
654 				}
655 				else if ( r_texturebits->integer == 32 )
656 				{
657 					internalFormat = GL_RGB8;
658 				}
659 				else
660 				{
661 					internalFormat = GL_RGB;
662 				}
663 			}
664 		}
665 		else if ( samples == 4 )
666 		{
667 			if(r_greyscale->integer)
668 			{
669 				if(r_texturebits->integer == 16)
670 					internalFormat = GL_LUMINANCE8_ALPHA8;
671 				else if(r_texturebits->integer == 32)
672 					internalFormat = GL_LUMINANCE16_ALPHA16;
673 				else
674 					internalFormat = GL_LUMINANCE_ALPHA;
675 			}
676 			else
677 			{
678 /*
679 // leilei - This was commented out, because bloom strictly needs GL_RGBA
680 				if ( glConfig.textureCompression == TC_S3TC_ARB )
681 				{
682 					internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; // leilei - this was missing
683 				}
684 				else */
685 				if ( r_texturebits->integer == 16 )
686 				{
687 					internalFormat = GL_RGBA4;
688 				}
689 				else if ( r_texturebits->integer == 15 )
690 				{
691 					internalFormat = GL_RGB5_A1;
692 				}
693 				else if ( r_texturebits->integer == 12 )
694 				{
695 					internalFormat = GL_RGBA4;
696 				}
697 				else if ( r_texturebits->integer == 6 )
698 				{
699 					internalFormat = GL_RGBA2;
700 				}
701 				else if ( r_texturebits->integer == 32 )
702 				{
703 					internalFormat = GL_RGBA8;
704 				}
705 				else
706 				{
707 					internalFormat = GL_RGBA;
708 				}
709 			}
710 		}
711 	}
712 
713 	if (depthimage)
714 		{ mipmap=0; internalFormat = GL_DEPTH_COMPONENT; temp_GLformat=GL_DEPTH_COMPONENT; temp_GLtype=GL_FLOAT; }
715 			else
716 		{ temp_GLformat=GL_RGBA; temp_GLtype=GL_UNSIGNED_BYTE; }
717 
718 	// copy or resample data as appropriate for first MIP level
719 	if ( ( scaled_width == width ) &&
720 		( scaled_height == height ) ) {
721 		if (!mipmap)
722 		{
723 			qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, temp_GLformat, temp_GLtype, data);
724 			*pUploadWidth = scaled_width;
725 			*pUploadHeight = scaled_height;
726 			*format = internalFormat;
727 
728 			goto done;
729 		}
730 		Com_Memcpy (scaledBuffer, data, width*height*4);
731 	}
732 	else
733 	{
734 		// use the normal mip-mapping function to go down from here
735 		while ( width > scaled_width || height > scaled_height ) {
736 			R_MipMap( (byte *)data, width, height );
737 			width >>= 1;
738 			height >>= 1;
739 			if ( width < 1 ) {
740 				width = 1;
741 			}
742 			if ( height < 1 ) {
743 				height = 1;
744 			}
745 		}
746 		Com_Memcpy( scaledBuffer, data, width * height * 4 );
747 	}
748 
749 	R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !mipmap );
750 
751 	*pUploadWidth = scaled_width;
752 	*pUploadHeight = scaled_height;
753 	*format = internalFormat;
754 
755 	qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, temp_GLformat, temp_GLtype, scaledBuffer );
756 
757 	if (mipmap)
758 	{
759 		int		miplevel;
760 
761 		miplevel = 0;
762 		while (scaled_width > 1 || scaled_height > 1)
763 		{
764 			R_MipMap( (byte *)scaledBuffer, scaled_width, scaled_height );
765 			scaled_width >>= 1;
766 			scaled_height >>= 1;
767 			if (scaled_width < 1)
768 				scaled_width = 1;
769 			if (scaled_height < 1)
770 				scaled_height = 1;
771 			miplevel++;
772 
773 			if ( r_colorMipLevels->integer ) {
774 				R_BlendOverTexture( (byte *)scaledBuffer, scaled_width * scaled_height, mipBlendColors[miplevel] );
775 			}
776 
777 			qglTexImage2D (GL_TEXTURE_2D, miplevel, internalFormat, scaled_width, scaled_height, 0, temp_GLformat, temp_GLtype, scaledBuffer );
778 		}
779 	}
780 done:
781 
782 	if (mipmap)
783 	{
784 		if ( textureFilterAnisotropic )
785 			qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
786 					(GLint)Com_Clamp( 1, maxAnisotropy, r_ext_max_anisotropy->integer ) );
787 
788 		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
789 		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
790 	}
791 	else
792 	{
793 		if ( textureFilterAnisotropic )
794 			qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 );
795 
796 		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
797 		qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
798 	}
799 
800 	if (depthimage) {
801 		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
802 		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
803 		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
804 		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
805 	    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
806 	    glTexParameteri (GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_ALPHA);
807 
808 	}
809 	GL_CheckErrors();
810 
811 	if ( scaledBuffer != 0 )
812 		ri.Hunk_FreeTempMemory( scaledBuffer );
813 	if ( resampledBuffer != 0 )
814 		ri.Hunk_FreeTempMemory( resampledBuffer );
815 }
816 
817 
818 /*
819 ================
820 R_CreateImage
821 
822 This is the only way any image_t are created
823 ================
824 */
R_CreateImage(const char * name,const byte * pic,int width,int height,qboolean mipmap,qboolean allowPicmip,int glWrapClampMode)825 image_t *R_CreateImage( const char *name, const byte *pic, int width, int height,
826 					   qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) {
827 	image_t		*image;
828 	qboolean	isLightmap = qfalse;
829 	long		hash;
830 
831 	if (strlen(name) >= MAX_QPATH ) {
832 		ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long\n", name);
833 	}
834 	if ( !strncmp( name, "*lightmap", 9 ) ) {
835 		isLightmap = qtrue;
836 	}
837 
838 	if ( tr.numImages == MAX_DRAWIMAGES ) {
839 		ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit\n");
840 	}
841 
842 	image = tr.images[tr.numImages] = ri.Hunk_Alloc( sizeof( image_t ), h_low );
843 	image->texnum = 1024 + tr.numImages;
844 	tr.numImages++;
845 
846 	image->mipmap = mipmap;
847 	image->allowPicmip = allowPicmip;
848 
849 	strcpy (image->imgName, name);
850 
851 	image->width = width;
852 	image->height = height;
853 	image->wrapClampMode = glWrapClampMode;
854 
855 	// lightmaps are always allocated on TMU 1
856 	if ( qglActiveTextureARB && isLightmap ) {
857 		image->TMU = 1;
858 	} else {
859 		image->TMU = 0;
860 	}
861 
862 	if ( qglActiveTextureARB ) {
863 		GL_SelectTexture( image->TMU );
864 	}
865 
866 	GL_Bind(image);
867 
868 	Upload32( (unsigned *)pic, image->width, image->height,
869 								image->mipmap,
870 								allowPicmip,
871 								isLightmap,
872 								&image->internalFormat,
873 								&image->uploadWidth,
874 								&image->uploadHeight );
875 
876 	qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode );
877 	qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode );
878 
879 	qglBindTexture( GL_TEXTURE_2D, 0 );
880 
881 	if ( image->TMU == 1 ) {
882 		GL_SelectTexture( 0 );
883 	}
884 
885 	hash = generateHashValue(name);
886 	image->next = hashTable[hash];
887 	hashTable[hash] = image;
888 
889 	return image;
890 }
891 
892 //===================================================================
893 
894 typedef struct
895 {
896 	char *ext;
897 	void (*ImageLoader)( const char *, unsigned char **, int *, int * );
898 } imageExtToLoaderMap_t;
899 
900 // Note that the ordering indicates the order of preference used
901 // when there are multiple images of different formats available
902 static imageExtToLoaderMap_t imageLoaders[ ] =
903 {
904 	{ "tga",  R_LoadTGA },
905 	{ "jpg",  R_LoadJPG },
906 	{ "jpeg", R_LoadJPG },
907 	{ "png",  R_LoadPNG },
908 	{ "pcx",  R_LoadPCX },
909 	{ "bmp",  R_LoadBMP }
910 };
911 
912 static int numImageLoaders = sizeof( imageLoaders ) /
913 		sizeof( imageLoaders[ 0 ] );
914 
915 /*
916 =================
917 R_LoadImage
918 
919 Loads any of the supported image types into a cannonical
920 32 bit format.
921 =================
922 */
R_LoadImage(const char * name,byte ** pic,int * width,int * height)923 void R_LoadImage( const char *name, byte **pic, int *width, int *height )
924 {
925 	qboolean orgNameFailed = qfalse;
926 	int i;
927 	char localName[ MAX_QPATH ];
928 	const char *ext;
929 
930 	*pic = NULL;
931 	*width = 0;
932 	*height = 0;
933 
934 	Q_strncpyz( localName, name, MAX_QPATH );
935 
936 	ext = COM_GetExtension( localName );
937 
938 	if( *ext )
939 	{
940 		// Look for the correct loader and use it
941 		for( i = 0; i < numImageLoaders; i++ )
942 		{
943 			if( !Q_stricmp( ext, imageLoaders[ i ].ext ) )
944 			{
945 				// Load
946 				imageLoaders[ i ].ImageLoader( localName, pic, width, height );
947 				break;
948 			}
949 		}
950 
951 		// A loader was found
952 		if( i < numImageLoaders )
953 		{
954 			if( *pic == NULL )
955 			{
956 				// Loader failed, most likely because the file isn't there;
957 				// try again without the extension
958 				orgNameFailed = qtrue;
959 				COM_StripExtension( name, localName, MAX_QPATH );
960 			}
961 			else
962 			{
963 				// Something loaded
964 				return;
965 			}
966 		}
967 	}
968 
969 	// Try and find a suitable match using all
970 	// the image formats supported
971 	for( i = 0; i < numImageLoaders; i++ )
972 	{
973 		char *altName = va( "%s.%s", localName, imageLoaders[ i ].ext );
974 
975 		// Load
976 		imageLoaders[ i ].ImageLoader( altName, pic, width, height );
977 
978 		if( *pic )
979 		{
980 			if( orgNameFailed )
981 			{
982 				ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n",
983 						name, altName );
984 			}
985 
986 			break;
987 		}
988 	}
989 }
990 
991 
992 /*
993 ===============
994 R_FindImageFile
995 
996 Finds or loads the given image.
997 Returns NULL if it fails, not a default image.
998 ==============
999 */
R_FindImageFile(const char * name,qboolean mipmap,qboolean allowPicmip,int glWrapClampMode)1000 image_t	*R_FindImageFile( const char *name, qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) {
1001 	image_t	*image;
1002 	int		width, height;
1003 	byte	*pic;
1004 	long	hash;
1005 
1006 	if (!name) {
1007 		return NULL;
1008 	}
1009 
1010 	hash = generateHashValue(name);
1011 
1012 	//
1013 	// see if the image is already loaded
1014 	//
1015 	for (image=hashTable[hash]; image; image=image->next) {
1016 		if ( !strcmp( name, image->imgName ) ) {
1017 			// the white image can be used with any set of parms, but other mismatches are errors
1018 			if ( strcmp( name, "*white" ) ) {
1019 				if ( image->mipmap != mipmap ) {
1020 					ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed mipmap parm\n", name );
1021 				}
1022 				if ( image->allowPicmip != allowPicmip ) {
1023 					ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed allowPicmip parm\n", name );
1024 				}
1025 				if ( image->wrapClampMode != glWrapClampMode ) {
1026 					ri.Printf( PRINT_ALL, "WARNING: reused image %s with mixed glWrapClampMode parm\n", name );
1027 				}
1028 			}
1029 			return image;
1030 		}
1031 	}
1032 
1033 	//
1034 	// load the pic from disk
1035 	//
1036 	R_LoadImage( name, &pic, &width, &height );
1037 	if ( pic == NULL ) {
1038 		return NULL;
1039 	}
1040 
1041 	image = R_CreateImage( ( char * ) name, pic, width, height, mipmap, allowPicmip, glWrapClampMode );
1042 	ri.Free( pic );
1043 	return image;
1044 }
1045 
1046 
1047 /*
1048 ================
1049 R_CreateDlightImage
1050 ================
1051 */
1052 #define	DLIGHT_SIZE	16
R_CreateDlightImage(void)1053 static void R_CreateDlightImage( void ) {
1054 	int		x,y;
1055 	byte	data[DLIGHT_SIZE][DLIGHT_SIZE][4];
1056 	int		b;
1057 
1058 	// make a centered inverse-square falloff blob for dynamic lighting
1059 	for (x=0 ; x<DLIGHT_SIZE ; x++) {
1060 		for (y=0 ; y<DLIGHT_SIZE ; y++) {
1061 			float	d;
1062 
1063 			d = ( DLIGHT_SIZE/2 - 0.5f - x ) * ( DLIGHT_SIZE/2 - 0.5f - x ) +
1064 				( DLIGHT_SIZE/2 - 0.5f - y ) * ( DLIGHT_SIZE/2 - 0.5f - y );
1065 			b = 4000 / d;
1066 			if (b > 255) {
1067 				b = 255;
1068 			} else if ( b < 75 ) {
1069 				b = 0;
1070 			}
1071 			data[y][x][0] =
1072 			data[y][x][1] =
1073 			data[y][x][2] = b;
1074 			data[y][x][3] = 255;
1075 		}
1076 	}
1077 	tr.dlightImage = R_CreateImage("*dlight", (byte *)data, DLIGHT_SIZE, DLIGHT_SIZE, qfalse, qfalse, GL_CLAMP_TO_EDGE );
1078 }
1079 
1080 
1081 /*
1082 =================
1083 R_InitFogTable
1084 =================
1085 */
R_InitFogTable(void)1086 void R_InitFogTable( void ) {
1087 	int		i;
1088 	float	d;
1089 	float	exp;
1090 
1091 	exp = 0.5;
1092 
1093 	for ( i = 0 ; i < FOG_TABLE_SIZE ; i++ ) {
1094 		d = pow ( (float)i/(FOG_TABLE_SIZE-1), exp );
1095 
1096 		tr.fogTable[i] = d;
1097 	}
1098 }
1099 
1100 /*
1101 ================
1102 R_FogFactor
1103 
1104 Returns a 0.0 to 1.0 fog density value
1105 This is called for each texel of the fog texture on startup
1106 and for each vertex of transparent shaders in fog dynamically
1107 ================
1108 */
R_FogFactor(float s,float t)1109 float	R_FogFactor( float s, float t ) {
1110 	float	d;
1111 
1112 	s -= 1.0/512;
1113 	if ( s < 0 ) {
1114 		return 0;
1115 	}
1116 	if ( t < 1.0/32 ) {
1117 		return 0;
1118 	}
1119 	if ( t < 31.0/32 ) {
1120 		s *= (t - 1.0f/32.0f) / (30.0f/32.0f);
1121 	}
1122 
1123 	// we need to leave a lot of clamp range
1124 	s *= 8;
1125 
1126 	if ( s > 1.0 ) {
1127 		s = 1.0;
1128 	}
1129 
1130 	d = tr.fogTable[ (int)(s * (FOG_TABLE_SIZE-1)) ];
1131 
1132 	return d;
1133 }
1134 
1135 /*
1136 ================
1137 R_CreateFogImage
1138 ================
1139 */
1140 #define	FOG_S	256
1141 #define	FOG_T	32
R_CreateFogImage(void)1142 static void R_CreateFogImage( void ) {
1143 	int		x,y;
1144 	byte	*data;
1145 	float	g;
1146 	float	d;
1147 	float	borderColor[4];
1148 
1149 	data = ri.Hunk_AllocateTempMemory( FOG_S * FOG_T * 4 );
1150 
1151 	g = 2.0;
1152 
1153 	// S is distance, T is depth
1154 	for (x=0 ; x<FOG_S ; x++) {
1155 		for (y=0 ; y<FOG_T ; y++) {
1156 			d = R_FogFactor( ( x + 0.5f ) / FOG_S, ( y + 0.5f ) / FOG_T );
1157 
1158 			data[(y*FOG_S+x)*4+0] =
1159 			data[(y*FOG_S+x)*4+1] =
1160 			data[(y*FOG_S+x)*4+2] = 255;
1161 			data[(y*FOG_S+x)*4+3] = 255*d;
1162 		}
1163 	}
1164 	// standard openGL clamping doesn't really do what we want -- it includes
1165 	// the border color at the edges.  OpenGL 1.2 has clamp-to-edge, which does
1166 	// what we want.
1167 	tr.fogImage = R_CreateImage("*fog", (byte *)data, FOG_S, FOG_T, qfalse, qfalse, GL_CLAMP_TO_EDGE );
1168 	ri.Hunk_FreeTempMemory( data );
1169 
1170 	borderColor[0] = 1.0;
1171 	borderColor[1] = 1.0;
1172 	borderColor[2] = 1.0;
1173 	borderColor[3] = 1;
1174 
1175 	qglTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor );
1176 }
1177 
1178 /*
1179 ==================
1180 R_CreateDefaultImage
1181 ==================
1182 */
1183 #define	DEFAULT_SIZE	16
R_CreateDefaultImage(void)1184 static void R_CreateDefaultImage( void ) {
1185 	int		x;
1186 	byte	data[DEFAULT_SIZE][DEFAULT_SIZE][4];
1187 
1188 	// the default image will be a box, to allow you to see the mapping coordinates
1189 	Com_Memset( data, 32, sizeof( data ) );
1190 	for ( x = 0 ; x < DEFAULT_SIZE ; x++ ) {
1191 		data[0][x][0] =
1192 		data[0][x][1] =
1193 		data[0][x][2] =
1194 		data[0][x][3] = 255;
1195 
1196 		data[x][0][0] =
1197 		data[x][0][1] =
1198 		data[x][0][2] =
1199 		data[x][0][3] = 255;
1200 
1201 		data[DEFAULT_SIZE-1][x][0] =
1202 		data[DEFAULT_SIZE-1][x][1] =
1203 		data[DEFAULT_SIZE-1][x][2] =
1204 		data[DEFAULT_SIZE-1][x][3] = 255;
1205 
1206 		data[x][DEFAULT_SIZE-1][0] =
1207 		data[x][DEFAULT_SIZE-1][1] =
1208 		data[x][DEFAULT_SIZE-1][2] =
1209 		data[x][DEFAULT_SIZE-1][3] = 255;
1210 	}
1211 	tr.defaultImage = R_CreateImage("*default", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, qtrue, qfalse, GL_REPEAT );
1212 }
1213 
1214 /*
1215 ==================
1216 R_CreateBuiltinImages
1217 ==================
1218 */
R_CreateBuiltinImages(void)1219 void R_CreateBuiltinImages( void ) {
1220 	int		x,y;
1221 	byte	data[DEFAULT_SIZE][DEFAULT_SIZE][4];
1222 
1223 	R_CreateDefaultImage();
1224 
1225 	// we use a solid white image instead of disabling texturing
1226 	Com_Memset( data, 255, sizeof( data ) );
1227 	tr.whiteImage = R_CreateImage("*white", (byte *)data, 8, 8, qfalse, qfalse, GL_REPEAT );
1228 
1229 	// with overbright bits active, we need an image which is some fraction of full color,
1230 	// for default lightmaps, etc
1231 	for (x=0 ; x<DEFAULT_SIZE ; x++) {
1232 		for (y=0 ; y<DEFAULT_SIZE ; y++) {
1233 			data[y][x][0] =
1234 			data[y][x][1] =
1235 			data[y][x][2] = tr.identityLightByte;
1236 			data[y][x][3] = 255;
1237 		}
1238 	}
1239 
1240 	tr.identityLightImage = R_CreateImage("*identityLight", (byte *)data, 8, 8, qfalse, qfalse, GL_REPEAT );
1241 
1242 
1243 	for(x=0;x<32;x++) {
1244 		// scratchimage is usually used for cinematic drawing
1245 		tr.scratchImage[x] = R_CreateImage("*scratch", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, qfalse, qtrue, GL_CLAMP_TO_EDGE );
1246 	}
1247 
1248 	R_CreateDlightImage();
1249 	R_CreateFogImage();
1250 }
1251 
1252 
1253 /*
1254 ===============
1255 R_SetColorMappings
1256 ===============
1257 */
R_SetColorMappings(void)1258 void R_SetColorMappings( void ) {
1259 	int		i, j;
1260 	float	g;
1261 	int		inf;
1262 	int		shift;
1263 
1264 	// setup the overbright lighting
1265 	tr.overbrightBits = r_overBrightBits->integer;
1266 	if ( !glConfig.deviceSupportsGamma ) {
1267 		tr.overbrightBits = 0;		// need hardware gamma for overbright
1268 	}
1269 
1270 	// never overbright in windowed mode
1271 	if ( !glConfig.isFullscreen )
1272 	{
1273 		tr.overbrightBits = 0;
1274 	}
1275 
1276 	// allow 2 overbright bits in 24 bit, but only 1 in 16 bit
1277 	if ( glConfig.colorBits > 16 ) {
1278 		if ( tr.overbrightBits > 2 ) {
1279 			tr.overbrightBits = 2;
1280 		}
1281 	} else {
1282 		if ( tr.overbrightBits > 1 ) {
1283 			tr.overbrightBits = 1;
1284 		}
1285 	}
1286 	if ( tr.overbrightBits < 0 ) {
1287 		tr.overbrightBits = 0;
1288 	}
1289 
1290 	tr.identityLight = 1.0f / ( 1 << tr.overbrightBits );
1291 	tr.identityLightByte = 255 * tr.identityLight;
1292 
1293 
1294 	if ( r_intensity->value <= 1 ) {
1295 		ri.Cvar_Set( "r_intensity", "1" );
1296 	}
1297 
1298 	if ( r_gamma->value < 0.5f ) {
1299 		ri.Cvar_Set( "r_gamma", "0.5" );
1300 	} else if ( r_gamma->value > 3.0f ) {
1301 		ri.Cvar_Set( "r_gamma", "3.0" );
1302 	}
1303 
1304 	g = r_gamma->value;
1305 
1306 	shift = tr.overbrightBits;
1307 
1308 	for ( i = 0; i < 256; i++ ) {
1309 		if ( g == 1 ) {
1310 			inf = i;
1311 		} else {
1312 			inf = 255 * pow ( i/255.0f, 1.0f / g ) + 0.5f;
1313 		}
1314 		inf <<= shift;
1315 		if (inf < 0) {
1316 			inf = 0;
1317 		}
1318 		if (inf > 255) {
1319 			inf = 255;
1320 		}
1321 		s_gammatable[i] = inf;
1322 	}
1323 
1324 	for (i=0 ; i<256 ; i++) {
1325 		j = i * r_intensity->value;
1326 		if (j > 255) {
1327 			j = 255;
1328 		}
1329 		s_intensitytable[i] = j;
1330 	}
1331 
1332 	if ( glConfig.deviceSupportsGamma )
1333 	{
1334 		GLimp_SetGamma( s_gammatable, s_gammatable, s_gammatable );
1335 	}
1336 }
1337 
1338 /*
1339 ===============
1340 R_InitImages
1341 ===============
1342 */
R_InitImages(void)1343 void	R_InitImages( void ) {
1344 	Com_Memset(hashTable, 0, sizeof(hashTable));
1345 	// build brightness translation tables
1346 	R_SetColorMappings();
1347 
1348 	// create default texture and white texture
1349 	R_CreateBuiltinImages();
1350 }
1351 
1352 /*
1353 ===============
1354 R_DeleteTextures
1355 ===============
1356 */
R_DeleteTextures(void)1357 void R_DeleteTextures( void ) {
1358 	int		i;
1359 
1360 	for ( i=0; i<tr.numImages ; i++ ) {
1361 		qglDeleteTextures( 1, &tr.images[i]->texnum );
1362 	}
1363 	Com_Memset( tr.images, 0, sizeof( tr.images ) );
1364 
1365 	tr.numImages = 0;
1366 
1367 	Com_Memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) );
1368 	if ( qglActiveTextureARB ) {
1369 		GL_SelectTexture( 1 );
1370 		qglBindTexture( GL_TEXTURE_2D, 0 );
1371 		GL_SelectTexture( 0 );
1372 		qglBindTexture( GL_TEXTURE_2D, 0 );
1373 	} else {
1374 		qglBindTexture( GL_TEXTURE_2D, 0 );
1375 	}
1376 }
1377 
1378 /*
1379 ============================================================================
1380 
1381 SKINS
1382 
1383 ============================================================================
1384 */
1385 
1386 /*
1387 ==================
1388 CommaParse
1389 
1390 This is unfortunate, but the skin files aren't
1391 compatable with our normal parsing rules.
1392 ==================
1393 */
CommaParse(char ** data_p)1394 static char *CommaParse( char **data_p ) {
1395 	int c = 0, len;
1396 	char *data;
1397 	static	char	com_token[MAX_TOKEN_CHARS];
1398 
1399 	data = *data_p;
1400 	len = 0;
1401 	com_token[0] = 0;
1402 
1403 	// make sure incoming data is valid
1404 	if ( !data ) {
1405 		*data_p = NULL;
1406 		return com_token;
1407 	}
1408 
1409 	while ( 1 ) {
1410 		// skip whitespace
1411 		while( (c = *data) <= ' ') {
1412 			if( !c ) {
1413 				break;
1414 			}
1415 			data++;
1416 		}
1417 
1418 
1419 		c = *data;
1420 
1421 		// skip double slash comments
1422 		if ( c == '/' && data[1] == '/' )
1423 		{
1424 			while (*data && *data != '\n')
1425 				data++;
1426 		}
1427 		// skip /* */ comments
1428 		else if ( c=='/' && data[1] == '*' )
1429 		{
1430 			while ( *data && ( *data != '*' || data[1] != '/' ) )
1431 			{
1432 				data++;
1433 			}
1434 			if ( *data )
1435 			{
1436 				data += 2;
1437 			}
1438 		}
1439 		else
1440 		{
1441 			break;
1442 		}
1443 	}
1444 
1445 	if ( c == 0 ) {
1446 		return "";
1447 	}
1448 
1449 	// handle quoted strings
1450 	if (c == '\"')
1451 	{
1452 		data++;
1453 		while (1)
1454 		{
1455 			c = *data++;
1456 			if (c=='\"' || !c)
1457 			{
1458 				com_token[len] = 0;
1459 				*data_p = ( char * ) data;
1460 				return com_token;
1461 			}
1462 			if (len < MAX_TOKEN_CHARS)
1463 			{
1464 				com_token[len] = c;
1465 				len++;
1466 			}
1467 		}
1468 	}
1469 
1470 	// parse a regular word
1471 	do
1472 	{
1473 		if (len < MAX_TOKEN_CHARS)
1474 		{
1475 			com_token[len] = c;
1476 			len++;
1477 		}
1478 		data++;
1479 		c = *data;
1480 	} while (c>32 && c != ',' );
1481 
1482 	if (len == MAX_TOKEN_CHARS)
1483 	{
1484 //		Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS);
1485 		len = 0;
1486 	}
1487 	com_token[len] = 0;
1488 
1489 	*data_p = ( char * ) data;
1490 	return com_token;
1491 }
1492 
1493 
1494 /*
1495 ===============
1496 RE_RegisterSkin
1497 
1498 ===============
1499 */
RE_RegisterSkin(const char * name)1500 qhandle_t RE_RegisterSkin( const char *name ) {
1501 	qhandle_t	hSkin;
1502 	skin_t		*skin;
1503 	skinSurface_t	*surf;
1504 	union {
1505 		char *c;
1506 		void *v;
1507 	} text;
1508 	char		*text_p;
1509 	char		*token;
1510 	char		surfName[MAX_QPATH];
1511 
1512 	if ( !name || !name[0] ) {
1513 		Com_Printf( "Empty name passed to RE_RegisterSkin\n" );
1514 		return 0;
1515 	}
1516 
1517 	if ( strlen( name ) >= MAX_QPATH ) {
1518 		Com_Printf( "Skin name exceeds MAX_QPATH\n" );
1519 		return 0;
1520 	}
1521 
1522 
1523 	// see if the skin is already loaded
1524 	for ( hSkin = 1; hSkin < tr.numSkins ; hSkin++ ) {
1525 		skin = tr.skins[hSkin];
1526 		if ( !Q_stricmp( skin->name, name ) ) {
1527 			if( skin->numSurfaces == 0 ) {
1528 				return 0;		// default skin
1529 			}
1530 			return hSkin;
1531 		}
1532 	}
1533 
1534 	// allocate a new skin
1535 	if ( tr.numSkins == MAX_SKINS ) {
1536 		ri.Printf( PRINT_WARNING, "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name );
1537 		return 0;
1538 	}
1539 	tr.numSkins++;
1540 	skin = ri.Hunk_Alloc( sizeof( skin_t ), h_low );
1541 	tr.skins[hSkin] = skin;
1542 	Q_strncpyz( skin->name, name, sizeof( skin->name ) );
1543 	skin->numSurfaces = 0;
1544 
1545 	// make sure the render thread is stopped
1546 	R_SyncRenderThread();
1547 
1548 	// If not a .skin file, load as a single shader
1549 	if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) {
1550 		skin->numSurfaces = 1;
1551 		skin->surfaces[0] = ri.Hunk_Alloc( sizeof(skin->surfaces[0]), h_low );
1552 		skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue );
1553 		return hSkin;
1554 	}
1555 
1556 	// load and parse the skin file
1557     ri.FS_ReadFile( name, &text.v );
1558 	if ( !text.c ) {
1559 		return 0;
1560 	}
1561 
1562 	text_p = text.c;
1563 	while ( text_p && *text_p ) {
1564 		// get surface name
1565 		token = CommaParse( &text_p );
1566 		Q_strncpyz( surfName, token, sizeof( surfName ) );
1567 
1568 		if ( !token[0] ) {
1569 			break;
1570 		}
1571 		// lowercase the surface name so skin compares are faster
1572 		Q_strlwr( surfName );
1573 
1574 		if ( *text_p == ',' ) {
1575 			text_p++;
1576 		}
1577 
1578 		if ( strstr( token, "tag_" ) ) {
1579 			continue;
1580 		}
1581 
1582 		// parse the shader name
1583 		token = CommaParse( &text_p );
1584 
1585 		surf = skin->surfaces[ skin->numSurfaces ] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
1586 		Q_strncpyz( surf->name, surfName, sizeof( surf->name ) );
1587 		surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue );
1588 		skin->numSurfaces++;
1589 	}
1590 
1591 	ri.FS_FreeFile( text.v );
1592 
1593 
1594 	// never let a skin have 0 shaders
1595 	if ( skin->numSurfaces == 0 ) {
1596 		return 0;		// use default skin
1597 	}
1598 
1599 	return hSkin;
1600 }
1601 
1602 
1603 /*
1604 ===============
1605 R_InitSkins
1606 ===============
1607 */
R_InitSkins(void)1608 void	R_InitSkins( void ) {
1609 	skin_t		*skin;
1610 
1611 	tr.numSkins = 1;
1612 
1613 	// make the default skin have all default shaders
1614 	skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low );
1615 	Q_strncpyz( skin->name, "<default skin>", sizeof( skin->name )  );
1616 	skin->numSurfaces = 1;
1617 	skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces ), h_low );
1618 	skin->surfaces[0]->shader = tr.defaultShader;
1619 }
1620 
1621 /*
1622 ===============
1623 R_GetSkinByHandle
1624 ===============
1625 */
R_GetSkinByHandle(qhandle_t hSkin)1626 skin_t	*R_GetSkinByHandle( qhandle_t hSkin ) {
1627 	if ( hSkin < 1 || hSkin >= tr.numSkins ) {
1628 		return tr.skins[0];
1629 	}
1630 	return tr.skins[ hSkin ];
1631 }
1632 
1633 /*
1634 ===============
1635 R_SkinList_f
1636 ===============
1637 */
R_SkinList_f(void)1638 void	R_SkinList_f( void ) {
1639 	int			i, j;
1640 	skin_t		*skin;
1641 
1642 	ri.Printf (PRINT_ALL, "------------------\n");
1643 
1644 	for ( i = 0 ; i < tr.numSkins ; i++ ) {
1645 		skin = tr.skins[i];
1646 
1647 		ri.Printf( PRINT_ALL, "%3i:%s\n", i, skin->name );
1648 		for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
1649 			ri.Printf( PRINT_ALL, "       %s = %s\n",
1650 				skin->surfaces[j]->name, skin->surfaces[j]->shader->name );
1651 		}
1652 	}
1653 	ri.Printf (PRINT_ALL, "------------------\n");
1654 }
1655 
1656