doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MegaTexture.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 #include "../idlib/precompiled.h"
29 #pragma hdrstop
30 
31 #include "tr_local.h"
32 
33 idCVar idMegaTexture::r_megaTextureLevel( "r_megaTextureLevel", "0", CVAR_RENDERER | CVAR_INTEGER, "draw only a specific level" );
34 idCVar idMegaTexture::r_showMegaTexture( "r_showMegaTexture", "0", CVAR_RENDERER | CVAR_BOOL, "display all the level images" );
35 idCVar idMegaTexture::r_showMegaTextureLabels( "r_showMegaTextureLabels", "0", CVAR_RENDERER | CVAR_BOOL, "draw colored blocks in each tile" );
36 idCVar idMegaTexture::r_skipMegaTexture( "r_skipMegaTexture", "0", CVAR_RENDERER | CVAR_INTEGER, "only use the lowest level image" );
37 idCVar idMegaTexture::r_terrainScale( "r_terrainScale", "3", CVAR_RENDERER | CVAR_INTEGER, "vertically scale USGS data" );
38 
39 /*
40 
41 allow sparse population of the upper detail tiles
42 
43 */
44 
46  int pot;
47  for (pot = 1 ; (pot*2) <= num ; pot<<=1) {
48  }
49  return pot;
50 }
51 
52 static union {
53  int intVal;
54  byte color[4];
55 } fillColor;
56 
57 static byte colors[8][4] = {
58  { 0, 0, 0, 255 },
59  { 255, 0, 0, 255 },
60  { 0, 255, 0, 255 },
61  { 255, 255, 0, 255 },
62  { 0, 0, 255, 255 },
63  { 255, 0, 255, 255 },
64  { 0, 255, 255, 255 },
65  { 255, 255, 255, 255 }
66 };
67 
68 static void R_EmptyLevelImage( idImage *image ) {
69  int c = MAX_LEVEL_WIDTH * MAX_LEVEL_WIDTH;
70  byte *data = (byte *)_alloca( c*4 );
71 
72  for ( int i = 0 ; i < c ; i++ ) {
73  ((int *)data)[i] = fillColor.intVal;
74  }
75 
76  // FIXME: this won't live past vid mode changes
77  image->GenerateImage( data, MAX_LEVEL_WIDTH, MAX_LEVEL_WIDTH,
79 }
80 
81 
82 /*
83 ====================
84 InitFromMegaFile
85 ====================
86 */
87 bool idMegaTexture::InitFromMegaFile( const char *fileBase ) {
88  idStr name = "megaTextures/";
89  name += fileBase;
90  name.StripFileExtension();
91  name += ".mega";
92 
93  int width, height;
94 
96  if ( !fileHandle ) {
97  common->Printf( "idMegaTexture: failed to open %s\n", name.c_str() );
98  return false;
99  }
100 
101  fileHandle->Read( &header, sizeof( header ) );
102  if ( header.tileSize < 64 || header.tilesWide < 1 || header.tilesHigh < 1 ) {
103  common->Printf( "idMegaTexture: bad header on %s\n", name.c_str() );
104  return false;
105  }
106 
108 
109  numLevels = 0;
110  width = header.tilesWide;
111  height = header.tilesHigh;
112 
113  int tileOffset = 1; // just past the header
114 
115  memset( levels, 0, sizeof( levels ) );
116  while( 1 ) {
118 
119  level->mega = this;
120  level->tileOffset = tileOffset;
121  level->tilesWide = width;
122  level->tilesHigh = height;
123  level->parms[0] = -1; // initially mask everything
124  level->parms[1] = 0;
125  level->parms[2] = 0;
126  level->parms[3] = (float)width / TILE_PER_LEVEL;
127  level->Invalidate();
128 
129  tileOffset += level->tilesWide * level->tilesHigh;
130 
131  char str[1024];
132  sprintf( str, "MEGA_%s_%i", fileBase, numLevels );
133 
134  // give each level a default fill color
135  for (int i = 0 ; i < 4 ; i++ ) {
136  fillColor.color[i] = colors[numLevels+1][i];
137  }
138 
139  levels[numLevels].image = globalImages->ImageFromFunction( str, R_EmptyLevelImage );
140  numLevels++;
141 
142  if ( width <= TILE_PER_LEVEL && height <= TILE_PER_LEVEL ) {
143  break;
144  }
145  width = ( width + 1 ) >> 1;
146  height = ( height + 1 ) >> 1;
147  }
148 
149  // force first bind to load everything
150  currentViewOrigin[0] = -99999999.0f;
151  currentViewOrigin[1] = -99999999.0f;
152  currentViewOrigin[2] = -99999999.0f;
153 
154  return true;
155 }
156 
157 /*
158 ====================
159 SetMappingForSurface
160 
161 analyzes xyz and st to create a mapping
162 This is not very robust, but works for rectangular grids
163 ====================
164 */
166  if ( tri == currentTriMapping ) {
167  return;
168  }
169  currentTriMapping = tri;
170 
171  if ( !tri->verts ) {
172  return;
173  }
174 
175  idDrawVert origin, axis[2];
176 
177  origin.st[0] = 1.0;
178  origin.st[1] = 1.0;
179 
180  axis[0].st[0] = 0;
181  axis[0].st[1] = 1;
182 
183  axis[1].st[0] = 1;
184  axis[1].st[1] = 0;
185 
186  for ( int i = 0 ; i < tri->numVerts ; i++ ) {
187  idDrawVert *v = &tri->verts[i];
188 
189  if ( v->st[0] <= origin.st[0] && v->st[1] <= origin.st[1] ) {
190  origin = *v;
191  }
192  if ( v->st[0] >= axis[0].st[0] && v->st[1] <= axis[0].st[1] ) {
193  axis[0] = *v;
194  }
195  if ( v->st[0] <= axis[1].st[0] && v->st[1] >= axis[1].st[1] ) {
196  axis[1] = *v;
197  }
198  }
199 
200  for ( int i = 0 ; i < 2 ; i++ ) {
201  idVec3 dir = axis[i].xyz - origin.xyz;
202  float texLen = axis[i].st[i] - origin.st[i];
203  float spaceLen = (axis[i].xyz - origin.xyz).Length();
204 
205  float scale = texLen / (spaceLen*spaceLen);
206  dir *= scale;
207 
208  float c = origin.xyz * dir - origin.st[i];
209 
210  localViewToTextureCenter[i][0] = dir[0];
211  localViewToTextureCenter[i][1] = dir[1];
212  localViewToTextureCenter[i][2] = dir[2];
214  }
215 }
216 
217 /*
218 ====================
219 BindForViewOrigin
220 ====================
221 */
222 void idMegaTexture::BindForViewOrigin( const idVec3 viewOrigin ) {
223 
224  SetViewOrigin( viewOrigin );
225 
226  // borderClamp image goes in texture 0
227  GL_SelectTexture( 0 );
229 
230  // level images in higher textures, blurriest first
231  for ( int i = 0 ; i < 7 ; i++ ) {
232  GL_SelectTexture( 1+i );
233 
234  if ( i >= numLevels ) {
236 
237  static float parms[4] = { -2, -2, 0, 1 }; // no contribution
239  } else {
241 
242  if ( r_showMegaTexture.GetBool() ) {
243  if ( i & 1 ) {
245  } else {
247  }
248  } else {
249  level->image->Bind();
250  }
252  }
253  }
254 
255  float parms[4];
256  parms[0] = 0;
257  parms[1] = 0;
258  parms[2] = 0;
259  parms[3] = 1;
261 
262  parms[0] = 1;
263  parms[1] = 1;
264  parms[2] = r_terrainScale.GetFloat();
265  parms[3] = 1;
267 }
268 
269 /*
270 ====================
271 Unbind
272 
273 This can go away once everything uses fragment programs so the enable states don't
274 need tracking
275 ====================
276 */
277 void idMegaTexture::Unbind( void ) {
278  for ( int i = 0 ; i < numLevels ; i++ ) {
279  GL_SelectTexture( 1+i );
281  }
282 }
283 
284 
285 /*
286 ====================
287 SetViewOrigin
288 ====================
289 */
290 void idMegaTexture::SetViewOrigin( const idVec3 viewOrigin ) {
293  currentViewOrigin[0] = viewOrigin[0] + 0.1; // force a change
294  for ( int i = 0 ; i < numLevels ; i++ ) {
295  levels[i].Invalidate();
296  }
297  }
298 
299  if ( viewOrigin == currentViewOrigin ) {
300  return;
301  }
302  if ( r_skipMegaTexture.GetBool() ) {
303  return;
304  }
305 
306  currentViewOrigin = viewOrigin;
307 
308  float texCenter[2];
309 
310  // convert the viewOrigin to a texture center, which will
311  // be a different conversion for each megaTexture
312  for ( int i = 0 ; i < 2 ; i++ ) {
313  texCenter[i] =
314  viewOrigin[0] * localViewToTextureCenter[i][0] +
315  viewOrigin[1] * localViewToTextureCenter[i][1] +
316  viewOrigin[2] * localViewToTextureCenter[i][2] +
318  }
319 
320  for ( int i = 0 ; i < numLevels ; i++ ) {
321  levels[i].UpdateForCenter( texCenter );
322  }
323 }
324 
325 
326 /*
327 ====================
328 UpdateTile
329 
330 A local tile will only be mapped to globalTile[ localTile + X * TILE_PER_LEVEL ] for some x
331 ====================
332 */
333 void idTextureLevel::UpdateTile( int localX, int localY, int globalX, int globalY ) {
334  idTextureTile *tile = &tileMap[localX][localY];
335 
336  if ( tile->x == globalX && tile->y == globalY ) {
337  return;
338  }
339  if ( (globalX & (TILE_PER_LEVEL-1)) != localX || (globalY & (TILE_PER_LEVEL-1)) != localY ) {
340  common->Error( "idTextureLevel::UpdateTile: bad coordinate mod" );
341  }
342 
343  tile->x = globalX;
344  tile->y = globalY;
345 
346  byte data[ TILE_SIZE * TILE_SIZE * 4 ];
347 
348  if ( globalX >= tilesWide || globalX < 0 || globalY >= tilesHigh || globalY < 0 ) {
349  // off the map
350  memset( data, 0, sizeof( data ) );
351  } else {
352  // extract the data from the full image (FIXME: background load from disk)
353  int tileNum = tileOffset + tile->y * tilesWide + tile->x;
354 
355  int tileSize = TILE_SIZE * TILE_SIZE * 4;
356 
357  mega->fileHandle->Seek( tileNum * tileSize, FS_SEEK_SET );
358  memset( data, 128, sizeof( data ) );
359  mega->fileHandle->Read( data, tileSize );
360  }
361 
362  if ( idMegaTexture::r_showMegaTextureLabels.GetBool() ) {
363  // put a color marker in it
364  byte color[4] = { 255 * localX / TILE_PER_LEVEL, 255 * localY / TILE_PER_LEVEL, 0, 0 };
365  for ( int x = 0 ; x < 8 ; x++ ) {
366  for ( int y = 0 ; y < 8 ; y++ ) {
367  *(int *)&data[ ( ( y + TILE_SIZE/2 - 4 ) * TILE_SIZE + x + TILE_SIZE/2 - 4 ) * 4 ] = *(int *)color;
368  }
369  }
370  }
371 
372  // upload all the mip-map levels
373  int level = 0;
374  int size = TILE_SIZE;
375  while ( 1 ) {
376  qglTexSubImage2D( GL_TEXTURE_2D, level, localX * size, localY * size, size, size, GL_RGBA, GL_UNSIGNED_BYTE, data );
377  size >>= 1;
378  level++;
379 
380  if ( size == 0 ) {
381  break;
382  }
383 
384  int byteSize = size * 4;
385  // mip-map in place
386  for ( int y = 0 ; y < size ; y++ ) {
387  byte *in, *in2, *out;
388  in = data + y * size * 16;
389  in2 = in + size * 8;
390  out = data + y * size * 4;
391  for ( int x = 0 ; x < size ; x++ ) {
392  out[x*4+0] = ( in[x*8+0] + in[x*8+4+0] + in2[x*8+0] + in2[x*8+4+0] ) >> 2;
393  out[x*4+1] = ( in[x*8+1] + in[x*8+4+1] + in2[x*8+1] + in2[x*8+4+1] ) >> 2;
394  out[x*4+2] = ( in[x*8+2] + in[x*8+4+2] + in2[x*8+2] + in2[x*8+4+2] ) >> 2;
395  out[x*4+3] = ( in[x*8+3] + in[x*8+4+3] + in2[x*8+3] + in2[x*8+4+3] ) >> 2;
396  }
397  }
398  }
399 }
400 
401 /*
402 ====================
403 UpdateForCenter
404 
405 Center is in the 0.0 to 1.0 range
406 ====================
407 */
408 void idTextureLevel::UpdateForCenter( float center[2] ) {
409  int globalTileCorner[2];
410  int localTileOffset[2];
411 
412  if ( tilesWide <= TILE_PER_LEVEL && tilesHigh <= TILE_PER_LEVEL ) {
413  globalTileCorner[0] = 0;
414  globalTileCorner[1] = 0;
415  localTileOffset[0] = 0;
416  localTileOffset[1] = 0;
417  // orient the mask so that it doesn't mask anything at all
418  parms[0] = 0.25;
419  parms[1] = 0.25;
420  parms[3] = 0.25;
421  } else {
422  for ( int i = 0 ; i < 2 ; i++ ) {
423  float global[2];
424 
425  // this value will be outside the 0.0 to 1.0 range unless
426  // we are in the corner of the megaTexture
427  global[i] = ( center[i] * parms[3] - 0.5 ) * TILE_PER_LEVEL;
428 
429  globalTileCorner[i] = (int)( global[i] + 0.5 );
430 
431  localTileOffset[i] = globalTileCorner[i] & (TILE_PER_LEVEL-1);
432 
433  // scaling for the mask texture to only allow the proper window
434  // of tiles to show through
435  parms[i] = -globalTileCorner[i] / (float)TILE_PER_LEVEL;
436  }
437  }
438 
439  image->Bind();
440 
441  for ( int x = 0 ; x < TILE_PER_LEVEL ; x++ ) {
442  for ( int y = 0 ; y < TILE_PER_LEVEL ; y++ ) {
443  int globalTile[2];
444 
445  globalTile[0] = globalTileCorner[0] + ( ( x - localTileOffset[0] ) & (TILE_PER_LEVEL-1) );
446  globalTile[1] = globalTileCorner[1] + ( ( y - localTileOffset[1] ) & (TILE_PER_LEVEL-1) );
447 
448  UpdateTile( x, y, globalTile[0], globalTile[1] );
449  }
450  }
451 }
452 
453 /*
454 =====================
455 Invalidate
456 
457 Forces all tiles to be regenerated
458 =====================
459 */
461  for ( int x = 0 ; x < TILE_PER_LEVEL ; x++ ) {
462  for ( int y = 0 ; y < TILE_PER_LEVEL ; y++ ) {
463  tileMap[x][y].x =
464  tileMap[x][y].y = -99999;
465  }
466  }
467 }
468 
469 //===================================================================================================
470 
471 
472 typedef struct _TargaHeader {
473  unsigned char id_length, colormap_type, image_type;
474  unsigned short colormap_index, colormap_length;
475  unsigned char colormap_size;
476  unsigned short x_origin, y_origin, width, height;
477  unsigned char pixel_size, attributes;
478 } TargaHeader;
479 
480 
481 static byte ReadByte( idFile *f ) {
482  byte b;
483 
484  f->Read( &b, 1 );
485  return b;
486 }
487 
488 static short ReadShort( idFile *f ) {
489  byte b[2];
490 
491  f->Read( &b, 2 );
492 
493  return b[0] + ( b[1] << 8 );
494 }
495 
496 
497 /*
498 ====================
499 GenerateMegaMipMaps
500 ====================
501 */
503  outFile->Flush();
504 
505  // out fileSystem doesn't allow read / write access...
506  idFile *inFile = fileSystem->OpenFileRead( outFile->GetName() );
507 
508  int tileOffset = 1;
509  int width = header->tilesWide;
510  int height = header->tilesHigh;
511 
512  int tileSize = header->tileSize * header->tileSize * 4;
513  byte *oldBlock = (byte *)_alloca( tileSize );
514  byte *newBlock = (byte *)_alloca( tileSize );
515 
516  while ( width > 1 || height > 1 ) {
517  int newHeight = (height+1) >> 1;
518  if ( newHeight < 1 ) {
519  newHeight = 1;
520  }
521  int newWidth = (width+1) >> 1;
522  if ( width < 1 ) {
523  width = 1;
524  }
525  common->Printf( "generating %i x %i block mip level\n", newWidth, newHeight );
526 
527  int tileNum;
528 
529  for ( int y = 0 ; y < newHeight ; y++ ) {
530  common->Printf( "row %i\n", y );
532 
533  for ( int x = 0 ; x < newWidth ; x++ ) {
534  // mip map four original blocks down into a single new block
535  for ( int yy = 0 ; yy < 2 ; yy++ ) {
536  for ( int xx = 0 ; xx< 2 ; xx++ ) {
537  int tx = x*2 + xx;
538  int ty = y*2 + yy;
539 
540  if ( tx > width || ty > height ) {
541  // off edge, zero fill
542  memset( newBlock, 0, sizeof( newBlock ) );
543  } else {
544  tileNum = tileOffset + ty * width + tx;
545  inFile->Seek( tileNum * tileSize, FS_SEEK_SET );
546  inFile->Read( oldBlock, tileSize );
547  }
548  // mip map the new pixels
549  for ( int yyy = 0 ; yyy < TILE_SIZE / 2 ; yyy++ ) {
550  for ( int xxx = 0 ; xxx < TILE_SIZE / 2 ; xxx++ ) {
551  byte *in = &oldBlock[ ( yyy * 2 * TILE_SIZE + xxx * 2 ) * 4 ];
552  byte *out = &newBlock[ ( ( ( TILE_SIZE/2 * yy ) + yyy ) * TILE_SIZE + ( TILE_SIZE/2 * xx ) + xxx ) * 4 ];
553  out[0] = ( in[0] + in[4] + in[0+TILE_SIZE*4] + in[4+TILE_SIZE*4] ) >> 2;
554  out[1] = ( in[1] + in[5] + in[1+TILE_SIZE*4] + in[5+TILE_SIZE*4] ) >> 2;
555  out[2] = ( in[2] + in[6] + in[2+TILE_SIZE*4] + in[6+TILE_SIZE*4] ) >> 2;
556  out[3] = ( in[3] + in[7] + in[3+TILE_SIZE*4] + in[7+TILE_SIZE*4] ) >> 2;
557  }
558  }
559 
560  // write the block out
561  tileNum = tileOffset + width * height + y * newWidth + x;
562  outFile->Seek( tileNum * tileSize, FS_SEEK_SET );
563  outFile->Write( newBlock, tileSize );
564 
565  }
566  }
567  }
568  }
569  tileOffset += width * height;
570  width = newWidth;
571  height = newHeight;
572  }
573 
574  delete inFile;
575 }
576 
577 /*
578 ====================
579 GenerateMegaPreview
580 
581 Make a 2k x 2k preview image for a mega texture that can be used in modeling programs
582 ====================
583 */
584 void idMegaTexture::GenerateMegaPreview( const char *fileName ) {
585  idFile *fileHandle = fileSystem->OpenFileRead( fileName );
586  if ( !fileHandle ) {
587  common->Printf( "idMegaTexture: failed to open %s\n", fileName );
588  return;
589  }
590 
591  idStr outName = fileName;
592  outName.StripFileExtension();
593  outName += "_preview.tga";
594 
595  common->Printf( "Creating %s.\n", outName.c_str() );
596 
598 
599  fileHandle->Read( &header, sizeof( header ) );
600  if ( header.tileSize < 64 || header.tilesWide < 1 || header.tilesHigh < 1 ) {
601  common->Printf( "idMegaTexture: bad header on %s\n", fileName );
602  return;
603  }
604 
605  int tileSize = header.tileSize;
606  int width = header.tilesWide;
607  int height = header.tilesHigh;
608  int tileOffset = 1;
609  int tileBytes = tileSize * tileSize * 4;
610  // find the level that fits
611  while ( width * tileSize > 2048 || height * tileSize > 2048 ) {
612  tileOffset += width * height;
613  width >>= 1;
614  if ( width < 1 ) {
615  width = 1;
616  }
617  height >>= 1;
618  if ( height < 1 ) {
619  height = 1;
620  }
621  }
622 
623  byte *pic = (byte *)R_StaticAlloc( width * height * tileBytes );
624  byte *oldBlock = (byte *)_alloca( tileBytes );
625  for ( int y = 0 ; y < height ; y++ ) {
626  for ( int x = 0 ; x < width ; x++ ) {
627  int tileNum = tileOffset + y * width + x;
628  fileHandle->Seek( tileNum * tileBytes, FS_SEEK_SET );
629  fileHandle->Read( oldBlock, tileBytes );
630 
631  for ( int yy = 0 ; yy < tileSize ; yy++ ) {
632  memcpy( pic + ( ( y * tileSize + yy ) * width * tileSize + x * tileSize ) * 4,
633  oldBlock + yy * tileSize * 4, tileSize * 4 );
634  }
635  }
636  }
637 
638  R_WriteTGA( outName.c_str(), pic, width * tileSize, height * tileSize, false );
639 
640  R_StaticFree( pic );
641 
642  delete fileHandle;
643 }
644 
645 
646 /*
647 ====================
648 MakeMegaTexture_f
649 
650 Incrementally load a giant tga file and process into the mega texture block format
651 ====================
652 */
654  int columns, rows, fileSize, numBytes;
655  byte *pixbuf;
656  int row, column;
657  TargaHeader targa_header;
658 
659  if ( args.Argc() != 2 ) {
660  common->Printf( "USAGE: makeMegaTexture <filebase>\n" );
661  return;
662  }
663 
664  idStr name_s = "megaTextures/";
665  name_s += args.Argv(1);
666  name_s.StripFileExtension();
667  name_s += ".tga";
668 
669  const char *name = name_s.c_str();
670 
671  //
672  // open the file
673  //
674  common->Printf( "Opening %s.\n", name );
675  fileSize = fileSystem->ReadFile( name, NULL, NULL );
676  idFile *file = fileSystem->OpenFileRead( name );
677 
678  if ( !file ) {
679  common->Printf( "Couldn't open %s\n", name );
680  return;
681  }
682 
683  targa_header.id_length = ReadByte( file );
684  targa_header.colormap_type = ReadByte( file );
685  targa_header.image_type = ReadByte( file );
686 
687  targa_header.colormap_index = ReadShort( file );
688  targa_header.colormap_length = ReadShort( file );
689  targa_header.colormap_size = ReadByte( file );
690  targa_header.x_origin = ReadShort( file );
691  targa_header.y_origin = ReadShort( file );
692  targa_header.width = ReadShort( file );
693  targa_header.height = ReadShort( file );
694  targa_header.pixel_size = ReadByte( file );
695  targa_header.attributes = ReadByte( file );
696 
697  if ( targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3 ) {
698  common->Error( "LoadTGA( %s ): Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n", name );
699  }
700 
701  if ( targa_header.colormap_type != 0 ) {
702  common->Error( "LoadTGA( %s ): colormaps not supported\n", name );
703  }
704 
705  if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 ) {
706  common->Error( "LoadTGA( %s ): Only 32 or 24 bit images supported (no colormaps)\n", name );
707  }
708 
709  if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) {
710  numBytes = targa_header.width * targa_header.height * ( targa_header.pixel_size >> 3 );
711  if ( numBytes > fileSize - 18 - targa_header.id_length ) {
712  common->Error( "LoadTGA( %s ): incomplete file\n", name );
713  }
714  }
715 
716  columns = targa_header.width;
717  rows = targa_header.height;
718 
719  // skip TARGA image comment
720  if ( targa_header.id_length != 0 ) {
721  file->Seek( targa_header.id_length, FS_SEEK_CUR );
722  }
723 
724  megaTextureHeader_t mtHeader;
725 
726  mtHeader.tileSize = TILE_SIZE;
727  mtHeader.tilesWide = RoundDownToPowerOfTwo( targa_header.width ) / TILE_SIZE;
728  mtHeader.tilesHigh = RoundDownToPowerOfTwo( targa_header.height ) / TILE_SIZE;
729 
730  idStr outName = name;
731  outName.StripFileExtension();
732  outName += ".mega";
733 
734  common->Printf( "Writing %i x %i size %i tiles to %s.\n",
735  mtHeader.tilesWide, mtHeader.tilesHigh, mtHeader.tileSize, outName.c_str() );
736 
737  // open the output megatexture file
738  idFile *out = fileSystem->OpenFileWrite( outName.c_str() );
739 
740  out->Write( &mtHeader, sizeof( mtHeader ) );
741  out->Seek( TILE_SIZE * TILE_SIZE * 4, FS_SEEK_SET );
742 
743  // we will process this one row of tiles at a time, since the entire thing
744  // won't fit in memory
745  byte *targa_rgba = (byte *)R_StaticAlloc( TILE_SIZE * targa_header.width * 4 );
746 
747  int blockRowsRemaining = mtHeader.tilesHigh;
748  while ( blockRowsRemaining-- ) {
749  common->Printf( "%i blockRowsRemaining\n", blockRowsRemaining );
751 
752  if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) {
753  // Uncompressed RGB or gray scale image
754  for( row = 0 ; row < TILE_SIZE ; row++ ) {
755  pixbuf = targa_rgba + row*columns*4;
756  for( column = 0; column < columns; column++) {
757  unsigned char red,green,blue,alphabyte;
758  switch( targa_header.pixel_size ) {
759  case 8:
760  blue = ReadByte( file );
761  green = blue;
762  red = blue;
763  *pixbuf++ = red;
764  *pixbuf++ = green;
765  *pixbuf++ = blue;
766  *pixbuf++ = 255;
767  break;
768 
769  case 24:
770  blue = ReadByte( file );
771  green = ReadByte( file );
772  red = ReadByte( file );
773  *pixbuf++ = red;
774  *pixbuf++ = green;
775  *pixbuf++ = blue;
776  *pixbuf++ = 255;
777  break;
778  case 32:
779  blue = ReadByte( file );
780  green = ReadByte( file );
781  red = ReadByte( file );
782  alphabyte = ReadByte( file );
783  *pixbuf++ = red;
784  *pixbuf++ = green;
785  *pixbuf++ = blue;
786  *pixbuf++ = alphabyte;
787  break;
788  default:
789  common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size );
790  break;
791  }
792  }
793  }
794  } else if ( targa_header.image_type == 10 ) { // Runlength encoded RGB images
795  unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
796 
797  red = 0;
798  green = 0;
799  blue = 0;
800  alphabyte = 0xff;
801 
802  for( row = 0 ; row < TILE_SIZE ; row++ ) {
803  pixbuf = targa_rgba + row*columns*4;
804  for( column = 0; column < columns; ) {
805  packetHeader= ReadByte( file );
806  packetSize = 1 + (packetHeader & 0x7f);
807  if ( packetHeader & 0x80 ) { // run-length packet
808  switch( targa_header.pixel_size ) {
809  case 24:
810  blue = ReadByte( file );
811  green = ReadByte( file );
812  red = ReadByte( file );
813  alphabyte = 255;
814  break;
815  case 32:
816  blue = ReadByte( file );
817  green = ReadByte( file );
818  red = ReadByte( file );
819  alphabyte = ReadByte( file );
820  break;
821  default:
822  common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size );
823  break;
824  }
825 
826  for( j = 0; j < packetSize; j++ ) {
827  *pixbuf++=red;
828  *pixbuf++=green;
829  *pixbuf++=blue;
830  *pixbuf++=alphabyte;
831  column++;
832  if ( column == columns ) { // run spans across rows
833  common->Error( "TGA had RLE across columns, probably breaks block" );
834  column = 0;
835  if ( row > 0) {
836  row--;
837  }
838  else {
839  goto breakOut;
840  }
841  pixbuf = targa_rgba + row*columns*4;
842  }
843  }
844  } else { // non run-length packet
845  for( j = 0; j < packetSize; j++ ) {
846  switch( targa_header.pixel_size ) {
847  case 24:
848  blue = ReadByte( file );
849  green = ReadByte( file );
850  red = ReadByte( file );
851  *pixbuf++ = red;
852  *pixbuf++ = green;
853  *pixbuf++ = blue;
854  *pixbuf++ = 255;
855  break;
856  case 32:
857  blue = ReadByte( file );
858  green = ReadByte( file );
859  red = ReadByte( file );
860  alphabyte = ReadByte( file );
861  *pixbuf++ = red;
862  *pixbuf++ = green;
863  *pixbuf++ = blue;
864  *pixbuf++ = alphabyte;
865  break;
866  default:
867  common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size );
868  break;
869  }
870  column++;
871  if ( column == columns ) { // pixel packet run spans across rows
872  column = 0;
873  if ( row > 0 ) {
874  row--;
875  }
876  else {
877  goto breakOut;
878  }
879  pixbuf = targa_rgba + row*columns*4;
880  }
881  }
882  }
883  }
884  breakOut: ;
885  }
886  }
887 
888  //
889  // write out individual blocks from the full row block buffer
890  //
891  for ( int rowBlock = 0 ; rowBlock < mtHeader.tilesWide ; rowBlock++ ) {
892  for ( int y = 0 ; y < TILE_SIZE ; y++ ) {
893  out->Write( targa_rgba + ( y * targa_header.width + rowBlock * TILE_SIZE ) * 4, TILE_SIZE * 4 );
894  }
895  }
896  }
897 
898  R_StaticFree( targa_rgba );
899 
900  GenerateMegaMipMaps( &mtHeader, out );
901 
902  delete out;
903  delete file;
904 
905  GenerateMegaPreview( outName.c_str() );
906 #if 0
907  if ( (targa_header.attributes & (1<<5)) ) { // image flp bit
908  R_VerticalFlip( *pic, *width, *height );
909  }
910 #endif
911 }
912 
913 
byte color[4]
Definition: MegaTexture.cpp:54
virtual idFile * OpenFileRead(const char *relativePath, bool allowCopyFiles=true, const char *gamedir=NULL)=0
void SetMappingForSurface(const srfTriangles_t *tri)
idVec3 currentViewOrigin
Definition: MegaTexture.h:85
Definition: Image.h:146
const srfTriangles_t * currentTriMapping
Definition: MegaTexture.h:83
idFile * fileHandle
Definition: MegaTexture.h:81
int numVerts
Definition: Model.h:98
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
float parms[4]
Definition: MegaTexture.h:53
float GetFloat(void) const
Definition: CVarSystem.h:144
const GLdouble * v
Definition: glext.h:2936
virtual int ReadFile(const char *relativePath, void **buffer, ID_TIME_T *timestamp=NULL)=0
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:4804
struct _TargaHeader TargaHeader
idVec3 xyz
Definition: DrawVert.h:42
GLenum GLint GLint y
Definition: glext.h:2849
void UpdateForCenter(float center[2])
case const int
Definition: Callbacks.cpp:52
megaTextureHeader_t header
Definition: MegaTexture.h:91
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
Definition: Vector.h:316
case const float
Definition: Callbacks.cpp:62
GLenum GLsizei GLenum GLenum const GLvoid * image
Definition: glext.h:2855
unsigned short width
GLclampf GLclampf blue
Definition: glext.h:2843
idMegaTexture * mega
Definition: MegaTexture.h:44
unsigned short height
GLenum GLint x
Definition: glext.h:2849
virtual const char * GetName(void)
Definition: File.cpp:161
int i
Definition: process.py:33
idTextureLevel levels[MAX_LEVELS]
Definition: MegaTexture.h:90
GLuint GLuint num
Definition: glext.h:5390
#define qglTexSubImage2D
Definition: qgl_linked.h:336
unsigned char colormap_type
idImage * image
Definition: MegaTexture.h:50
static void MakeMegaTexture_f(const idCmdArgs &args)
static idCVar r_megaTextureLevel
Definition: MegaTexture.h:93
unsigned char id_length
Definition: File.h:50
idVec2 st
Definition: DrawVert.h:43
virtual void Flush(void)
Definition: File.cpp:234
int intVal
Definition: MegaTexture.cpp:53
const GLubyte * c
Definition: glext.h:4677
idStr & StripFileExtension(void)
Definition: Str.cpp:757
GLbyte ty
Definition: glext.h:4528
void BindForViewOrigin(const idVec3 origin)
static void GenerateMegaMipMaps(megaTextureHeader_t *header, idFile *file)
static idCVar r_skipMegaTexture
Definition: MegaTexture.h:96
idCommon * common
Definition: Common.cpp:206
#define NULL
Definition: Lib.h:88
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:2853
void SetViewOrigin(const idVec3 origin)
idImageManager * globalImages
Definition: Image_init.cpp:74
idImage * whiteImage
Definition: Image.h:398
virtual idFile * OpenFileWrite(const char *relativePath, const char *basePath="fs_savepath")=0
virtual int Read(void *buffer, int len)
Definition: File.cpp:179
unsigned short y_origin
void R_WriteTGA(const char *filename, const byte *data, int width, int height, bool flipVertical=false)
Definition: Image_files.cpp:85
static idCVar r_showMegaTextureLabels
Definition: MegaTexture.h:95
idImage * borderClampImage
Definition: Image.h:412
int Argc(void) const
Definition: CmdArgs.h:48
idImage * blackImage
Definition: Image.h:399
idImage * ImageFromFunction(const char *name, void(*generatorFunction)(idImage *image))
unsigned short x_origin
GLenum GLsizei width
Definition: glext.h:2846
virtual void UpdateScreen(bool outOfSequence=true)=0
unsigned char pixel_size
virtual void Printf(const char *fmt,...) id_attribute((format(printf
virtual int Seek(long offset, fsOrigin_t origin)
Definition: File.cpp:242
GLenum GLsizei GLsizei height
Definition: glext.h:2856
GLubyte GLubyte b
Definition: glext.h:4662
static idCVar r_showMegaTexture
Definition: MegaTexture.h:94
GLenum GLenum GLvoid * row
Definition: glext.h:2866
void UpdateTile(int localX, int localY, int globalX, int globalY)
float localViewToTextureCenter[2][4]
Definition: MegaTexture.h:87
bool GetBool(void) const
Definition: CVarSystem.h:142
void ClearModified(void)
Definition: CVarSystem.h:139
tuple f
Definition: idal.py:89
static idCVar r_terrainScale
Definition: MegaTexture.h:97
void R_VerticalFlip(byte *data, int width, int height)
GLuint in
Definition: glext.h:5388
unsigned char byte
Definition: Lib.h:75
void * R_StaticAlloc(int bytes)
Definition: tr_main.cpp:301
const GLcharARB * name
Definition: glext.h:3629
GLsizeiptr size
Definition: glext.h:3112
idTextureTile tileMap[TILE_PER_LEVEL][TILE_PER_LEVEL]
Definition: MegaTexture.h:51
#define GL_VERTEX_PROGRAM_ARB
Definition: glext.h:594
bool IsModified(void) const
Definition: CVarSystem.h:137
virtual int Write(const void *buffer, int len)
Definition: File.cpp:189
Definition: Str.h:116
PFNGLPROGRAMLOCALPARAMETER4FVARBPROC qglProgramLocalParameter4fvARB
unsigned char image_type
const char * c_str(void) const
Definition: Str.h:487
unsigned char colormap_size
unsigned short colormap_index
const char * Argv(int arg) const
Definition: CmdArgs.h:50
GLint j
Definition: qgl.h:264
GLint level
Definition: glext.h:2878
bool InitFromMegaFile(const char *fileBase)
Definition: MegaTexture.cpp:87
idSession * session
Definition: Session.cpp:48
void GL_SelectTexture(int unit)
Definition: tr_backend.cpp:135
GLenum GLenum GLvoid GLvoid * column
Definition: glext.h:2866
void R_StaticFree(void *data)
Definition: tr_main.cpp:335
int RoundDownToPowerOfTwo(int num)
Definition: MegaTexture.cpp:45
virtual void Error(const char *fmt,...) id_attribute((format(printf
void Bind()
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
unsigned char attributes
idDrawVert * verts
Definition: Model.h:99
unsigned short colormap_length
GLclampf green
Definition: glext.h:2843
static void GenerateMegaPreview(const char *fileName)