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