]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/renderer/MegaTexture.cpp
Use the same OpenAL headers on all platforms.
[icculus/iodoom3.git] / neo / renderer / MegaTexture.cpp
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
45 int RoundDownToPowerOfTwo( int num ) {
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, 
78                 TF_DEFAULT, false, TR_REPEAT, TD_HIGH_QUALITY );
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
95         fileHandle = fileSystem->OpenFileRead( name.c_str() );
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
107         currentTriMapping = NULL;
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 ) {
117                 idTextureLevel *level = &levels[numLevels];
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 */
165 void    idMegaTexture::SetMappingForSurface( const srfTriangles_t *tri ) {
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];
213                 localViewToTextureCenter[i][3] = -c;
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 );
228         globalImages->borderClampImage->Bind();
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 ) {
235                         globalImages->whiteImage->Bind();
236
237                         static float    parms[4] = { -2, -2, 0, 1 };    // no contribution
238                         qglProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, i, parms );
239                 } else {
240                         idTextureLevel  *level = &levels[ numLevels-1-i ];
241                         
242                         if ( r_showMegaTexture.GetBool() ) {
243                                 if ( i & 1 ) {
244                                         globalImages->blackImage->Bind();
245                                 } else {
246                                         globalImages->whiteImage->Bind();
247                                 }
248                         } else {
249                                 level->image->Bind();
250                         }
251                         qglProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, i, level->parms );
252                 }
253         }
254
255         float   parms[4];
256         parms[0] = 0;
257         parms[1] = 0;
258         parms[2] = 0;
259         parms[3] = 1;
260         qglProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 7, parms );
261
262         parms[0] = 1;
263         parms[1] = 1;
264         parms[2] = r_terrainScale.GetFloat();
265         parms[3] = 1;
266         qglProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 8, parms );
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 );
280                 globalImages->BindNull();
281         }
282 }
283
284
285 /*
286 ====================
287 SetViewOrigin
288 ====================
289 */
290 void idMegaTexture::SetViewOrigin( const idVec3 viewOrigin ) {
291         if ( r_showMegaTextureLabels.IsModified() ) {
292                 r_showMegaTextureLabels.ClearModified();
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] +
317                         localViewToTextureCenter[i][3];
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 */
460 void idTextureLevel::Invalidate() {
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 */
502 void    idMegaTexture::GenerateMegaMipMaps( megaTextureHeader_t *header, idFile *outFile ) {
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 );
531                         session->UpdateScreen();
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
597         megaTextureHeader_t header;
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 */
653 void idMegaTexture::MakeMegaTexture_f( const idCmdArgs &args ) {
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 );
750                 session->UpdateScreen();
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