doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Image_init.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "tr_local.h"
33 
34 const char *imageFilter[] = {
35  "GL_LINEAR_MIPMAP_NEAREST",
36  "GL_LINEAR_MIPMAP_LINEAR",
37  "GL_NEAREST",
38  "GL_LINEAR",
39  "GL_NEAREST_MIPMAP_NEAREST",
40  "GL_NEAREST_MIPMAP_LINEAR",
41  NULL
42 };
43 
44 idCVar idImageManager::image_filter( "image_filter", imageFilter[1], CVAR_RENDERER | CVAR_ARCHIVE, "changes texture filtering on mipmapped images", imageFilter, idCmdSystem::ArgCompletion_String<imageFilter> );
45 idCVar idImageManager::image_anisotropy( "image_anisotropy", "1", CVAR_RENDERER | CVAR_ARCHIVE, "set the maximum texture anisotropy if available" );
46 idCVar idImageManager::image_lodbias( "image_lodbias", "0", CVAR_RENDERER | CVAR_ARCHIVE, "change lod bias on mipmapped images" );
47 idCVar idImageManager::image_downSize( "image_downSize", "0", CVAR_RENDERER | CVAR_ARCHIVE, "controls texture downsampling" );
49 idCVar idImageManager::image_roundDown( "image_roundDown", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "round bad sizes down to nearest power of two" );
50 idCVar idImageManager::image_colorMipLevels( "image_colorMipLevels", "0", CVAR_RENDERER | CVAR_BOOL, "development aid to see texture mip usage" );
51 idCVar idImageManager::image_preload( "image_preload", "1", CVAR_RENDERER | CVAR_BOOL | CVAR_ARCHIVE, "if 0, dynamically load all images" );
52 idCVar idImageManager::image_useCompression( "image_useCompression", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "0 = force everything to high quality" );
53 idCVar idImageManager::image_useAllFormats( "image_useAllFormats", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "allow alpha/intensity/luminance/luminance+alpha" );
54 idCVar idImageManager::image_useNormalCompression( "image_useNormalCompression", "2", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "2 = use rxgb compression for normal maps, 1 = use 256 color compression for normal maps if available" );
55 idCVar idImageManager::image_usePrecompressedTextures( "image_usePrecompressedTextures", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "use .dds files if present" );
56 idCVar idImageManager::image_writePrecompressedTextures( "image_writePrecompressedTextures", "0", CVAR_RENDERER | CVAR_BOOL, "write .dds files if necessary" );
57 idCVar idImageManager::image_writeNormalTGA( "image_writeNormalTGA", "0", CVAR_RENDERER | CVAR_BOOL, "write .tgas of the final normal maps for debugging" );
58 idCVar idImageManager::image_writeNormalTGAPalletized( "image_writeNormalTGAPalletized", "0", CVAR_RENDERER | CVAR_BOOL, "write .tgas of the final palletized normal maps for debugging" );
59 idCVar idImageManager::image_writeTGA( "image_writeTGA", "0", CVAR_RENDERER | CVAR_BOOL, "write .tgas of the non normal maps for debugging" );
60 idCVar idImageManager::image_useOffLineCompression( "image_useOfflineCompression", "0", CVAR_RENDERER | CVAR_BOOL, "write a batch file for offline compression of DDS files" );
61 idCVar idImageManager::image_cacheMinK( "image_cacheMinK", "200", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "maximum KB of precompressed files to read at specification time" );
62 idCVar idImageManager::image_cacheMegs( "image_cacheMegs", "20", CVAR_RENDERER | CVAR_ARCHIVE, "maximum MB set aside for temporary loading of full-sized precompressed images" );
63 idCVar idImageManager::image_useCache( "image_useCache", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "1 = do background load image caching" );
64 idCVar idImageManager::image_showBackgroundLoads( "image_showBackgroundLoads", "0", CVAR_RENDERER | CVAR_BOOL, "1 = print number of outstanding background loads" );
65 idCVar idImageManager::image_downSizeSpecular( "image_downSizeSpecular", "0", CVAR_RENDERER | CVAR_ARCHIVE, "controls specular downsampling" );
66 idCVar idImageManager::image_downSizeBump( "image_downSizeBump", "0", CVAR_RENDERER | CVAR_ARCHIVE, "controls normal map downsampling" );
67 idCVar idImageManager::image_downSizeSpecularLimit( "image_downSizeSpecularLimit", "64", CVAR_RENDERER | CVAR_ARCHIVE, "controls specular downsampled limit" );
68 idCVar idImageManager::image_downSizeBumpLimit( "image_downSizeBumpLimit", "128", CVAR_RENDERER | CVAR_ARCHIVE, "controls normal map downsample limit" );
69 idCVar idImageManager::image_ignoreHighQuality( "image_ignoreHighQuality", "0", CVAR_RENDERER | CVAR_ARCHIVE, "ignore high quality setting on materials" );
70 idCVar idImageManager::image_downSizeLimit( "image_downSizeLimit", "256", CVAR_RENDERER | CVAR_ARCHIVE, "controls diffuse map downsample limit" );
71 // do this with a pointer, in case we want to make the actual manager
72 // a private virtual subclass
75 
76 
88 };
89 
91  const char *rootPath;
92  const char *desc;
93  int type;
94  int maxWidth;
95  int maxHeight;
96 };
97 
99 
101  { "models/characters", "Characters", IC_NPC, 512, 512 },
102  { "models/weapons", "Weapons", IC_WEAPON, 512, 512 },
103  { "models/monsters", "Monsters", IC_MONSTER, 512, 512 },
104  { "models/mapobjects", "Model Geometry", IC_MODELGEOMETRY, 512, 512 },
105  { "models/items", "Items", IC_ITEMS, 512, 512 },
106  { "models", "Other model textures", IC_MODELSOTHER, 512, 512 },
107  { "guis/assets", "Guis", IC_GUIS, 256, 256 },
108  { "textures", "World Geometry", IC_WORLDGEOMETRY, 256, 256 },
109  { "", "Other", IC_OTHER, 256, 256 }
110 };
111 
112 
113 
114 static int ClassifyImage( const char *name ) {
115  idStr str;
116  str = name;
117  for ( int i = 0; i < IC_COUNT; i++ ) {
118  if ( str.Find( IC_Info[i].rootPath, false ) == 0 ) {
119  return IC_Info[i].type;
120  }
121  }
122  return IC_OTHER;
123 }
124 
125 /*
126 ================
127 R_RampImage
128 
129 Creates a 0-255 ramp image
130 ================
131 */
132 static void R_RampImage( idImage *image ) {
133  int x;
134  byte data[256][4];
135 
136  for (x=0 ; x<256 ; x++) {
137  data[x][0] =
138  data[x][1] =
139  data[x][2] =
140  data[x][3] = x;
141  }
142 
143  image->GenerateImage( (byte *)data, 256, 1,
145 }
146 
147 /*
148 ================
149 R_SpecularTableImage
150 
151 Creates a ramp that matches our fudged specular calculation
152 ================
153 */
154 static void R_SpecularTableImage( idImage *image ) {
155  int x;
156  byte data[256][4];
157 
158  for (x=0 ; x<256 ; x++) {
159  float f = x/255.f;
160 #if 0
161  f = pow(f, 16);
162 #else
163  // this is the behavior of the hacked up fragment programs that
164  // can't really do a power function
165  f = (f-0.75)*4;
166  if ( f < 0 ) {
167  f = 0;
168  }
169  f = f * f;
170 #endif
171  int b = (int)(f * 255);
172 
173  data[x][0] =
174  data[x][1] =
175  data[x][2] =
176  data[x][3] = b;
177  }
178 
179  image->GenerateImage( (byte *)data, 256, 1,
181 }
182 
183 
184 /*
185 ================
186 R_Specular2DTableImage
187 
188 Create a 2D table that calculates ( reflection dot , specularity )
189 ================
190 */
191 static void R_Specular2DTableImage( idImage *image ) {
192  int x, y;
193  byte data[256][256][4];
194 
195  memset( data, 0, sizeof( data ) );
196  for ( x = 0 ; x < 256 ; x++ ) {
197  float f = x / 255.0f;
198  for ( y = 0; y < 256; y++ ) {
199 
200  int b = (int)( pow( f, y ) * 255.0f );
201  if ( b == 0 ) {
202  // as soon as b equals zero all remaining values in this column are going to be zero
203  // we early out to avoid pow() underflows
204  break;
205  }
206 
207  data[y][x][0] =
208  data[y][x][1] =
209  data[y][x][2] =
210  data[y][x][3] = b;
211  }
212  }
213 
214  image->GenerateImage( (byte *)data, 256, 256, TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY );
215 }
216 
217 
218 
219 /*
220 ================
221 R_AlphaRampImage
222 
223 Creates a 0-255 ramp image
224 ================
225 */
226 static void R_AlphaRampImage( idImage *image ) {
227  int x;
228  byte data[256][4];
229 
230  for (x=0 ; x<256 ; x++) {
231  data[x][0] =
232  data[x][1] =
233  data[x][2] = 255;
234  data[x][3] = x;
235  }
236 
237  image->GenerateImage( (byte *)data, 256, 1,
239 }
240 
241 
242 
243 /*
244 ==================
245 R_CreateDefaultImage
246 
247 the default image will be grey with a white box outline
248 to allow you to see the mapping coordinates on a surface
249 ==================
250 */
251 #define DEFAULT_SIZE 16
253  int x, y;
254  byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
255 
256  if ( com_developer.GetBool() ) {
257  // grey center
258  for ( y = 0 ; y < DEFAULT_SIZE ; y++ ) {
259  for ( x = 0 ; x < DEFAULT_SIZE ; x++ ) {
260  data[y][x][0] = 32;
261  data[y][x][1] = 32;
262  data[y][x][2] = 32;
263  data[y][x][3] = 255;
264  }
265  }
266 
267  // white border
268  for ( x = 0 ; x < DEFAULT_SIZE ; x++ ) {
269  data[0][x][0] =
270  data[0][x][1] =
271  data[0][x][2] =
272  data[0][x][3] = 255;
273 
274  data[x][0][0] =
275  data[x][0][1] =
276  data[x][0][2] =
277  data[x][0][3] = 255;
278 
279  data[DEFAULT_SIZE-1][x][0] =
280  data[DEFAULT_SIZE-1][x][1] =
281  data[DEFAULT_SIZE-1][x][2] =
282  data[DEFAULT_SIZE-1][x][3] = 255;
283 
284  data[x][DEFAULT_SIZE-1][0] =
285  data[x][DEFAULT_SIZE-1][1] =
286  data[x][DEFAULT_SIZE-1][2] =
287  data[x][DEFAULT_SIZE-1][3] = 255;
288  }
289  } else {
290  for ( y = 0 ; y < DEFAULT_SIZE ; y++ ) {
291  for ( x = 0 ; x < DEFAULT_SIZE ; x++ ) {
292  data[y][x][0] = 0;
293  data[y][x][1] = 0;
294  data[y][x][2] = 0;
295  data[y][x][3] = 0;
296  }
297  }
298  }
299 
300  GenerateImage( (byte *)data,
302  TF_DEFAULT, true, TR_REPEAT, TD_DEFAULT );
303 
304  defaulted = true;
305 }
306 
307 static void R_DefaultImage( idImage *image ) {
308  image->MakeDefault();
309 }
310 
311 static void R_WhiteImage( idImage *image ) {
312  byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
313 
314  // solid white texture
315  memset( data, 255, sizeof( data ) );
316  image->GenerateImage( (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE,
317  TF_DEFAULT, false, TR_REPEAT, TD_DEFAULT );
318 }
319 
320 static void R_BlackImage( idImage *image ) {
321  byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
322 
323  // solid black texture
324  memset( data, 0, sizeof( data ) );
325  image->GenerateImage( (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE,
326  TF_DEFAULT, false, TR_REPEAT, TD_DEFAULT );
327 }
328 
329 
330 // the size determines how far away from the edge the blocks start fading
331 static const int BORDER_CLAMP_SIZE = 32;
332 static void R_BorderClampImage( idImage *image ) {
333  byte data[BORDER_CLAMP_SIZE][BORDER_CLAMP_SIZE][4];
334 
335  // solid white texture with a single pixel black border
336  memset( data, 255, sizeof( data ) );
337  for ( int i = 0 ; i < BORDER_CLAMP_SIZE ; i++ ) {
338  data[i][0][0] =
339  data[i][0][1] =
340  data[i][0][2] =
341  data[i][0][3] =
342 
343  data[i][BORDER_CLAMP_SIZE-1][0] =
344  data[i][BORDER_CLAMP_SIZE-1][1] =
345  data[i][BORDER_CLAMP_SIZE-1][2] =
346  data[i][BORDER_CLAMP_SIZE-1][3] =
347 
348  data[0][i][0] =
349  data[0][i][1] =
350  data[0][i][2] =
351  data[0][i][3] =
352 
353  data[BORDER_CLAMP_SIZE-1][i][0] =
354  data[BORDER_CLAMP_SIZE-1][i][1] =
355  data[BORDER_CLAMP_SIZE-1][i][2] =
356  data[BORDER_CLAMP_SIZE-1][i][3] = 0;
357  }
358 
359  image->GenerateImage( (byte *)data, BORDER_CLAMP_SIZE, BORDER_CLAMP_SIZE,
360  TF_LINEAR /* TF_NEAREST */, false, TR_CLAMP_TO_BORDER, TD_DEFAULT );
361 
362  if ( !glConfig.isInitialized ) {
363  // can't call qglTexParameterfv yet
364  return;
365  }
366  // explicit zero border
367  float color[4];
368  color[0] = color[1] = color[2] = color[3] = 0;
369  qglTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color );
370 }
371 
372 static void R_RGBA8Image( idImage *image ) {
373  byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
374 
375  memset( data, 0, sizeof( data ) );
376  data[0][0][0] = 16;
377  data[0][0][1] = 32;
378  data[0][0][2] = 48;
379  data[0][0][3] = 96;
380 
381  image->GenerateImage( (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE,
383 }
384 
385 static void R_RGB8Image( idImage *image ) {
386  byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
387 
388  memset( data, 0, sizeof( data ) );
389  data[0][0][0] = 16;
390  data[0][0][1] = 32;
391  data[0][0][2] = 48;
392  data[0][0][3] = 255;
393 
394  image->GenerateImage( (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE,
396 }
397 
398 static void R_AlphaNotchImage( idImage *image ) {
399  byte data[2][4];
400 
401  // this is used for alpha test clip planes
402 
403  data[0][0] = data[0][1] = data[0][2] = 255;
404  data[0][3] = 0;
405  data[1][0] = data[1][1] = data[1][2] = 255;
406  data[1][3] = 255;
407 
408  image->GenerateImage( (byte *)data, 2, 1,
410 }
411 
412 static void R_FlatNormalImage( idImage *image ) {
413  byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
414  int i;
415 
416  int red = ( globalImages->image_useNormalCompression.GetInteger() == 1 ) ? 0 : 3;
417  int alpha = ( red == 0 ) ? 3 : 0;
418  // flat normal map for default bunp mapping
419  for ( i = 0 ; i < 4 ; i++ ) {
420  data[0][i][red] = 128;
421  data[0][i][1] = 128;
422  data[0][i][2] = 255;
423  data[0][i][alpha] = 255;
424  }
425  image->GenerateImage( (byte *)data, 2, 2,
427 }
428 
429 static void R_AmbientNormalImage( idImage *image ) {
430  byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
431  int i;
432 
433  int red = ( globalImages->image_useNormalCompression.GetInteger() == 1 ) ? 0 : 3;
434  int alpha = ( red == 0 ) ? 3 : 0;
435  // flat normal map for default bunp mapping
436  for ( i = 0 ; i < 4 ; i++ ) {
437  data[0][i][red] = (byte)(255 * tr.ambientLightVector[0]);
438  data[0][i][1] = (byte)(255 * tr.ambientLightVector[1]);
439  data[0][i][2] = (byte)(255 * tr.ambientLightVector[2]);
440  data[0][i][alpha] = 255;
441  }
442  const byte *pics[6];
443  for ( i = 0 ; i < 6 ; i++ ) {
444  pics[i] = data[0][0];
445  }
446  // this must be a cube map for fragment programs to simply substitute for the normalization cube map
447  image->GenerateCubeImage( pics, 2, TF_DEFAULT, true, TD_HIGH_QUALITY );
448 }
449 
450 
451 static void CreateSquareLight( void ) {
452  byte *buffer;
453  int x, y;
454  int dx, dy;
455  int d;
456  int width, height;
457 
458  width = height = 128;
459 
460  buffer = (byte *)R_StaticAlloc( 128 * 128 * 4 );
461 
462  for ( x = 0 ; x < 128 ; x++ ) {
463  if ( x < 32 ) {
464  dx = 32 - x;
465  } else if ( x > 96 ) {
466  dx = x - 96;
467  } else {
468  dx = 0;
469  }
470  for ( y = 0 ; y < 128 ; y++ ) {
471  if ( y < 32 ) {
472  dy = 32 - y;
473  } else if ( y > 96 ) {
474  dy = y - 96;
475  } else {
476  dy = 0;
477  }
478  d = (byte)idMath::Sqrt( dx * dx + dy * dy );
479  if ( d > 32 ) {
480  d = 32;
481  }
482  d = 255 - d * 8;
483  if ( d < 0 ) {
484  d = 0;
485  }
486  buffer[(y*128+x)*4+0] =
487  buffer[(y*128+x)*4+1] =
488  buffer[(y*128+x)*4+2] = d;
489  buffer[(y*128+x)*4+3] = 255;
490  }
491  }
492 
493  R_WriteTGA( "lights/squarelight.tga", buffer, width, height );
494 
495  R_StaticFree( buffer );
496 }
497 
498 static void CreateFlashOff( void ) {
499  byte *buffer;
500  int x, y;
501  int d;
502  int width, height;
503 
504  width = 256;
505  height = 4;
506 
507  buffer = (byte *)R_StaticAlloc( width * height * 4 );
508 
509  for ( x = 0 ; x < width ; x++ ) {
510  for ( y = 0 ; y < height ; y++ ) {
511  d = 255 - ( x * 256 / width );
512  buffer[(y*width+x)*4+0] =
513  buffer[(y*width+x)*4+1] =
514  buffer[(y*width+x)*4+2] = d;
515  buffer[(y*width+x)*4+3] = 255;
516  }
517  }
518 
519  R_WriteTGA( "lights/flashoff.tga", buffer, width, height );
520 
521  R_StaticFree( buffer );
522 }
523 
524 
525 /*
526 ===============
527 CreatePitFogImage
528 ===============
529 */
530 void CreatePitFogImage( void ) {
531  byte data[16][16][4];
532  int i, j;
533 
534  memset( data, 0, sizeof( data ) );
535  for ( i = 0 ; i < 16 ; i++ ) {
536  int a;
537 
538 #if 0
539  if ( i > 14 ) {
540  a = 0;
541  } else
542 #endif
543  {
544  a = i * 255 / 15;
545  if ( a > 255 ) {
546  a = 255;
547  }
548  }
549 
550  for ( j = 0 ; j < 16 ; j++ ) {
551  data[j][i][0] =
552  data[j][i][1] =
553  data[j][i][2] = 255;
554  data[j][i][3] = a;
555  }
556  }
557 
558  R_WriteTGA( "shapes/pitFalloff.tga", data[0][0], 16, 16 );
559 }
560 
561 /*
562 ===============
563 CreatealphaSquareImage
564 ===============
565 */
567  byte data[16][16][4];
568  int i, j;
569 
570  for ( i = 0 ; i < 16 ; i++ ) {
571  int a;
572 
573  for ( j = 0 ; j < 16 ; j++ ) {
574  if ( i == 0 || i == 15 || j == 0 || j == 15 ) {
575  a = 0;
576  } else {
577  a = 255;
578  }
579  data[j][i][0] =
580  data[j][i][1] =
581  data[j][i][2] = 255;
582  data[j][i][3] = a;
583  }
584  }
585 
586  R_WriteTGA( "shapes/alphaSquare.tga", data[0][0], 16, 16 );
587 }
588 
589 #define NORMAL_MAP_SIZE 32
590 
591 /*** NORMALIZATION CUBE MAP CONSTRUCTION ***/
592 
593 /* Given a cube map face index, cube map size, and integer 2D face position,
594  * return the cooresponding normalized vector.
595  */
596 static void getCubeVector(int i, int cubesize, int x, int y, float *vector) {
597  float s, t, sc, tc, mag;
598 
599  s = ((float)x + 0.5) / (float)cubesize;
600  t = ((float)y + 0.5) / (float)cubesize;
601  sc = s*2.0 - 1.0;
602  tc = t*2.0 - 1.0;
603 
604  switch (i) {
605  case 0:
606  vector[0] = 1.0;
607  vector[1] = -tc;
608  vector[2] = -sc;
609  break;
610  case 1:
611  vector[0] = -1.0;
612  vector[1] = -tc;
613  vector[2] = sc;
614  break;
615  case 2:
616  vector[0] = sc;
617  vector[1] = 1.0;
618  vector[2] = tc;
619  break;
620  case 3:
621  vector[0] = sc;
622  vector[1] = -1.0;
623  vector[2] = -tc;
624  break;
625  case 4:
626  vector[0] = sc;
627  vector[1] = -tc;
628  vector[2] = 1.0;
629  break;
630  case 5:
631  vector[0] = -sc;
632  vector[1] = -tc;
633  vector[2] = -1.0;
634  break;
635  }
636 
637  mag = idMath::InvSqrt(vector[0]*vector[0] + vector[1]*vector[1] + vector[2]*vector[2]);
638  vector[0] *= mag;
639  vector[1] *= mag;
640  vector[2] *= mag;
641 }
642 
643 /* Initialize a cube map texture object that generates RGB values
644  * that when expanded to a [-1,1] range in the register combiners
645  * form a normalized vector matching the per-pixel vector used to
646  * access the cube map.
647  */
648 static void makeNormalizeVectorCubeMap( idImage *image ) {
649  float vector[3];
650  int i, x, y;
651  byte *pixels[6];
652  int size;
653 
654  size = NORMAL_MAP_SIZE;
655 
656  pixels[0] = (GLubyte*) Mem_Alloc(size*size*4*6);
657 
658  for (i = 0; i < 6; i++) {
659  pixels[i] = pixels[0] + i*size*size*4;
660  for (y = 0; y < size; y++) {
661  for (x = 0; x < size; x++) {
662  getCubeVector(i, size, x, y, vector);
663  pixels[i][4*(y*size+x) + 0] = (byte)(128 + 127*vector[0]);
664  pixels[i][4*(y*size+x) + 1] = (byte)(128 + 127*vector[1]);
665  pixels[i][4*(y*size+x) + 2] = (byte)(128 + 127*vector[2]);
666  pixels[i][4*(y*size+x) + 3] = 255;
667  }
668  }
669  }
670 
671  image->GenerateCubeImage( (const byte **)pixels, size,
672  TF_LINEAR, false, TD_HIGH_QUALITY );
673 
674  Mem_Free(pixels[0]);
675 }
676 
677 
678 
679 
680 /*
681 ================
682 R_CreateNoFalloffImage
683 
684 This is a solid white texture that is zero clamped.
685 ================
686 */
687 static void R_CreateNoFalloffImage( idImage *image ) {
688  int x,y;
689  byte data[16][FALLOFF_TEXTURE_SIZE][4];
690 
691  memset( data, 0, sizeof( data ) );
692  for (x=1 ; x<FALLOFF_TEXTURE_SIZE-1 ; x++) {
693  for (y=1 ; y<15 ; y++) {
694  data[y][x][0] = 255;
695  data[y][x][1] = 255;
696  data[y][x][2] = 255;
697  data[y][x][3] = 255;
698  }
699  }
700  image->GenerateImage( (byte *)data, FALLOFF_TEXTURE_SIZE, 16,
702 }
703 
704 
705 /*
706 ================
707 R_FogImage
708 
709 We calculate distance correctly in two planes, but the
710 third will still be projection based
711 ================
712 */
713 const int FOG_SIZE = 128;
714 
715 void R_FogImage( idImage *image ) {
716  int x,y;
717  byte data[FOG_SIZE][FOG_SIZE][4];
718  int b;
719 
720 float step[256];
721 int i;
722 float remaining = 1.0;
723 for ( i = 0 ; i < 256 ; i++ ) {
724  step[i] = remaining;
725  remaining *= 0.982f;
726 }
727 
728  for (x=0 ; x<FOG_SIZE ; x++) {
729  for (y=0 ; y<FOG_SIZE ; y++) {
730  float d;
731 
732  d = idMath::Sqrt( (x - FOG_SIZE/2) * (x - FOG_SIZE/2)
733  + (y - FOG_SIZE/2) * (y - FOG_SIZE / 2) );
734  d /= FOG_SIZE/2-1;
735 
736  b = (byte)(d * 255);
737  if ( b <= 0 ) {
738  b = 0;
739  } else if ( b > 255 ) {
740  b = 255;
741  }
742 b = (byte)(255 * ( 1.0 - step[b] ));
743  if ( x == 0 || x == FOG_SIZE-1 || y == 0 || y == FOG_SIZE-1 ) {
744  b = 255; // avoid clamping issues
745  }
746  data[y][x][0] =
747  data[y][x][1] =
748  data[y][x][2] = 255;
749  data[y][x][3] = b;
750  }
751  }
752 
753  image->GenerateImage( (byte *)data, FOG_SIZE, FOG_SIZE,
755 }
756 
757 
758 /*
759 ================
760 FogFraction
761 
762 Height values below zero are inside the fog volume
763 ================
764 */
765 static const float RAMP_RANGE = 8;
766 static const float DEEP_RANGE = -30;
767 static float FogFraction( float viewHeight, float targetHeight ) {
768  float total = idMath::Fabs( targetHeight - viewHeight );
769 
770 // return targetHeight >= 0 ? 0 : 1.0;
771 
772  // only ranges that cross the ramp range are special
773  if ( targetHeight > 0 && viewHeight > 0 ) {
774  return 0.0;
775  }
776  if ( targetHeight < -RAMP_RANGE && viewHeight < -RAMP_RANGE ) {
777  return 1.0;
778  }
779 
780  float above;
781  if ( targetHeight > 0 ) {
782  above = targetHeight;
783  } else if ( viewHeight > 0 ) {
784  above = viewHeight;
785  } else {
786  above = 0;
787  }
788 
789  float rampTop, rampBottom;
790 
791  if ( viewHeight > targetHeight ) {
792  rampTop = viewHeight;
793  rampBottom = targetHeight;
794  } else {
795  rampTop = targetHeight;
796  rampBottom = viewHeight;
797  }
798  if ( rampTop > 0 ) {
799  rampTop = 0;
800  }
801  if ( rampBottom < -RAMP_RANGE ) {
802  rampBottom = -RAMP_RANGE;
803  }
804 
805  float rampSlope = 1.0 / RAMP_RANGE;
806 
807  if ( !total ) {
808  return -viewHeight * rampSlope;
809  }
810 
811  float ramp = ( 1.0 - ( rampTop * rampSlope + rampBottom * rampSlope ) * -0.5 ) * ( rampTop - rampBottom );
812 
813  float frac = ( total - above - ramp ) / total;
814 
815  // after it gets moderately deep, always use full value
816  float deepest = viewHeight < targetHeight ? viewHeight : targetHeight;
817 
818  float deepFrac = deepest / DEEP_RANGE;
819  if ( deepFrac >= 1.0 ) {
820  return 1.0;
821  }
822 
823  frac = frac * ( 1.0 - deepFrac ) + deepFrac;
824 
825  return frac;
826 }
827 
828 /*
829 ================
830 R_FogEnterImage
831 
832 Modulate the fog alpha density based on the distance of the
833 start and end points to the terminator plane
834 ================
835 */
836 void R_FogEnterImage( idImage *image ) {
837  int x,y;
839  int b;
840 
841  for (x=0 ; x<FOG_ENTER_SIZE ; x++) {
842  for (y=0 ; y<FOG_ENTER_SIZE ; y++) {
843  float d;
844 
845  d = FogFraction( x - (FOG_ENTER_SIZE / 2), y - (FOG_ENTER_SIZE / 2) );
846 
847  b = (byte)(d * 255);
848  if ( b <= 0 ) {
849  b = 0;
850  } else if ( b > 255 ) {
851  b = 255;
852  }
853  data[y][x][0] =
854  data[y][x][1] =
855  data[y][x][2] = 255;
856  data[y][x][3] = b;
857  }
858  }
859 
860  // if mipmapped, acutely viewed surfaces fade wrong
861  image->GenerateImage( (byte *)data, FOG_ENTER_SIZE, FOG_ENTER_SIZE,
863 }
864 
865 
866 /*
867 ================
868 R_QuadraticImage
869 
870 ================
871 */
872 static const int QUADRATIC_WIDTH = 32;
873 static const int QUADRATIC_HEIGHT = 4;
874 
875 void R_QuadraticImage( idImage *image ) {
876  int x,y;
877  byte data[QUADRATIC_HEIGHT][QUADRATIC_WIDTH][4];
878  int b;
879 
880 
881  for (x=0 ; x<QUADRATIC_WIDTH ; x++) {
882  for (y=0 ; y<QUADRATIC_HEIGHT ; y++) {
883  float d;
884 
885  d = x - (QUADRATIC_WIDTH/2 - 0.5);
886  d = idMath::Fabs( d );
887  d -= 0.5;
888  d /= QUADRATIC_WIDTH/2;
889 
890  d = 1.0 - d;
891  d = d * d;
892 
893  b = (byte)(d * 255);
894  if ( b <= 0 ) {
895  b = 0;
896  } else if ( b > 255 ) {
897  b = 255;
898  }
899  data[y][x][0] =
900  data[y][x][1] =
901  data[y][x][2] = b;
902  data[y][x][3] = 255;
903  }
904  }
905 
906  image->GenerateImage( (byte *)data, QUADRATIC_WIDTH, QUADRATIC_HEIGHT,
908 }
909 
910 //=====================================================================
911 
912 
913 typedef struct {
914  char *name;
915  int minimize, maximize;
916 } filterName_t;
917 
918 
919 
920 /*
921 ===============
922 ChangeTextureFilter
923 
924 This resets filtering on all loaded images
925 New images will automatically pick up the current values.
926 ===============
927 */
929  int i;
930  idImage *glt;
931  const char *string;
932 static filterName_t textureFilters[] = {
933  {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
934  {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR},
935  {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
936  {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
937  {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
938  {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}
939 };
940 
941  // if these are changed dynamically, it will force another ChangeTextureFilter
945 
946  string = image_filter.GetString();
947  for ( i = 0; i < 6; i++ ) {
948  if ( !idStr::Icmp( textureFilters[i].name, string ) ) {
949  break;
950  }
951  }
952 
953  if ( i == 6 ) {
954  common->Warning( "bad r_textureFilter: '%s'", string);
955  // default to LINEAR_MIPMAP_NEAREST
956  i = 0;
957  }
958 
959  // set the values for future images
960  textureMinFilter = textureFilters[i].minimize;
961  textureMaxFilter = textureFilters[i].maximize;
963  if ( textureAnisotropy < 1 ) {
964  textureAnisotropy = 1;
967  }
969 
970  // change all the existing mipmap texture objects with default filtering
971 
972  for ( i = 0 ; i < images.Num() ; i++ ) {
973  unsigned int texEnum = GL_TEXTURE_2D;
974 
975  glt = images[ i ];
976 
977  switch( glt->type ) {
978  case TT_2D:
979  texEnum = GL_TEXTURE_2D;
980  break;
981  case TT_3D:
982  texEnum = GL_TEXTURE_3D;
983  break;
984  case TT_CUBIC:
985  texEnum = GL_TEXTURE_CUBE_MAP_EXT;
986  break;
987  }
988 
989  // make sure we don't start a background load
990  if ( glt->texnum == idImage::TEXTURE_NOT_LOADED ) {
991  continue;
992  }
993  glt->Bind();
994  if ( glt->filter == TF_DEFAULT ) {
995  qglTexParameterf(texEnum, GL_TEXTURE_MIN_FILTER, globalImages->textureMinFilter );
996  qglTexParameterf(texEnum, GL_TEXTURE_MAG_FILTER, globalImages->textureMaxFilter );
997  }
1000  }
1002  qglTexParameterf(texEnum, GL_TEXTURE_LOD_BIAS_EXT, globalImages->textureLODBias );
1003  }
1004  }
1005 }
1006 
1007 /*
1008 ===============
1009 idImage::Reload
1010 ===============
1011 */
1012 void idImage::Reload( bool checkPrecompressed, bool force ) {
1013  // always regenerate functional images
1014  if ( generatorFunction ) {
1015  common->DPrintf( "regenerating %s.\n", imgName.c_str() );
1016  generatorFunction( this );
1017  return;
1018  }
1019 
1020  // check file times
1021  if ( !force ) {
1022  ID_TIME_T current;
1023 
1024  if ( cubeFiles != CF_2D ) {
1025  R_LoadCubeImages( imgName, cubeFiles, NULL, NULL, &current );
1026  } else {
1027  // get the current values
1028  R_LoadImageProgram( imgName, NULL, NULL, NULL, &current );
1029  }
1030  if ( current <= timestamp ) {
1031  return;
1032  }
1033  }
1034 
1035  common->DPrintf( "reloading %s.\n", imgName.c_str() );
1036 
1037  PurgeImage();
1038 
1039  // force no precompressed image check, which will cause it to be reloaded
1040  // from source, and another precompressed file generated.
1041  // Load is from the front end, so the back end must be synced
1042  ActuallyLoadImage( checkPrecompressed, false );
1043 }
1044 
1045 /*
1046 ===============
1047 R_ReloadImages_f
1048 
1049 Regenerate all images that came directly from files that have changed, so
1050 any saved changes will show up in place.
1051 
1052 New r_texturesize/r_texturedepth variables will take effect on reload
1053 
1054 reloadImages <all>
1055 ===============
1056 */
1057 void R_ReloadImages_f( const idCmdArgs &args ) {
1058  int i;
1059  idImage *image;
1060  bool all;
1061  bool checkPrecompressed;
1062 
1063  // this probably isn't necessary...
1064  globalImages->ChangeTextureFilter();
1065 
1066  all = false;
1067  checkPrecompressed = false; // if we are doing this as a vid_restart, look for precompressed like normal
1068 
1069  if ( args.Argc() == 2 ) {
1070  if ( !idStr::Icmp( args.Argv(1), "all" ) ) {
1071  all = true;
1072  } else if ( !idStr::Icmp( args.Argv(1), "reload" ) ) {
1073  all = true;
1074  checkPrecompressed = true;
1075  } else {
1076  common->Printf( "USAGE: reloadImages <all>\n" );
1077  return;
1078  }
1079  }
1080 
1081  for ( i = 0 ; i < globalImages->images.Num() ; i++ ) {
1082  image = globalImages->images[ i ];
1083  image->Reload( checkPrecompressed, all );
1084  }
1085 }
1086 
1087 typedef struct {
1089  int size;
1090 } sortedImage_t;
1091 
1092 /*
1093 =======================
1094 R_QsortImageSizes
1095 
1096 =======================
1097 */
1098 static int R_QsortImageSizes( const void *a, const void *b ) {
1099  const sortedImage_t *ea, *eb;
1100 
1101  ea = (sortedImage_t *)a;
1102  eb = (sortedImage_t *)b;
1103 
1104  if ( ea->size > eb->size ) {
1105  return -1;
1106  }
1107  if ( ea->size < eb->size ) {
1108  return 1;
1109  }
1110  return idStr::Icmp( ea->image->imgName, eb->image->imgName );
1111 }
1112 
1113 /*
1114 ===============
1115 R_ListImages_f
1116 ===============
1117 */
1118 void R_ListImages_f( const idCmdArgs &args ) {
1119  int i, j, partialSize;
1120  idImage *image;
1121  int totalSize;
1122  int count = 0;
1123  int matchTag = 0;
1124  bool uncompressedOnly = false;
1125  bool unloaded = false;
1126  bool partial = false;
1127  bool cached = false;
1128  bool uncached = false;
1129  bool failed = false;
1130  bool touched = false;
1131  bool sorted = false;
1132  bool duplicated = false;
1133  bool byClassification = false;
1134  bool overSized = false;
1135 
1136  if ( args.Argc() == 1 ) {
1137 
1138  } else if ( args.Argc() == 2 ) {
1139  if ( idStr::Icmp( args.Argv( 1 ), "uncompressed" ) == 0 ) {
1140  uncompressedOnly = true;
1141  } else if ( idStr::Icmp( args.Argv( 1 ), "sorted" ) == 0 ) {
1142  sorted = true;
1143  } else if ( idStr::Icmp( args.Argv( 1 ), "partial" ) == 0 ) {
1144  partial = true;
1145  } else if ( idStr::Icmp( args.Argv( 1 ), "unloaded" ) == 0 ) {
1146  unloaded = true;
1147  } else if ( idStr::Icmp( args.Argv( 1 ), "cached" ) == 0 ) {
1148  cached = true;
1149  } else if ( idStr::Icmp( args.Argv( 1 ), "uncached" ) == 0 ) {
1150  uncached = true;
1151  } else if ( idStr::Icmp( args.Argv( 1 ), "tagged" ) == 0 ) {
1152  matchTag = 1;
1153  } else if ( idStr::Icmp( args.Argv( 1 ), "duplicated" ) == 0 ) {
1154  duplicated = true;
1155  } else if ( idStr::Icmp( args.Argv( 1 ), "touched" ) == 0 ) {
1156  touched = true;
1157  } else if ( idStr::Icmp( args.Argv( 1 ), "classify" ) == 0 ) {
1158  byClassification = true;
1159  sorted = true;
1160  } else if ( idStr::Icmp( args.Argv( 1 ), "oversized" ) == 0 ) {
1161  byClassification = true;
1162  sorted = true;
1163  overSized = true;
1164  } else {
1165  failed = true;
1166  }
1167  } else {
1168  failed = true;
1169  }
1170 
1171  if ( failed ) {
1172  common->Printf( "usage: listImages [ sorted | partial | unloaded | cached | uncached | tagged | duplicated | touched | classify | showOverSized ]\n" );
1173  return;
1174  }
1175 
1176  const char *header = " -w-- -h-- filt -fmt-- wrap size --name-------\n";
1177  common->Printf( "\n%s", header );
1178 
1179  totalSize = 0;
1180 
1181  sortedImage_t *sortedArray = (sortedImage_t *)alloca( sizeof( sortedImage_t ) * globalImages->images.Num() );
1182 
1183  for ( i = 0 ; i < globalImages->images.Num() ; i++ ) {
1184  image = globalImages->images[ i ];
1185 
1186  if ( uncompressedOnly ) {
1188  || image->internalFormat == GL_COLOR_INDEX8_EXT ) {
1189  continue;
1190  }
1191  }
1192 
1193  if ( matchTag && image->classification != matchTag ) {
1194  continue;
1195  }
1196  if ( unloaded && image->texnum != idImage::TEXTURE_NOT_LOADED ) {
1197  continue;
1198  }
1199  if ( partial && !image->isPartialImage ) {
1200  continue;
1201  }
1202  if ( cached && ( !image->partialImage || image->texnum == idImage::TEXTURE_NOT_LOADED ) ) {
1203  continue;
1204  }
1205  if ( uncached && ( !image->partialImage || image->texnum != idImage::TEXTURE_NOT_LOADED ) ) {
1206  continue;
1207  }
1208 
1209  // only print duplicates (from mismatched wrap / clamp, etc)
1210  if ( duplicated ) {
1211  int j;
1212  for ( j = i+1 ; j < globalImages->images.Num() ; j++ ) {
1213  if ( idStr::Icmp( image->imgName, globalImages->images[ j ]->imgName ) == 0 ) {
1214  break;
1215  }
1216  }
1217  if ( j == globalImages->images.Num() ) {
1218  continue;
1219  }
1220  }
1221 
1222  // "listimages touched" will list only images bound since the last "listimages touched" call
1223  if ( touched ) {
1224  if ( image->bindCount == 0 ) {
1225  continue;
1226  }
1227  image->bindCount = 0;
1228  }
1229 
1230  if ( sorted ) {
1231  sortedArray[count].image = image;
1232  sortedArray[count].size = image->StorageSize();
1233  } else {
1234  common->Printf( "%4i:", i );
1235  image->Print();
1236  }
1237  totalSize += image->StorageSize();
1238  count++;
1239  }
1240 
1241  if ( sorted ) {
1242  qsort( sortedArray, count, sizeof( sortedImage_t ), R_QsortImageSizes );
1243  partialSize = 0;
1244  for ( i = 0 ; i < count ; i++ ) {
1245  common->Printf( "%4i:", i );
1246  sortedArray[i].image->Print();
1247  partialSize += sortedArray[i].image->StorageSize();
1248  if ( ( (i+1) % 10 ) == 0 ) {
1249  common->Printf( "-------- %5.1f of %5.1f megs --------\n",
1250  partialSize / (1024*1024.0), totalSize / (1024*1024.0) );
1251  }
1252  }
1253  }
1254 
1255  common->Printf( "%s", header );
1256  common->Printf( " %i images (%i total)\n", count, globalImages->images.Num() );
1257  common->Printf( " %5.1f total megabytes of images\n\n\n", totalSize / (1024*1024.0) );
1258 
1259  if ( byClassification ) {
1260 
1261  idList< int > classifications[IC_COUNT];
1262 
1263  for ( i = 0 ; i < count ; i++ ) {
1264  int cl = ClassifyImage( sortedArray[i].image->imgName );
1265  classifications[ cl ].Append( i );
1266  }
1267 
1268  for ( i = 0; i < IC_COUNT; i++ ) {
1269  partialSize = 0;
1270  idList< int > overSizedList;
1271  for ( j = 0; j < classifications[ i ].Num(); j++ ) {
1272  partialSize += sortedArray[ classifications[ i ][ j ] ].image->StorageSize();
1273  if ( overSized ) {
1274  if ( sortedArray[ classifications[ i ][ j ] ].image->uploadWidth > IC_Info[i].maxWidth && sortedArray[ classifications[ i ][ j ] ].image->uploadHeight > IC_Info[i].maxHeight ) {
1275  overSizedList.Append( classifications[ i ][ j ] );
1276  }
1277  }
1278  }
1279  common->Printf ( " Classification %s contains %i images using %5.1f megabytes\n", IC_Info[i].desc, classifications[i].Num(), partialSize / ( 1024*1024.0 ) );
1280  if ( overSized && overSizedList.Num() ) {
1281  common->Printf( " The following images may be oversized\n" );
1282  for ( j = 0; j < overSizedList.Num(); j++ ) {
1283  common->Printf( " " );
1284  sortedArray[ overSizedList[ j ] ].image->Print();
1285  common->Printf( "\n" );
1286  }
1287  }
1288  }
1289  }
1290 
1291 }
1292 
1293 /*
1294 ==================
1295 SetNormalPalette
1296 
1297 Create a 256 color palette to be used by compressed normal maps
1298 ==================
1299 */
1301  int i, j;
1302  idVec3 v;
1303  float t;
1304  //byte temptable[768];
1305  byte *temptable = compressedPalette;
1306  int compressedToOriginal[16];
1307 
1308  // make an ad-hoc separable compression mapping scheme
1309  for ( i = 0 ; i < 8 ; i++ ) {
1310  float f, y;
1311 
1312  f = ( i + 1 ) / 8.5;
1313  y = idMath::Sqrt( 1.0 - f * f );
1314  y = 1.0 - y;
1315 
1316  compressedToOriginal[7-i] = 127 - (int)( y * 127 + 0.5 );
1317  compressedToOriginal[8+i] = 128 + (int)( y * 127 + 0.5 );
1318  }
1319 
1320  for ( i = 0 ; i < 256 ; i++ ) {
1321  if ( i <= compressedToOriginal[0] ) {
1322  originalToCompressed[i] = 0;
1323  } else if ( i >= compressedToOriginal[15] ) {
1324  originalToCompressed[i] = 15;
1325  } else {
1326  for ( j = 0 ; j < 14 ; j++ ) {
1327  if ( i <= compressedToOriginal[j+1] ) {
1328  break;
1329  }
1330  }
1331  if ( i - compressedToOriginal[j] < compressedToOriginal[j+1] - i ) {
1333  } else {
1334  originalToCompressed[i] = j + 1;
1335  }
1336  }
1337  }
1338 
1339 #if 0
1340  for ( i = 0; i < 16; i++ ) {
1341  for ( j = 0 ; j < 16 ; j++ ) {
1342 
1343  v[0] = ( i - 7.5 ) / 8;
1344  v[1] = ( j - 7.5 ) / 8;
1345 
1346  t = 1.0 - ( v[0]*v[0] + v[1]*v[1] );
1347  if ( t < 0 ) {
1348  t = 0;
1349  }
1350  v[2] = idMath::Sqrt( t );
1351 
1352  temptable[(i*16+j)*3+0] = 128 + floor( 127 * v[0] + 0.5 );
1353  temptable[(i*16+j)*3+1] = 128 + floor( 127 * v[1] );
1354  temptable[(i*16+j)*3+2] = 128 + floor( 127 * v[2] );
1355  }
1356  }
1357 #else
1358  for ( i = 0; i < 16; i++ ) {
1359  for ( j = 0 ; j < 16 ; j++ ) {
1360 
1361  v[0] = ( compressedToOriginal[i] - 127.5 ) / 128;
1362  v[1] = ( compressedToOriginal[j] - 127.5 ) / 128;
1363 
1364  t = 1.0 - ( v[0]*v[0] + v[1]*v[1] );
1365  if ( t < 0 ) {
1366  t = 0;
1367  }
1368  v[2] = idMath::Sqrt( t );
1369 
1370  temptable[(i*16+j)*3+0] = (byte)(128 + floor( 127 * v[0] + 0.5 ));
1371  temptable[(i*16+j)*3+1] = (byte)(128 + floor( 127 * v[1] ));
1372  temptable[(i*16+j)*3+2] = (byte)(128 + floor( 127 * v[2] ));
1373  }
1374  }
1375 #endif
1376 
1377  // color 255 will be the "nullnormal" color for no reflection
1378  temptable[255*3+0] =
1379  temptable[255*3+1] =
1380  temptable[255*3+2] = 128;
1381 
1383  return;
1384  }
1385 
1386  qglColorTableEXT( GL_SHARED_TEXTURE_PALETTE_EXT,
1387  GL_RGB,
1388  256,
1389  GL_RGB,
1390  GL_UNSIGNED_BYTE,
1391  temptable );
1392 
1394 }
1395 
1396 /*
1397 ==============
1398 AllocImage
1399 
1400 Allocates an idImage, adds it to the list,
1401 copies the name, and adds it to the hash chain.
1402 ==============
1403 */
1404 idImage *idImageManager::AllocImage( const char *name ) {
1405  idImage *image;
1406  int hash;
1407 
1408  if (strlen(name) >= MAX_IMAGE_NAME ) {
1409  common->Error ("idImageManager::AllocImage: \"%s\" is too long\n", name);
1410  }
1411 
1412  hash = idStr( name ).FileNameHash();
1413 
1414  image = new idImage;
1415  images.Append( image );
1416 
1417  image->hashNext = imageHashTable[hash];
1418  imageHashTable[hash] = image;
1419 
1420  image->imgName = name;
1421 
1422  return image;
1423 }
1424 
1425 /*
1426 ==================
1427 ImageFromFunction
1428 
1429 Images that are procedurally generated are allways specified
1430 with a callback which must work at any time, allowing the OpenGL
1431 system to be completely regenerated if needed.
1432 ==================
1433 */
1434 idImage *idImageManager::ImageFromFunction( const char *_name, void (*generatorFunction)( idImage *image ) ) {
1435  idStr name;
1436  idImage *image;
1437  int hash;
1438 
1439  if ( !name ) {
1440  common->FatalError( "idImageManager::ImageFromFunction: NULL name" );
1441  }
1442 
1443  // strip any .tga file extensions from anywhere in the _name
1444  name = _name;
1445  name.Replace( ".tga", "" );
1446  name.BackSlashesToSlashes();
1447 
1448  // see if the image already exists
1449  hash = name.FileNameHash();
1450  for ( image = imageHashTable[hash] ; image; image = image->hashNext ) {
1451  if ( name.Icmp( image->imgName ) == 0 ) {
1452  if ( image->generatorFunction != generatorFunction ) {
1453  common->DPrintf( "WARNING: reused image %s with mixed generators\n", name.c_str() );
1454  }
1455  return image;
1456  }
1457  }
1458 
1459  // create the image and issue the callback
1460  image = AllocImage( name );
1461 
1462  image->generatorFunction = generatorFunction;
1463 
1464  if ( image_preload.GetBool() ) {
1465  // check for precompressed, load is from the front end
1466  image->referencedOutsideLevelLoad = true;
1467  image->ActuallyLoadImage( true, false );
1468  }
1469 
1470  return image;
1471 }
1472 
1473 /*
1474 ===============
1475 ImageFromFile
1476 
1477 Finds or loads the given image, always returning a valid image pointer.
1478 Loading of the image may be deferred for dynamic loading.
1479 ==============
1480 */
1481 idImage *idImageManager::ImageFromFile( const char *_name, textureFilter_t filter, bool allowDownSize,
1482  textureRepeat_t repeat, textureDepth_t depth, cubeFiles_t cubeMap ) {
1483  idStr name;
1484  idImage *image;
1485  int hash;
1486 
1487  if ( !_name || !_name[0] || idStr::Icmp( _name, "default" ) == 0 || idStr::Icmp( _name, "_default" ) == 0 ) {
1488  declManager->MediaPrint( "DEFAULTED\n" );
1489  return globalImages->defaultImage;
1490  }
1491 
1492  // strip any .tga file extensions from anywhere in the _name, including image program parameters
1493  name = _name;
1494  name.Replace( ".tga", "" );
1495  name.BackSlashesToSlashes();
1496 
1497  //
1498  // see if the image is already loaded, unless we
1499  // are in a reloadImages call
1500  //
1501  hash = name.FileNameHash();
1502  for ( image = imageHashTable[hash]; image; image = image->hashNext ) {
1503  if ( name.Icmp( image->imgName ) == 0 ) {
1504  // the built in's, like _white and _flat always match the other options
1505  if ( name[0] == '_' ) {
1506  return image;
1507  }
1508  if ( image->cubeFiles != cubeMap ) {
1509  common->Error( "Image '%s' has been referenced with conflicting cube map states", _name );
1510  }
1511 
1512  if ( image->filter != filter || image->repeat != repeat ) {
1513  // we might want to have the system reset these parameters on every bind and
1514  // share the image data
1515  continue;
1516  }
1517 
1518  if ( image->allowDownSize == allowDownSize && image->depth == depth ) {
1519  // note that it is used this level load
1520  image->levelLoadReferenced = true;
1521  if ( image->partialImage != NULL ) {
1522  image->partialImage->levelLoadReferenced = true;
1523  }
1524  return image;
1525  }
1526 
1527  // the same image is being requested, but with a different allowDownSize or depth
1528  // so pick the highest of the two and reload the old image with those parameters
1529  if ( !image->allowDownSize ) {
1530  allowDownSize = false;
1531  }
1532  if ( image->depth > depth ) {
1533  depth = image->depth;
1534  }
1535  if ( image->allowDownSize == allowDownSize && image->depth == depth ) {
1536  // the already created one is already the highest quality
1537  image->levelLoadReferenced = true;
1538  if ( image->partialImage != NULL ) {
1539  image->partialImage->levelLoadReferenced = true;
1540  }
1541  return image;
1542  }
1543 
1544  image->allowDownSize = allowDownSize;
1545  image->depth = depth;
1546  image->levelLoadReferenced = true;
1547  if ( image->partialImage != NULL ) {
1548  image->partialImage->levelLoadReferenced = true;
1549  }
1550  if ( image_preload.GetBool() && !insideLevelLoad ) {
1551  image->referencedOutsideLevelLoad = true;
1552  image->ActuallyLoadImage( true, false ); // check for precompressed, load is from front end
1553  declManager->MediaPrint( "%ix%i %s (reload for mixed referneces)\n", image->uploadWidth, image->uploadHeight, image->imgName.c_str() );
1554  }
1555  return image;
1556  }
1557  }
1558 
1559  //
1560  // create a new image
1561  //
1562  image = AllocImage( name );
1563 
1564  // HACK: to allow keep fonts from being mip'd, as new ones will be introduced with localization
1565  // this keeps us from having to make a material for each font tga
1566  if ( name.Find( "fontImage_") >= 0 ) {
1567  allowDownSize = false;
1568  }
1569 
1570  image->allowDownSize = allowDownSize;
1571  image->repeat = repeat;
1572  image->depth = depth;
1573  image->type = TT_2D;
1574  image->cubeFiles = cubeMap;
1575  image->filter = filter;
1576 
1577  image->levelLoadReferenced = true;
1578 
1579  // also create a shrunken version if we are going to dynamically cache the full size image
1580  if ( image->ShouldImageBePartialCached() ) {
1581  // if we only loaded part of the file, create a new idImage for the shrunken version
1582  image->partialImage = new idImage;
1583 
1584  image->partialImage->allowDownSize = allowDownSize;
1585  image->partialImage->repeat = repeat;
1586  image->partialImage->depth = depth;
1587  image->partialImage->type = TT_2D;
1588  image->partialImage->cubeFiles = cubeMap;
1589  image->partialImage->filter = filter;
1590 
1591  image->partialImage->levelLoadReferenced = true;
1592 
1593  // we don't bother hooking this into the hash table for lookup, but we do add it to the manager
1594  // list for listImages
1595  globalImages->images.Append( image->partialImage );
1596  image->partialImage->imgName = image->imgName;
1597  image->partialImage->isPartialImage = true;
1598 
1599  // let the background file loader know that we can load
1600  image->precompressedFile = true;
1601 
1602  if ( image_preload.GetBool() && !insideLevelLoad ) {
1603  image->partialImage->ActuallyLoadImage( true, false ); // check for precompressed, load is from front end
1604  declManager->MediaPrint( "%ix%i %s\n", image->partialImage->uploadWidth, image->partialImage->uploadHeight, image->imgName.c_str() );
1605  } else {
1606  declManager->MediaPrint( "%s\n", image->imgName.c_str() );
1607  }
1608  return image;
1609  }
1610 
1611  // load it if we aren't in a level preload
1612  if ( image_preload.GetBool() && !insideLevelLoad ) {
1613  image->referencedOutsideLevelLoad = true;
1614  image->ActuallyLoadImage( true, false ); // check for precompressed, load is from front end
1615  declManager->MediaPrint( "%ix%i %s\n", image->uploadWidth, image->uploadHeight, image->imgName.c_str() );
1616  } else {
1617  declManager->MediaPrint( "%s\n", image->imgName.c_str() );
1618  }
1619 
1620  return image;
1621 }
1622 
1623 /*
1624 ===============
1625 idImageManager::GetImage
1626 ===============
1627 */
1628 idImage *idImageManager::GetImage( const char *_name ) const {
1629  idStr name;
1630  idImage *image;
1631  int hash;
1632 
1633  if ( !_name || !_name[0] || idStr::Icmp( _name, "default" ) == 0 || idStr::Icmp( _name, "_default" ) == 0 ) {
1634  declManager->MediaPrint( "DEFAULTED\n" );
1635  return globalImages->defaultImage;
1636  }
1637 
1638  // strip any .tga file extensions from anywhere in the _name, including image program parameters
1639  name = _name;
1640  name.Replace( ".tga", "" );
1641  name.BackSlashesToSlashes();
1642 
1643  //
1644  // look in loaded images
1645  //
1646  hash = name.FileNameHash();
1647  for ( image = imageHashTable[hash]; image; image = image->hashNext ) {
1648  if ( name.Icmp( image->imgName ) == 0 ) {
1649  return image;
1650  }
1651  }
1652 
1653  return NULL;
1654 }
1655 
1656 /*
1657 ===============
1658 PurgeAllImages
1659 ===============
1660 */
1662  int i;
1663  idImage *image;
1664 
1665  for ( i = 0; i < images.Num() ; i++ ) {
1666  image = images[i];
1667  image->PurgeImage();
1668  }
1669 }
1670 
1671 /*
1672 ===============
1673 ReloadAllImages
1674 ===============
1675 */
1677  idCmdArgs args;
1678 
1679  // build the compressed normal map palette
1680  SetNormalPalette();
1681 
1682  args.TokenizeString( "reloadImages reload", false );
1683  R_ReloadImages_f( args );
1684 }
1685 
1686 /*
1687 ===============
1688 R_CombineCubeImages_f
1689 
1690 Used to combine animations of six separate tga files into
1691 a serials of 6x taller tga files, for preparation to roq compress
1692 ===============
1693 */
1694 void R_CombineCubeImages_f( const idCmdArgs &args ) {
1695  if ( args.Argc() != 2 ) {
1696  common->Printf( "usage: combineCubeImages <baseName>\n" );
1697  common->Printf( " combines basename[1-6][0001-9999].tga to basenameCM[0001-9999].tga\n" );
1698  common->Printf( " 1: forward 2:right 3:back 4:left 5:up 6:down\n" );
1699  return;
1700  }
1701 
1702  idStr baseName = args.Argv( 1 );
1703  common->SetRefreshOnPrint( true );
1704 
1705  for ( int frameNum = 1 ; frameNum < 10000 ; frameNum++ ) {
1706  char filename[MAX_IMAGE_NAME];
1707  byte *pics[6];
1708  int width, height;
1709  int side;
1710  int orderRemap[6] = { 1,3,4,2,5,6 };
1711  for ( side = 0 ; side < 6 ; side++ ) {
1712  sprintf( filename, "%s%i%04i.tga", baseName.c_str(), orderRemap[side], frameNum );
1713 
1714  common->Printf( "reading %s\n", filename );
1715  R_LoadImage( filename, &pics[side], &width, &height, NULL, true );
1716 
1717  if ( !pics[side] ) {
1718  common->Printf( "not found.\n" );
1719  break;
1720  }
1721 
1722  // convert from "camera" images to native cube map images
1723  switch( side ) {
1724  case 0: // forward
1725  R_RotatePic( pics[side], width);
1726  break;
1727  case 1: // back
1728  R_RotatePic( pics[side], width);
1729  R_HorizontalFlip( pics[side], width, height );
1730  R_VerticalFlip( pics[side], width, height );
1731  break;
1732  case 2: // left
1733  R_VerticalFlip( pics[side], width, height );
1734  break;
1735  case 3: // right
1736  R_HorizontalFlip( pics[side], width, height );
1737  break;
1738  case 4: // up
1739  R_RotatePic( pics[side], width);
1740  break;
1741  case 5: // down
1742  R_RotatePic( pics[side], width);
1743  break;
1744  }
1745  }
1746 
1747  if ( side != 6 ) {
1748  for ( int i = 0 ; i < side ; side++ ) {
1749  Mem_Free( pics[side] );
1750  }
1751  break;
1752  }
1753 
1754  byte *combined = (byte *)Mem_Alloc( width*height*6*4 );
1755  for ( side = 0 ; side < 6 ; side++ ) {
1756  memcpy( combined+width*height*4*side, pics[side], width*height*4 );
1757  Mem_Free( pics[side] );
1758  }
1759  sprintf( filename, "%sCM%04i.tga", baseName.c_str(), frameNum );
1760 
1761  common->Printf( "writing %s\n", filename );
1762  R_WriteTGA( filename, combined, width, height*6 );
1763 
1764  Mem_Free( combined );
1765  }
1766  common->SetRefreshOnPrint( false );
1767 }
1768 
1769 
1770 /*
1771 ==================
1772 idImage::StartBackgroundImageLoad
1773 ==================
1774 */
1777  return;
1778  }
1779  if ( globalImages->image_showBackgroundLoads.GetBool() ) {
1780  common->Printf( "idImage::StartBackgroundImageLoad: %s\n", imgName.c_str() );
1781  }
1782  backgroundLoadInProgress = true;
1783 
1784  if ( !precompressedFile ) {
1785  common->Warning( "idImageManager::StartBackgroundImageLoad: %s wasn't a precompressed file", imgName.c_str() );
1786  return;
1787  }
1788 
1789  bglNext = globalImages->backgroundImageLoads;
1790  globalImages->backgroundImageLoads = this;
1791 
1792  char filename[MAX_IMAGE_NAME];
1794 
1795  bgl.completed = false;
1796  bgl.f = fileSystem->OpenFileRead( filename );
1797  if ( !bgl.f ) {
1798  common->Warning( "idImageManager::StartBackgroundImageLoad: Couldn't load %s", imgName.c_str() );
1799  return;
1800  }
1801  bgl.file.position = 0;
1802  bgl.file.length = bgl.f->Length();
1803  if ( bgl.file.length < sizeof( ddsFileHeader_t ) ) {
1804  common->Warning( "idImageManager::StartBackgroundImageLoad: %s had a bad file length", imgName.c_str() );
1805  return;
1806  }
1807 
1809 
1811 
1812  imageManager.numActiveBackgroundImageLoads++;
1813 
1814  // purge some images if necessary
1815  int totalSize = 0;
1816  for ( idImage *check = globalImages->cacheLRU.cacheUsageNext ; check != &globalImages->cacheLRU ; check = check->cacheUsageNext ) {
1817  totalSize += check->StorageSize();
1818  }
1819  int needed = this->StorageSize();
1820 
1821  while ( ( totalSize + needed ) > globalImages->image_cacheMegs.GetFloat() * 1024 * 1024 ) {
1822  // purge the least recently used
1823  idImage *check = globalImages->cacheLRU.cacheUsagePrev;
1824  if ( check->texnum != TEXTURE_NOT_LOADED ) {
1825  totalSize -= check->StorageSize();
1826  if ( globalImages->image_showBackgroundLoads.GetBool() ) {
1827  common->Printf( "purging %s\n", check->imgName.c_str() );
1828  }
1829  check->PurgeImage();
1830  }
1831  // remove it from the cached list
1832  check->cacheUsageNext->cacheUsagePrev = check->cacheUsagePrev;
1833  check->cacheUsagePrev->cacheUsageNext = check->cacheUsageNext;
1834  check->cacheUsageNext = NULL;
1835  check->cacheUsagePrev = NULL;
1836  }
1837 }
1838 
1839 /*
1840 ==================
1841 R_CompleteBackgroundImageLoads
1842 
1843 Do we need to worry about vid_restarts here?
1844 ==================
1845 */
1847  idImage *remainingList = NULL;
1848  idImage *next;
1849 
1850  for ( idImage *image = backgroundImageLoads ; image ; image = next ) {
1851  next = image->bglNext;
1852  if ( image->bgl.completed ) {
1854  fileSystem->CloseFile( image->bgl.f );
1855  // upload the image
1856  image->UploadPrecompressedImage( (byte *)image->bgl.file.buffer, image->bgl.file.length );
1857  R_StaticFree( image->bgl.file.buffer );
1859  common->Printf( "R_CompleteBackgroundImageLoad: %s\n", image->imgName.c_str() );
1860  }
1861  } else {
1862  image->bglNext = remainingList;
1863  remainingList = image;
1864  }
1865  }
1867  static int prev;
1868  if ( numActiveBackgroundImageLoads != prev ) {
1870  common->Printf( "background Loads: %i\n", numActiveBackgroundImageLoads );
1871  }
1872  }
1873 
1874  backgroundImageLoads = remainingList;
1875 }
1876 
1877 /*
1878 ===============
1879 CheckCvars
1880 ===============
1881 */
1883  // textureFilter stuff
1889  }
1890 }
1891 
1892 /*
1893 ===============
1894 SumOfUsedImages
1895 ===============
1896 */
1898  int total;
1899  int i;
1900  idImage *image;
1901 
1902  total = 0;
1903  for ( i = 0; i < images.Num(); i++ ) {
1904  image = images[i];
1905  if ( image->frameUsed == backEnd.frameCount ) {
1906  total += image->StorageSize();
1907  }
1908  }
1909 
1910  return total;
1911 }
1912 
1913 /*
1914 ===============
1915 BindNull
1916 ===============
1917 */
1919  tmu_t *tmu;
1920 
1922 
1923  RB_LogComment( "BindNull()\n" );
1924  if ( tmu->textureType == TT_CUBIC ) {
1926  } else if ( tmu->textureType == TT_3D ) {
1928  } else if ( tmu->textureType == TT_2D ) {
1929  qglDisable( GL_TEXTURE_2D );
1930  }
1931  tmu->textureType = TT_DISABLED;
1932 }
1933 
1934 /*
1935 ===============
1936 Init
1937 ===============
1938 */
1940 
1941  memset(imageHashTable, 0, sizeof(imageHashTable));
1942 
1943  images.Resize( 1024, 1024 );
1944 
1945  // clear the cached LRU
1948 
1949  // set default texture filter modes
1951 
1952  // create built in images
1953  defaultImage = ImageFromFunction( "_default", R_DefaultImage );
1954  whiteImage = ImageFromFunction( "_white", R_WhiteImage );
1955  blackImage = ImageFromFunction( "_black", R_BlackImage );
1956  borderClampImage = ImageFromFunction( "_borderClamp", R_BorderClampImage );
1957  flatNormalMap = ImageFromFunction( "_flat", R_FlatNormalImage );
1958  ambientNormalMap = ImageFromFunction( "_ambient", R_AmbientNormalImage );
1959  specularTableImage = ImageFromFunction( "_specularTable", R_SpecularTableImage );
1960  specular2DTableImage = ImageFromFunction( "_specular2DTable", R_Specular2DTableImage );
1961  rampImage = ImageFromFunction( "_ramp", R_RampImage );
1962  alphaRampImage = ImageFromFunction( "_alphaRamp", R_RampImage );
1963  alphaNotchImage = ImageFromFunction( "_alphaNotch", R_AlphaNotchImage );
1964  fogImage = ImageFromFunction( "_fog", R_FogImage );
1966  normalCubeMapImage = ImageFromFunction( "_normalCubeMap", makeNormalizeVectorCubeMap );
1967  noFalloffImage = ImageFromFunction( "_noFalloff", R_CreateNoFalloffImage );
1968  ImageFromFunction( "_quadratic", R_QuadraticImage );
1969 
1970  // cinematicImage is used for cinematic drawing
1971  // scratchImage is used for screen wipes/doublevision etc..
1972  cinematicImage = ImageFromFunction("_cinematic", R_RGBA8Image );
1973  scratchImage = ImageFromFunction("_scratch", R_RGBA8Image );
1974  scratchImage2 = ImageFromFunction("_scratch2", R_RGBA8Image );
1975  accumImage = ImageFromFunction("_accum", R_RGBA8Image );
1976  scratchCubeMapImage = ImageFromFunction("_scratchCubeMap", makeNormalizeVectorCubeMap );
1977  currentRenderImage = ImageFromFunction("_currentRender", R_RGBA8Image );
1978 
1979  cmdSystem->AddCommand( "reloadImages", R_ReloadImages_f, CMD_FL_RENDERER, "reloads images" );
1980  cmdSystem->AddCommand( "listImages", R_ListImages_f, CMD_FL_RENDERER, "lists images" );
1981  cmdSystem->AddCommand( "combineCubeImages", R_CombineCubeImages_f, CMD_FL_RENDERER, "combines six images for roq compression" );
1982 
1983  // should forceLoadImages be here?
1984 }
1985 
1986 /*
1987 ===============
1988 Shutdown
1989 ===============
1990 */
1992  images.DeleteContents( true );
1993 }
1994 
1995 /*
1996 ====================
1997 BeginLevelLoad
1998 
1999 Mark all file based images as currently unused,
2000 but don't free anything. Calls to ImageFromFile() will
2001 either mark the image as used, or create a new image without
2002 loading the actual data.
2003 ====================
2004 */
2006  insideLevelLoad = true;
2007 
2008  for ( int i = 0 ; i < images.Num() ; i++ ) {
2009  idImage *image = images[ i ];
2010 
2011  // generator function images are always kept around
2012  if ( image->generatorFunction ) {
2013  continue;
2014  }
2015 
2016  if ( com_purgeAll.GetBool() ) {
2017  image->PurgeImage();
2018  }
2019 
2020  image->levelLoadReferenced = false;
2021  }
2022 }
2023 
2024 /*
2025 ====================
2026 EndLevelLoad
2027 
2028 Free all images marked as unused, and load all images that are necessary.
2029 This architecture prevents us from having the union of two level's
2030 worth of data present at one time.
2031 
2032 preload everything, never free
2033 preload everything, free unused after level load
2034 blocking load on demand
2035 preload low mip levels, background load remainder on demand
2036 ====================
2037 */
2039  int start = Sys_Milliseconds();
2040 
2041  insideLevelLoad = false;
2042  if ( idAsyncNetwork::serverDedicated.GetInteger() ) {
2043  return;
2044  }
2045 
2046  common->Printf( "----- idImageManager::EndLevelLoad -----\n" );
2047 
2048  int purgeCount = 0;
2049  int keepCount = 0;
2050  int loadCount = 0;
2051 
2052  // purge the ones we don't need
2053  for ( int i = 0 ; i < images.Num() ; i++ ) {
2054  idImage *image = images[ i ];
2055  if ( image->generatorFunction ) {
2056  continue;
2057  }
2058 
2059  if ( !image->levelLoadReferenced && !image->referencedOutsideLevelLoad ) {
2060 // common->Printf( "Purging %s\n", image->imgName.c_str() );
2061  purgeCount++;
2062  image->PurgeImage();
2063  } else if ( image->texnum != idImage::TEXTURE_NOT_LOADED ) {
2064 // common->Printf( "Keeping %s\n", image->imgName.c_str() );
2065  keepCount++;
2066  }
2067  }
2068 
2069  // load the ones we do need, if we are preloading
2070  for ( int i = 0 ; i < images.Num() ; i++ ) {
2071  idImage *image = images[ i ];
2072  if ( image->generatorFunction ) {
2073  continue;
2074  }
2075 
2076  if ( image->levelLoadReferenced && image->texnum == idImage::TEXTURE_NOT_LOADED && !image->partialImage ) {
2077 // common->Printf( "Loading %s\n", image->imgName.c_str() );
2078  loadCount++;
2079  image->ActuallyLoadImage( true, false );
2080 
2081  if ( ( loadCount & 15 ) == 0 ) {
2083  }
2084  }
2085  }
2086 
2087  int end = Sys_Milliseconds();
2088  common->Printf( "%5i purged from previous\n", purgeCount );
2089  common->Printf( "%5i kept from previous\n", keepCount );
2090  common->Printf( "%5i new loaded\n", loadCount );
2091  common->Printf( "all images loaded in %5.1f seconds\n", (end-start) * 0.001 );
2092  common->Printf( "----------------------------------------\n" );
2093 }
2094 
2095 /*
2096 ===============
2097 idImageManager::StartBuild
2098 ===============
2099 */
2101  ddsList.Clear();
2102  ddsHash.Free();
2103 }
2104 
2105 /*
2106 ===============
2107 idImageManager::FinishBuild
2108 ===============
2109 */
2110 void idImageManager::FinishBuild( bool removeDups ) {
2111  idFile *batchFile;
2112  if ( removeDups ) {
2113  ddsList.Clear();
2114  char *buffer = NULL;
2115  fileSystem->ReadFile( "makedds.bat", (void**)&buffer );
2116  if ( buffer ) {
2117  idStr str = buffer;
2118  while ( str.Length() ) {
2119  int n = str.Find( '\n' );
2120  if ( n > 0 ) {
2121  idStr line = str.Left( n + 1 );
2122  idStr right;
2123  str.Right( str.Length() - n - 1, right );
2124  str = right;
2125  ddsList.AddUnique( line );
2126  } else {
2127  break;
2128  }
2129  }
2130  }
2131  }
2132  batchFile = fileSystem->OpenFileWrite( ( removeDups ) ? "makedds2.bat" : "makedds.bat" );
2133  if ( batchFile ) {
2134  int i;
2135  int ddsNum = ddsList.Num();
2136 
2137  for ( i = 0; i < ddsNum; i++ ) {
2138  batchFile->WriteFloatString( "%s", ddsList[ i ].c_str() );
2139  batchFile->Printf( "@echo Finished compressing %d of %d. %.1f percent done.\n", i+1, ddsNum, ((float)(i+1)/(float)ddsNum)*100.f );
2140  }
2141  fileSystem->CloseFile( batchFile );
2142  }
2143  ddsList.Clear();
2144  ddsHash.Free();
2145 }
2146 
2147 /*
2148 ===============
2149 idImageManager::AddDDSCommand
2150 ===============
2151 */
2152 void idImageManager::AddDDSCommand( const char *cmd ) {
2153  int i, key;
2154 
2155  if ( !( cmd && *cmd ) ) {
2156  return;
2157  }
2158 
2159  key = ddsHash.GenerateKey( cmd, false );
2160  for ( i = ddsHash.First( key ); i != -1; i = ddsHash.Next( i ) ) {
2161  if ( ddsList[i].Icmp( cmd ) == 0 ) {
2162  break;
2163  }
2164  }
2165 
2166  if ( i == -1 ) {
2167  ddsList.Append( cmd );
2168  }
2169 }
2170 
2171 /*
2172 ===============
2173 idImageManager::PrintMemInfo
2174 ===============
2175 */
2177  int i, j, total = 0;
2178  int *sortIndex;
2179  idFile *f;
2180 
2181  f = fileSystem->OpenFileWrite( mi->filebase + "_images.txt" );
2182  if ( !f ) {
2183  return;
2184  }
2185 
2186  // sort first
2187  sortIndex = new int[images.Num()];
2188 
2189  for ( i = 0; i < images.Num(); i++ ) {
2190  sortIndex[i] = i;
2191  }
2192 
2193  for ( i = 0; i < images.Num() - 1; i++ ) {
2194  for ( j = i + 1; j < images.Num(); j++ ) {
2195  if ( images[sortIndex[i]]->StorageSize() < images[sortIndex[j]]->StorageSize() ) {
2196  int temp = sortIndex[i];
2197  sortIndex[i] = sortIndex[j];
2198  sortIndex[j] = temp;
2199  }
2200  }
2201  }
2202 
2203  // print next
2204  for ( i = 0; i < images.Num(); i++ ) {
2205  idImage *im = images[sortIndex[i]];
2206  int size;
2207 
2208  size = im->StorageSize();
2209  total += size;
2210 
2211  f->Printf( "%s %3i %s\n", idStr::FormatNumber( size ).c_str(), im->refCount, im->imgName.c_str() );
2212  }
2213 
2214  delete sortIndex;
2215  mi->imageAssetsTotal = total;
2216 
2217  f->Printf( "\nTotal image bytes allocated: %s\n", idStr::FormatNumber( total ).c_str() );
2218  fileSystem->CloseFile( f );
2219 }
idImage * specular2DTableImage
Definition: Image.h:411
bool ShouldImageBePartialCached()
byte color[4]
Definition: MegaTexture.cpp:54
virtual idFile * OpenFileRead(const char *relativePath, bool allowCopyFiles=true, const char *gamedir=NULL)=0
void R_FogImage(idImage *image)
Definition: Image_init.cpp:715
Definition: Image.h:146
Definition: Image.h:133
void MakeDefault()
Definition: Image_init.cpp:252
static idCVar image_anisotropy
Definition: Image.h:367
void BeginLevelLoad()
int Next(const int index) const
Definition: HashIndex.h:247
idImage * fogEnterImage
Definition: Image.h:403
#define qglDisable
Definition: qgl_linked.h:92
static idCVar image_preload
Definition: Image.h:377
void CreatealphaSquareImage(void)
Definition: Image_init.cpp:566
void GenerateImage(const byte *pic, int width, int height, textureFilter_t filter, bool allowDownSize, textureRepeat_t repeat, textureDepth_t depth)
Definition: Image_load.cpp:509
#define GL_TEXTURE_LOD_BIAS_EXT
Definition: glext.h:1745
#define NORMAL_MAP_SIZE
Definition: Image_init.cpp:589
void R_FogEnterImage(idImage *image)
Definition: Image_init.cpp:836
static idCVar image_useCompression
Definition: Image.h:365
idImage * cacheUsageNext
Definition: Image.h:252
idImage * rampImage
Definition: Image.h:395
float GetFloat(void) const
Definition: CVarSystem.h:144
int numActiveBackgroundImageLoads
Definition: Image.h:441
const GLdouble * v
Definition: glext.h:2936
int internalFormat
Definition: Image.h:250
GLenum textureMinFilter
Definition: Image.h:430
const char * desc
Definition: Image_init.cpp:92
const int FALLOFF_TEXTURE_SIZE
Definition: tr_local.h:42
bool anisotropicAvailable
Definition: RenderSystem.h:64
virtual int ReadFile(const char *relativePath, void **buffer, ID_TIME_T *timestamp=NULL)=0
idList< int > intList
Definition: Image_init.cpp:98
bool textureLODBiasAvailable
Definition: RenderSystem.h:65
int Length(void) const
Definition: Str.h:702
idCVar com_purgeAll("com_purgeAll","0", CVAR_BOOL|CVAR_ARCHIVE|CVAR_SYSTEM,"purge everything between level loads")
GLenum GLint GLint y
Definition: glext.h:2849
textureDepth_t depth
Definition: Image.h:234
GLenum GLsizei n
Definition: glext.h:3705
#define MAX_IMAGE_NAME
Definition: Image.h:144
int Sys_Milliseconds(void)
Definition: Image.h:139
case const int
Definition: Callbacks.cpp:52
static idCVar image_downSizeBump
Definition: Image.h:386
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
void R_LoadImage(const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp, bool makePowerOf2)
idCVar com_developer("developer","0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT,"developer mode")
textureRepeat_t
Definition: Material.h:52
idImage * GetImage(const char *name) const
void Print() const
idImage * image
void R_ListImages_f(const idCmdArgs &args)
void ReloadAllImages()
Definition: Vector.h:316
cubeFiles_t cubeFiles
Definition: Image.h:235
case const float
Definition: Callbacks.cpp:62
GLenum GLsizei GLenum GLenum const GLvoid * image
Definition: glext.h:2855
idImage * bglNext
Definition: Image.h:226
GLint GLint GLsizei GLsizei GLsizei depth
Definition: glext.h:2878
GLenum GLsizei const GLvoid * string
Definition: glext.h:3472
idImage * currentRenderImage
Definition: Image.h:408
static float Sqrt(float x)
Definition: Math.h:302
const char * Left(int len, idStr &result) const
Definition: Str.h:892
float textureLODBias
Definition: Image.h:433
bool insideLevelLoad
Definition: Image.h:424
void FinishBuild(bool removeDups=false)
idCmdSystem * cmdSystem
Definition: CmdSystem.cpp:116
GLclampf GLclampf GLclampf alpha
Definition: glext.h:2843
void PrintMemInfo(MemInfo_t *mi)
void CompleteBackgroundImageLoads()
bool levelLoadReferenced
Definition: Image.h:238
GLdouble s
Definition: glext.h:2935
GLdouble right
Definition: qgl.h:273
virtual void BackgroundDownload(backgroundDownload_t *bgl)=0
void R_LoadImageProgram(const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp, textureDepth_t *depth=NULL)
GLenum GLint x
Definition: glext.h:2849
int i
Definition: process.py:33
int currenttmu
Definition: tr_local.h:605
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT
Definition: glext.h:1872
void PurgeImage()
bool isPartialImage
Definition: Image.h:223
bool sharedTexturePaletteAvailable
Definition: RenderSystem.h:72
void Free(void)
Definition: HashIndex.cpp:75
#define qglEnable
Definition: qgl_linked.h:101
idImage * noFalloffImage
Definition: Image.h:401
int Icmp(const char *text) const
Definition: Str.h:667
idStr & BackSlashesToSlashes(void)
Definition: Str.cpp:727
#define GL_TEXTURE_MAX_ANISOTROPY_EXT
Definition: glext.h:1749
volatile bool completed
Definition: FileSystem.h:118
idImage * flatNormalMap
Definition: Image.h:393
int First(const int key) const
Definition: HashIndex.h:238
bool precompressedFile
Definition: Image.h:239
cubeFiles_t
Definition: Image.h:138
float textureAnisotropy
Definition: Image.h:432
backEndState_t backEnd
Definition: tr_backend.cpp:35
fileDownload_t file
Definition: FileSystem.h:116
int imageAssetsTotal
Definition: Common.h:107
bool defaulted
Definition: Image.h:240
bool backgroundLoadInProgress
Definition: Image.h:224
idImage * alphaNotchImage
Definition: Image.h:397
Definition: File.h:50
idImage * ambientNormalMap
Definition: Image.h:394
void GenerateCubeImage(const byte *pic[6], int size, textureFilter_t filter, bool allowDownSize, textureDepth_t depth)
Definition: Image_load.cpp:866
const GLfloat * tc
Definition: glext.h:4697
void ChangeTextureFilter()
Definition: Image_init.cpp:928
GLuint GLuint GLsizei count
Definition: glext.h:2845
textureFilter_t filter
Definition: Image.h:232
static idCVar image_forceDownSize
Definition: Image.h:383
void R_ReloadImages_f(const idCmdArgs &args)
float maxTextureAnisotropy
Definition: RenderSystem.h:58
ID_TIME_T timestamp
Definition: Image.h:242
idImage * backgroundImageLoads
Definition: Image.h:437
idImage * normalCubeMapImage
Definition: Image.h:400
idImage * AllocImage(const char *name)
static idStr FormatNumber(int number)
Definition: Str.cpp:1682
GLuint texnum
Definition: Image.h:216
textureType_t type
Definition: Image.h:217
idImageManager imageManager
Definition: Image_init.cpp:73
bool allowDownSize
Definition: Image.h:231
const imageClassificate_t IC_Info[]
Definition: Image_init.cpp:100
GLuint GLuint end
Definition: glext.h:2845
idImage * defaultImage
Definition: Image.h:392
#define DEFAULT_SIZE
Definition: Image_init.cpp:251
static float Fabs(float f)
Definition: Math.h:779
bool referencedOutsideLevelLoad
Definition: Image.h:237
idCommon * common
Definition: Common.cpp:206
idImage * accumImage
Definition: Image.h:407
void ActuallyLoadImage(bool checkForPrecompressed, bool fromBackEnd)
#define GL_COLOR_INDEX8_EXT
Definition: glext.h:1347
#define NULL
Definition: Lib.h:88
idImage cacheLRU
Definition: Image.h:438
static idCVar image_downSizeBumpLimit
Definition: Image.h:387
static idCVar image_usePrecompressedTextures
Definition: Image.h:370
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:2853
idImageManager * globalImages
Definition: Image_init.cpp:74
GLuint buffer
Definition: glext.h:3108
int bindCount
Definition: Image.h:219
int GetInteger(void) const
Definition: CVarSystem.h:143
glstate_t glState
Definition: tr_local.h:663
int frameUsed
Definition: Image.h:218
void R_HorizontalFlip(byte *data, int width, int height)
idImage * whiteImage
Definition: Image.h:398
virtual void virtual void FatalError(const char *fmt,...) id_attribute((format(printf
void R_CombineCubeImages_f(const idCmdArgs &args)
virtual idFile * OpenFileWrite(const char *relativePath, const char *basePath="fs_savepath")=0
idHashIndex ddsHash
Definition: Image.h:422
void StartBackgroundImageLoad()
static idCVar image_useNormalCompression
Definition: Image.h:375
idImage * scratchImage2
Definition: Image.h:406
void R_WriteTGA(const char *filename, const byte *data, int width, int height, bool flipVertical=false)
Definition: Image_files.cpp:85
#define qglTexParameterf
Definition: qgl_linked.h:331
idImage * borderClampImage
Definition: Image.h:412
static idCVar image_writeTGA
Definition: Image.h:374
int Argc(void) const
Definition: CmdArgs.h:48
idImage * imageHashTable[FILE_HASH_SIZE]
Definition: Image.h:435
const char * imageFilter[]
Definition: Image_init.cpp:34
static idCVar serverDedicated
Definition: AsyncNetwork.h:172
void DeleteContents(bool clear)
Definition: List.h:207
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
idImage * blackImage
Definition: Image.h:399
const char * Right(int len, idStr &result) const
Definition: Str.h:896
idImage * ImageFromFunction(const char *name, void(*generatorFunction)(idImage *image))
idImage * scratchCubeMapImage
Definition: Image.h:409
int Find(const char c, int start=0, int end=-1) const
Definition: Str.h:874
virtual int WriteFloatString(const char *fmt,...) id_attribute((format(printf
Definition: File.cpp:294
static float InvSqrt(float x)
Definition: Math.h:268
GLenum GLsizei width
Definition: glext.h:2846
static idCVar image_downSizeSpecular
Definition: Image.h:384
static idCVar image_writeNormalTGA
Definition: Image.h:372
GLubyte GLubyte GLubyte a
Definition: glext.h:4662
virtual void Printf(const char *fmt,...) id_attribute((format(printf
idStr filebase
Definition: Common.h:94
static idCVar image_downSize
Definition: Image.h:364
idStrList ddsList
Definition: Image.h:421
int FileNameHash(void) const
Definition: Str.cpp:700
byte originalToCompressed[256]
Definition: Image.h:426
GLenum GLsizei GLsizei height
Definition: glext.h:2856
static idCVar image_downSizeLimit
Definition: Image.h:389
static idCVar image_lodbias
Definition: Image.h:368
virtual void MediaPrint(const char *fmt,...) id_attribute((format(printf
static idCVar image_roundDown
Definition: Image.h:362
const int FOG_ENTER_SIZE
Definition: tr_local.h:46
idDeclManager * declManager
int uploadHeight
Definition: Image.h:249
int GenerateKey(const char *string, bool caseSensitive=true) const
Definition: HashIndex.h:379
void R_RotatePic(byte *data, int width)
void ImageProgramStringToCompressedFileName(const char *imageProg, char *fileName) const
Definition: Image_load.cpp:982
GLubyte GLubyte b
Definition: glext.h:4662
idImage * ImageFromFile(const char *name, textureFilter_t filter, bool allowDownSize, textureRepeat_t repeat, textureDepth_t depth, cubeFiles_t cubeMap=CF_2D)
void UploadPrecompressedImage(byte *data, int len)
static idCVar image_cacheMinK
Definition: Image.h:378
void TokenizeString(const char *text, bool keepAsStrings)
Definition: CmdArgs.cpp:106
const char * GetString(void) const
Definition: CVarSystem.h:141
void(* generatorFunction)(idImage *image)
Definition: Image.h:230
int uploadWidth
Definition: Image.h:249
IMAGE_CLASSIFICATION
Definition: Image_init.cpp:77
void RB_LogComment(const char *comment,...)
Definition: tr_backend.cpp:112
int Append(const type &obj)
Definition: List.h:646
const char * rootPath
Definition: Image_init.cpp:91
textureType_t textureType
Definition: tr_local.h:599
virtual void PacifierUpdate()=0
idList< idImage * > images
Definition: Image.h:420
static idCVar image_writeNormalTGAPalletized
Definition: Image.h:373
int AddUnique(const type &obj)
Definition: List.h:742
bool GetBool(void) const
Definition: CVarSystem.h:142
glconfig_t glConfig
void PurgeAllImages()
GLenum filter
Definition: glext.h:3704
void ClearModified(void)
Definition: CVarSystem.h:139
tuple f
Definition: idal.py:89
void R_VerticalFlip(byte *data, int width, int height)
void SetNormalPalette()
static idCVar image_filter
Definition: Image.h:366
static idCVar image_cacheMegs
Definition: Image.h:380
int Num(void) const
Definition: List.h:265
unsigned char byte
Definition: Lib.h:75
void * R_StaticAlloc(int bytes)
Definition: tr_main.cpp:301
int classification
Definition: Image.h:246
GLenum textureMaxFilter
Definition: Image.h:431
idImage * alphaRampImage
Definition: Image.h:396
static idCVar image_useAllFormats
Definition: Image.h:369
const GLcharARB * name
Definition: glext.h:3629
GLsizeiptr size
Definition: glext.h:3112
#define GL_TEXTURE_3D
Definition: glext.h:71
static idCVar image_ignoreHighQuality
Definition: Image.h:388
bool IsModified(void) const
Definition: CVarSystem.h:137
static idCVar image_showBackgroundLoads
Definition: Image.h:382
Definition: Str.h:116
void Reload(bool checkPrecompressed, bool force)
idImage * cacheUsagePrev
Definition: Image.h:252
const char * c_str(void) const
Definition: Str.h:487
#define GL_SHARED_TEXTURE_PALETTE_EXT
Definition: glext.h:1551
idStr imgName
Definition: Image.h:229
static const int TEXTURE_NOT_LOADED
Definition: Image.h:215
idRenderSystemLocal tr
const int FOG_SIZE
Definition: Image_init.cpp:713
#define GL_TEXTURE_CUBE_MAP_EXT
Definition: glext.h:1723
void R_QuadraticImage(idImage *image)
Definition: Image_init.cpp:875
idImage * scratchImage
Definition: Image.h:405
void AddDDSCommand(const char *cmd)
const char * Argv(int arg) const
Definition: CmdArgs.h:50
static idCVar image_useCache
Definition: Image.h:381
static const int MAX_BACKGROUND_IMAGE_LOADS
Definition: Image.h:442
void * Mem_Alloc(const int size)
Definition: Heap.cpp:1067
GLint j
Definition: qgl.h:264
bool isInitialized
Definition: RenderSystem.h:98
virtual void SetRefreshOnPrint(bool set)=0
idSession * session
Definition: Session.cpp:48
#define qglTexParameterfv
Definition: qgl_linked.h:332
int StorageSize() const
idImage * hashNext
Definition: Image.h:254
idImage * cinematicImage
Definition: Image.h:404
idImage * fogImage
Definition: Image.h:402
GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid * pixels
Definition: glext.h:2878
virtual void CloseFile(idFile *f)=0
void R_StaticFree(void *data)
Definition: tr_main.cpp:335
virtual void DPrintf(const char *fmt,...) id_attribute((format(printf
idImage * specularTableImage
Definition: Image.h:410
virtual void Error(const char *fmt,...) id_attribute((format(printf
void Replace(const char *old, const char *nw)
Definition: Str.cpp:563
int refCount
Definition: Image.h:256
void Bind()
idVec4 ambientLightVector
Definition: tr_local.h:768
textureRepeat_t repeat
Definition: Image.h:233
backgroundDownload_t bgl
Definition: Image.h:225
bool R_LoadCubeImages(const char *cname, cubeFiles_t extensions, byte *pic[6], int *size, ID_TIME_T *timestamp)
virtual void virtual void Warning(const char *fmt,...) id_attribute((format(printf
textureFilter_t
Definition: Material.h:46
Definition: Image.h:132
void Resize(int newsize)
Definition: List.h:360
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
static idCVar image_useOffLineCompression
Definition: Image.h:376
static idCVar image_colorMipLevels
Definition: Image.h:363
static idCVar image_writePrecompressedTextures
Definition: Image.h:371
virtual int Printf(const char *fmt,...) id_attribute((format(printf
Definition: File.cpp:260
virtual int Length(void)
Definition: File.cpp:199
idImage * partialImage
Definition: Image.h:222
GLuint start
Definition: glext.h:2845
virtual void AddCommand(const char *cmdName, cmdFunction_t function, int flags, const char *description, argCompletion_t argCompletion=NULL)=0
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
Definition: glext.h:1875
void CreatePitFogImage(void)
Definition: Image_init.cpp:530
static idCVar image_downSizeSpecularLimit
Definition: Image.h:385
textureDepth_t
Definition: Image.h:122
GLdouble GLdouble t
Definition: glext.h:2943
void Clear(void)
Definition: List.h:184
tmu_t tmu[MAX_MULTITEXTURE_UNITS]
Definition: tr_local.h:604
byte compressedPalette[768]
Definition: Image.h:427