MegaTexture.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. 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.
  17. 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.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "tr_local.h"
  23. idCVar idMegaTexture::r_megaTextureLevel( "r_megaTextureLevel", "0", CVAR_RENDERER | CVAR_INTEGER, "draw only a specific level" );
  24. idCVar idMegaTexture::r_showMegaTexture( "r_showMegaTexture", "0", CVAR_RENDERER | CVAR_BOOL, "display all the level images" );
  25. idCVar idMegaTexture::r_showMegaTextureLabels( "r_showMegaTextureLabels", "0", CVAR_RENDERER | CVAR_BOOL, "draw colored blocks in each tile" );
  26. idCVar idMegaTexture::r_skipMegaTexture( "r_skipMegaTexture", "0", CVAR_RENDERER | CVAR_INTEGER, "only use the lowest level image" );
  27. idCVar idMegaTexture::r_terrainScale( "r_terrainScale", "3", CVAR_RENDERER | CVAR_INTEGER, "vertically scale USGS data" );
  28. /*
  29. allow sparse population of the upper detail tiles
  30. */
  31. int RoundDownToPowerOfTwo( int num ) {
  32. int pot;
  33. for (pot = 1 ; (pot*2) <= num ; pot<<=1) {
  34. }
  35. return pot;
  36. }
  37. static union {
  38. int intVal;
  39. byte color[4];
  40. } fillColor;
  41. static byte colors[8][4] = {
  42. { 0, 0, 0, 255 },
  43. { 255, 0, 0, 255 },
  44. { 0, 255, 0, 255 },
  45. { 255, 255, 0, 255 },
  46. { 0, 0, 255, 255 },
  47. { 255, 0, 255, 255 },
  48. { 0, 255, 255, 255 },
  49. { 255, 255, 255, 255 }
  50. };
  51. static void R_EmptyLevelImage( idImage *image ) {
  52. int c = MAX_LEVEL_WIDTH * MAX_LEVEL_WIDTH;
  53. byte *data = (byte *)_alloca( c*4 );
  54. for ( int i = 0 ; i < c ; i++ ) {
  55. ((int *)data)[i] = fillColor.intVal;
  56. }
  57. // FIXME: this won't live past vid mode changes
  58. image->GenerateImage( data, MAX_LEVEL_WIDTH, MAX_LEVEL_WIDTH,
  59. TF_DEFAULT, false, TR_REPEAT, TD_HIGH_QUALITY );
  60. }
  61. /*
  62. ====================
  63. InitFromMegaFile
  64. ====================
  65. */
  66. bool idMegaTexture::InitFromMegaFile( const char *fileBase ) {
  67. idStr name = "megaTextures/";
  68. name += fileBase;
  69. name.StripFileExtension();
  70. name += ".mega";
  71. int width, height;
  72. fileHandle = fileSystem->OpenFileRead( name.c_str() );
  73. if ( !fileHandle ) {
  74. common->Printf( "idMegaTexture: failed to open %s\n", name.c_str() );
  75. return false;
  76. }
  77. fileHandle->Read( &header, sizeof( header ) );
  78. if ( header.tileSize < 64 || header.tilesWide < 1 || header.tilesHigh < 1 ) {
  79. common->Printf( "idMegaTexture: bad header on %s\n", name.c_str() );
  80. return false;
  81. }
  82. currentTriMapping = NULL;
  83. numLevels = 0;
  84. width = header.tilesWide;
  85. height = header.tilesHigh;
  86. int tileOffset = 1; // just past the header
  87. memset( levels, 0, sizeof( levels ) );
  88. while( 1 ) {
  89. idTextureLevel *level = &levels[numLevels];
  90. level->mega = this;
  91. level->tileOffset = tileOffset;
  92. level->tilesWide = width;
  93. level->tilesHigh = height;
  94. level->parms[0] = -1; // initially mask everything
  95. level->parms[1] = 0;
  96. level->parms[2] = 0;
  97. level->parms[3] = (float)width / TILE_PER_LEVEL;
  98. level->Invalidate();
  99. tileOffset += level->tilesWide * level->tilesHigh;
  100. char str[1024];
  101. sprintf( str, "MEGA_%s_%i", fileBase, numLevels );
  102. // give each level a default fill color
  103. for (int i = 0 ; i < 4 ; i++ ) {
  104. fillColor.color[i] = colors[numLevels+1][i];
  105. }
  106. levels[numLevels].image = globalImages->ImageFromFunction( str, R_EmptyLevelImage );
  107. numLevels++;
  108. if ( width <= TILE_PER_LEVEL && height <= TILE_PER_LEVEL ) {
  109. break;
  110. }
  111. width = ( width + 1 ) >> 1;
  112. height = ( height + 1 ) >> 1;
  113. }
  114. // force first bind to load everything
  115. currentViewOrigin[0] = -99999999.0f;
  116. currentViewOrigin[1] = -99999999.0f;
  117. currentViewOrigin[2] = -99999999.0f;
  118. return true;
  119. }
  120. /*
  121. ====================
  122. SetMappingForSurface
  123. analyzes xyz and st to create a mapping
  124. This is not very robust, but works for rectangular grids
  125. ====================
  126. */
  127. void idMegaTexture::SetMappingForSurface( const srfTriangles_t *tri ) {
  128. if ( tri == currentTriMapping ) {
  129. return;
  130. }
  131. currentTriMapping = tri;
  132. if ( !tri->verts ) {
  133. return;
  134. }
  135. idDrawVert origin, axis[2];
  136. origin.st[0] = 1.0;
  137. origin.st[1] = 1.0;
  138. axis[0].st[0] = 0;
  139. axis[0].st[1] = 1;
  140. axis[1].st[0] = 1;
  141. axis[1].st[1] = 0;
  142. for ( int i = 0 ; i < tri->numVerts ; i++ ) {
  143. idDrawVert *v = &tri->verts[i];
  144. if ( v->st[0] <= origin.st[0] && v->st[1] <= origin.st[1] ) {
  145. origin = *v;
  146. }
  147. if ( v->st[0] >= axis[0].st[0] && v->st[1] <= axis[0].st[1] ) {
  148. axis[0] = *v;
  149. }
  150. if ( v->st[0] <= axis[1].st[0] && v->st[1] >= axis[1].st[1] ) {
  151. axis[1] = *v;
  152. }
  153. }
  154. for ( int i = 0 ; i < 2 ; i++ ) {
  155. idVec3 dir = axis[i].xyz - origin.xyz;
  156. float texLen = axis[i].st[i] - origin.st[i];
  157. float spaceLen = (axis[i].xyz - origin.xyz).Length();
  158. float scale = texLen / (spaceLen*spaceLen);
  159. dir *= scale;
  160. float c = origin.xyz * dir - origin.st[i];
  161. localViewToTextureCenter[i][0] = dir[0];
  162. localViewToTextureCenter[i][1] = dir[1];
  163. localViewToTextureCenter[i][2] = dir[2];
  164. localViewToTextureCenter[i][3] = -c;
  165. }
  166. }
  167. /*
  168. ====================
  169. BindForViewOrigin
  170. ====================
  171. */
  172. void idMegaTexture::BindForViewOrigin( const idVec3 viewOrigin ) {
  173. SetViewOrigin( viewOrigin );
  174. // borderClamp image goes in texture 0
  175. GL_SelectTexture( 0 );
  176. globalImages->borderClampImage->Bind();
  177. // level images in higher textures, blurriest first
  178. for ( int i = 0 ; i < 7 ; i++ ) {
  179. GL_SelectTexture( 1+i );
  180. if ( i >= numLevels ) {
  181. globalImages->whiteImage->Bind();
  182. static float parms[4] = { -2, -2, 0, 1 }; // no contribution
  183. qglProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, i, parms );
  184. } else {
  185. idTextureLevel *level = &levels[ numLevels-1-i ];
  186. if ( r_showMegaTexture.GetBool() ) {
  187. if ( i & 1 ) {
  188. globalImages->blackImage->Bind();
  189. } else {
  190. globalImages->whiteImage->Bind();
  191. }
  192. } else {
  193. level->image->Bind();
  194. }
  195. qglProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, i, level->parms );
  196. }
  197. }
  198. float parms[4];
  199. parms[0] = 0;
  200. parms[1] = 0;
  201. parms[2] = 0;
  202. parms[3] = 1;
  203. qglProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 7, parms );
  204. parms[0] = 1;
  205. parms[1] = 1;
  206. parms[2] = r_terrainScale.GetFloat();
  207. parms[3] = 1;
  208. qglProgramLocalParameter4fvARB( GL_VERTEX_PROGRAM_ARB, 8, parms );
  209. }
  210. /*
  211. ====================
  212. Unbind
  213. This can go away once everything uses fragment programs so the enable states don't
  214. need tracking
  215. ====================
  216. */
  217. void idMegaTexture::Unbind( void ) {
  218. for ( int i = 0 ; i < numLevels ; i++ ) {
  219. GL_SelectTexture( 1+i );
  220. globalImages->BindNull();
  221. }
  222. }
  223. /*
  224. ====================
  225. SetViewOrigin
  226. ====================
  227. */
  228. void idMegaTexture::SetViewOrigin( const idVec3 viewOrigin ) {
  229. if ( r_showMegaTextureLabels.IsModified() ) {
  230. r_showMegaTextureLabels.ClearModified();
  231. currentViewOrigin[0] = viewOrigin[0] + 0.1; // force a change
  232. for ( int i = 0 ; i < numLevels ; i++ ) {
  233. levels[i].Invalidate();
  234. }
  235. }
  236. if ( viewOrigin == currentViewOrigin ) {
  237. return;
  238. }
  239. if ( r_skipMegaTexture.GetBool() ) {
  240. return;
  241. }
  242. currentViewOrigin = viewOrigin;
  243. float texCenter[2];
  244. // convert the viewOrigin to a texture center, which will
  245. // be a different conversion for each megaTexture
  246. for ( int i = 0 ; i < 2 ; i++ ) {
  247. texCenter[i] =
  248. viewOrigin[0] * localViewToTextureCenter[i][0] +
  249. viewOrigin[1] * localViewToTextureCenter[i][1] +
  250. viewOrigin[2] * localViewToTextureCenter[i][2] +
  251. localViewToTextureCenter[i][3];
  252. }
  253. for ( int i = 0 ; i < numLevels ; i++ ) {
  254. levels[i].UpdateForCenter( texCenter );
  255. }
  256. }
  257. /*
  258. ====================
  259. UpdateTile
  260. A local tile will only be mapped to globalTile[ localTile + X * TILE_PER_LEVEL ] for some x
  261. ====================
  262. */
  263. void idTextureLevel::UpdateTile( int localX, int localY, int globalX, int globalY ) {
  264. idTextureTile *tile = &tileMap[localX][localY];
  265. if ( tile->x == globalX && tile->y == globalY ) {
  266. return;
  267. }
  268. if ( (globalX & (TILE_PER_LEVEL-1)) != localX || (globalY & (TILE_PER_LEVEL-1)) != localY ) {
  269. common->Error( "idTextureLevel::UpdateTile: bad coordinate mod" );
  270. }
  271. tile->x = globalX;
  272. tile->y = globalY;
  273. byte data[ TILE_SIZE * TILE_SIZE * 4 ];
  274. if ( globalX >= tilesWide || globalX < 0 || globalY >= tilesHigh || globalY < 0 ) {
  275. // off the map
  276. memset( data, 0, sizeof( data ) );
  277. } else {
  278. // extract the data from the full image (FIXME: background load from disk)
  279. int tileNum = tileOffset + tile->y * tilesWide + tile->x;
  280. int tileSize = TILE_SIZE * TILE_SIZE * 4;
  281. mega->fileHandle->Seek( tileNum * tileSize, FS_SEEK_SET );
  282. memset( data, 128, sizeof( data ) );
  283. mega->fileHandle->Read( data, tileSize );
  284. }
  285. if ( idMegaTexture::r_showMegaTextureLabels.GetBool() ) {
  286. // put a color marker in it
  287. byte color[4] = { 255 * localX / TILE_PER_LEVEL, 255 * localY / TILE_PER_LEVEL, 0, 0 };
  288. for ( int x = 0 ; x < 8 ; x++ ) {
  289. for ( int y = 0 ; y < 8 ; y++ ) {
  290. *(int *)&data[ ( ( y + TILE_SIZE/2 - 4 ) * TILE_SIZE + x + TILE_SIZE/2 - 4 ) * 4 ] = *(int *)color;
  291. }
  292. }
  293. }
  294. // upload all the mip-map levels
  295. int level = 0;
  296. int size = TILE_SIZE;
  297. while ( 1 ) {
  298. qglTexSubImage2D( GL_TEXTURE_2D, level, localX * size, localY * size, size, size, GL_RGBA, GL_UNSIGNED_BYTE, data );
  299. size >>= 1;
  300. level++;
  301. if ( size == 0 ) {
  302. break;
  303. }
  304. int byteSize = size * 4;
  305. // mip-map in place
  306. for ( int y = 0 ; y < size ; y++ ) {
  307. byte *in, *in2, *out;
  308. in = data + y * size * 16;
  309. in2 = in + size * 8;
  310. out = data + y * size * 4;
  311. for ( int x = 0 ; x < size ; x++ ) {
  312. out[x*4+0] = ( in[x*8+0] + in[x*8+4+0] + in2[x*8+0] + in2[x*8+4+0] ) >> 2;
  313. out[x*4+1] = ( in[x*8+1] + in[x*8+4+1] + in2[x*8+1] + in2[x*8+4+1] ) >> 2;
  314. out[x*4+2] = ( in[x*8+2] + in[x*8+4+2] + in2[x*8+2] + in2[x*8+4+2] ) >> 2;
  315. out[x*4+3] = ( in[x*8+3] + in[x*8+4+3] + in2[x*8+3] + in2[x*8+4+3] ) >> 2;
  316. }
  317. }
  318. }
  319. }
  320. /*
  321. ====================
  322. UpdateForCenter
  323. Center is in the 0.0 to 1.0 range
  324. ====================
  325. */
  326. void idTextureLevel::UpdateForCenter( float center[2] ) {
  327. int globalTileCorner[2];
  328. int localTileOffset[2];
  329. if ( tilesWide <= TILE_PER_LEVEL && tilesHigh <= TILE_PER_LEVEL ) {
  330. globalTileCorner[0] = 0;
  331. globalTileCorner[1] = 0;
  332. localTileOffset[0] = 0;
  333. localTileOffset[1] = 0;
  334. // orient the mask so that it doesn't mask anything at all
  335. parms[0] = 0.25;
  336. parms[1] = 0.25;
  337. parms[3] = 0.25;
  338. } else {
  339. for ( int i = 0 ; i < 2 ; i++ ) {
  340. float global[2];
  341. // this value will be outside the 0.0 to 1.0 range unless
  342. // we are in the corner of the megaTexture
  343. global[i] = ( center[i] * parms[3] - 0.5 ) * TILE_PER_LEVEL;
  344. globalTileCorner[i] = (int)( global[i] + 0.5 );
  345. localTileOffset[i] = globalTileCorner[i] & (TILE_PER_LEVEL-1);
  346. // scaling for the mask texture to only allow the proper window
  347. // of tiles to show through
  348. parms[i] = -globalTileCorner[i] / (float)TILE_PER_LEVEL;
  349. }
  350. }
  351. image->Bind();
  352. for ( int x = 0 ; x < TILE_PER_LEVEL ; x++ ) {
  353. for ( int y = 0 ; y < TILE_PER_LEVEL ; y++ ) {
  354. int globalTile[2];
  355. globalTile[0] = globalTileCorner[0] + ( ( x - localTileOffset[0] ) & (TILE_PER_LEVEL-1) );
  356. globalTile[1] = globalTileCorner[1] + ( ( y - localTileOffset[1] ) & (TILE_PER_LEVEL-1) );
  357. UpdateTile( x, y, globalTile[0], globalTile[1] );
  358. }
  359. }
  360. }
  361. /*
  362. =====================
  363. Invalidate
  364. Forces all tiles to be regenerated
  365. =====================
  366. */
  367. void idTextureLevel::Invalidate() {
  368. for ( int x = 0 ; x < TILE_PER_LEVEL ; x++ ) {
  369. for ( int y = 0 ; y < TILE_PER_LEVEL ; y++ ) {
  370. tileMap[x][y].x =
  371. tileMap[x][y].y = -99999;
  372. }
  373. }
  374. }
  375. //===================================================================================================
  376. typedef struct _TargaHeader {
  377. unsigned char id_length, colormap_type, image_type;
  378. unsigned short colormap_index, colormap_length;
  379. unsigned char colormap_size;
  380. unsigned short x_origin, y_origin, width, height;
  381. unsigned char pixel_size, attributes;
  382. } TargaHeader;
  383. static byte ReadByte( idFile *f ) {
  384. byte b;
  385. f->Read( &b, 1 );
  386. return b;
  387. }
  388. static short ReadShort( idFile *f ) {
  389. byte b[2];
  390. f->Read( &b, 2 );
  391. return b[0] + ( b[1] << 8 );
  392. }
  393. /*
  394. ====================
  395. GenerateMegaMipMaps
  396. ====================
  397. */
  398. void idMegaTexture::GenerateMegaMipMaps( megaTextureHeader_t *header, idFile *outFile ) {
  399. outFile->Flush();
  400. // out fileSystem doesn't allow read / write access...
  401. idFile *inFile = fileSystem->OpenFileRead( outFile->GetName() );
  402. int tileOffset = 1;
  403. int width = header->tilesWide;
  404. int height = header->tilesHigh;
  405. int tileSize = header->tileSize * header->tileSize * 4;
  406. byte *oldBlock = (byte *)_alloca( tileSize );
  407. byte *newBlock = (byte *)_alloca( tileSize );
  408. while ( width > 1 || height > 1 ) {
  409. int newHeight = (height+1) >> 1;
  410. if ( newHeight < 1 ) {
  411. newHeight = 1;
  412. }
  413. int newWidth = (width+1) >> 1;
  414. if ( width < 1 ) {
  415. width = 1;
  416. }
  417. common->Printf( "generating %i x %i block mip level\n", newWidth, newHeight );
  418. int tileNum;
  419. for ( int y = 0 ; y < newHeight ; y++ ) {
  420. common->Printf( "row %i\n", y );
  421. session->UpdateScreen();
  422. for ( int x = 0 ; x < newWidth ; x++ ) {
  423. // mip map four original blocks down into a single new block
  424. for ( int yy = 0 ; yy < 2 ; yy++ ) {
  425. for ( int xx = 0 ; xx< 2 ; xx++ ) {
  426. int tx = x*2 + xx;
  427. int ty = y*2 + yy;
  428. if ( tx > width || ty > height ) {
  429. // off edge, zero fill
  430. memset( newBlock, 0, sizeof( newBlock ) );
  431. } else {
  432. tileNum = tileOffset + ty * width + tx;
  433. inFile->Seek( tileNum * tileSize, FS_SEEK_SET );
  434. inFile->Read( oldBlock, tileSize );
  435. }
  436. // mip map the new pixels
  437. for ( int yyy = 0 ; yyy < TILE_SIZE / 2 ; yyy++ ) {
  438. for ( int xxx = 0 ; xxx < TILE_SIZE / 2 ; xxx++ ) {
  439. byte *in = &oldBlock[ ( yyy * 2 * TILE_SIZE + xxx * 2 ) * 4 ];
  440. byte *out = &newBlock[ ( ( ( TILE_SIZE/2 * yy ) + yyy ) * TILE_SIZE + ( TILE_SIZE/2 * xx ) + xxx ) * 4 ];
  441. out[0] = ( in[0] + in[4] + in[0+TILE_SIZE*4] + in[4+TILE_SIZE*4] ) >> 2;
  442. out[1] = ( in[1] + in[5] + in[1+TILE_SIZE*4] + in[5+TILE_SIZE*4] ) >> 2;
  443. out[2] = ( in[2] + in[6] + in[2+TILE_SIZE*4] + in[6+TILE_SIZE*4] ) >> 2;
  444. out[3] = ( in[3] + in[7] + in[3+TILE_SIZE*4] + in[7+TILE_SIZE*4] ) >> 2;
  445. }
  446. }
  447. // write the block out
  448. tileNum = tileOffset + width * height + y * newWidth + x;
  449. outFile->Seek( tileNum * tileSize, FS_SEEK_SET );
  450. outFile->Write( newBlock, tileSize );
  451. }
  452. }
  453. }
  454. }
  455. tileOffset += width * height;
  456. width = newWidth;
  457. height = newHeight;
  458. }
  459. delete inFile;
  460. }
  461. /*
  462. ====================
  463. GenerateMegaPreview
  464. Make a 2k x 2k preview image for a mega texture that can be used in modeling programs
  465. ====================
  466. */
  467. void idMegaTexture::GenerateMegaPreview( const char *fileName ) {
  468. idFile *fileHandle = fileSystem->OpenFileRead( fileName );
  469. if ( !fileHandle ) {
  470. common->Printf( "idMegaTexture: failed to open %s\n", fileName );
  471. return;
  472. }
  473. idStr outName = fileName;
  474. outName.StripFileExtension();
  475. outName += "_preview.tga";
  476. common->Printf( "Creating %s.\n", outName.c_str() );
  477. megaTextureHeader_t header;
  478. fileHandle->Read( &header, sizeof( header ) );
  479. if ( header.tileSize < 64 || header.tilesWide < 1 || header.tilesHigh < 1 ) {
  480. common->Printf( "idMegaTexture: bad header on %s\n", fileName );
  481. return;
  482. }
  483. int tileSize = header.tileSize;
  484. int width = header.tilesWide;
  485. int height = header.tilesHigh;
  486. int tileOffset = 1;
  487. int tileBytes = tileSize * tileSize * 4;
  488. // find the level that fits
  489. while ( width * tileSize > 2048 || height * tileSize > 2048 ) {
  490. tileOffset += width * height;
  491. width >>= 1;
  492. if ( width < 1 ) {
  493. width = 1;
  494. }
  495. height >>= 1;
  496. if ( height < 1 ) {
  497. height = 1;
  498. }
  499. }
  500. byte *pic = (byte *)R_StaticAlloc( width * height * tileBytes );
  501. byte *oldBlock = (byte *)_alloca( tileBytes );
  502. for ( int y = 0 ; y < height ; y++ ) {
  503. for ( int x = 0 ; x < width ; x++ ) {
  504. int tileNum = tileOffset + y * width + x;
  505. fileHandle->Seek( tileNum * tileBytes, FS_SEEK_SET );
  506. fileHandle->Read( oldBlock, tileBytes );
  507. for ( int yy = 0 ; yy < tileSize ; yy++ ) {
  508. memcpy( pic + ( ( y * tileSize + yy ) * width * tileSize + x * tileSize ) * 4,
  509. oldBlock + yy * tileSize * 4, tileSize * 4 );
  510. }
  511. }
  512. }
  513. R_WriteTGA( outName.c_str(), pic, width * tileSize, height * tileSize, false );
  514. R_StaticFree( pic );
  515. delete fileHandle;
  516. }
  517. /*
  518. ====================
  519. MakeMegaTexture_f
  520. Incrementally load a giant tga file and process into the mega texture block format
  521. ====================
  522. */
  523. void idMegaTexture::MakeMegaTexture_f( const idCmdArgs &args ) {
  524. int columns, rows, fileSize, numBytes;
  525. byte *pixbuf;
  526. int row, column;
  527. TargaHeader targa_header;
  528. if ( args.Argc() != 2 ) {
  529. common->Printf( "USAGE: makeMegaTexture <filebase>\n" );
  530. return;
  531. }
  532. idStr name_s = "megaTextures/";
  533. name_s += args.Argv(1);
  534. name_s.StripFileExtension();
  535. name_s += ".tga";
  536. const char *name = name_s.c_str();
  537. //
  538. // open the file
  539. //
  540. common->Printf( "Opening %s.\n", name );
  541. fileSize = fileSystem->ReadFile( name, NULL, NULL );
  542. idFile *file = fileSystem->OpenFileRead( name );
  543. if ( !file ) {
  544. common->Printf( "Couldn't open %s\n", name );
  545. return;
  546. }
  547. targa_header.id_length = ReadByte( file );
  548. targa_header.colormap_type = ReadByte( file );
  549. targa_header.image_type = ReadByte( file );
  550. targa_header.colormap_index = ReadShort( file );
  551. targa_header.colormap_length = ReadShort( file );
  552. targa_header.colormap_size = ReadByte( file );
  553. targa_header.x_origin = ReadShort( file );
  554. targa_header.y_origin = ReadShort( file );
  555. targa_header.width = ReadShort( file );
  556. targa_header.height = ReadShort( file );
  557. targa_header.pixel_size = ReadByte( file );
  558. targa_header.attributes = ReadByte( file );
  559. if ( targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3 ) {
  560. common->Error( "LoadTGA( %s ): Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n", name );
  561. }
  562. if ( targa_header.colormap_type != 0 ) {
  563. common->Error( "LoadTGA( %s ): colormaps not supported\n", name );
  564. }
  565. if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 ) {
  566. common->Error( "LoadTGA( %s ): Only 32 or 24 bit images supported (no colormaps)\n", name );
  567. }
  568. if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) {
  569. numBytes = targa_header.width * targa_header.height * ( targa_header.pixel_size >> 3 );
  570. if ( numBytes > fileSize - 18 - targa_header.id_length ) {
  571. common->Error( "LoadTGA( %s ): incomplete file\n", name );
  572. }
  573. }
  574. columns = targa_header.width;
  575. rows = targa_header.height;
  576. // skip TARGA image comment
  577. if ( targa_header.id_length != 0 ) {
  578. file->Seek( targa_header.id_length, FS_SEEK_CUR );
  579. }
  580. megaTextureHeader_t mtHeader;
  581. mtHeader.tileSize = TILE_SIZE;
  582. mtHeader.tilesWide = RoundDownToPowerOfTwo( targa_header.width ) / TILE_SIZE;
  583. mtHeader.tilesHigh = RoundDownToPowerOfTwo( targa_header.height ) / TILE_SIZE;
  584. idStr outName = name;
  585. outName.StripFileExtension();
  586. outName += ".mega";
  587. common->Printf( "Writing %i x %i size %i tiles to %s.\n",
  588. mtHeader.tilesWide, mtHeader.tilesHigh, mtHeader.tileSize, outName.c_str() );
  589. // open the output megatexture file
  590. idFile *out = fileSystem->OpenFileWrite( outName.c_str() );
  591. out->Write( &mtHeader, sizeof( mtHeader ) );
  592. out->Seek( TILE_SIZE * TILE_SIZE * 4, FS_SEEK_SET );
  593. // we will process this one row of tiles at a time, since the entire thing
  594. // won't fit in memory
  595. byte *targa_rgba = (byte *)R_StaticAlloc( TILE_SIZE * targa_header.width * 4 );
  596. int blockRowsRemaining = mtHeader.tilesHigh;
  597. while ( blockRowsRemaining-- ) {
  598. common->Printf( "%i blockRowsRemaining\n", blockRowsRemaining );
  599. session->UpdateScreen();
  600. if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) {
  601. // Uncompressed RGB or gray scale image
  602. for( row = 0 ; row < TILE_SIZE ; row++ ) {
  603. pixbuf = targa_rgba + row*columns*4;
  604. for( column = 0; column < columns; column++) {
  605. unsigned char red,green,blue,alphabyte;
  606. switch( targa_header.pixel_size ) {
  607. case 8:
  608. blue = ReadByte( file );
  609. green = blue;
  610. red = blue;
  611. *pixbuf++ = red;
  612. *pixbuf++ = green;
  613. *pixbuf++ = blue;
  614. *pixbuf++ = 255;
  615. break;
  616. case 24:
  617. blue = ReadByte( file );
  618. green = ReadByte( file );
  619. red = ReadByte( file );
  620. *pixbuf++ = red;
  621. *pixbuf++ = green;
  622. *pixbuf++ = blue;
  623. *pixbuf++ = 255;
  624. break;
  625. case 32:
  626. blue = ReadByte( file );
  627. green = ReadByte( file );
  628. red = ReadByte( file );
  629. alphabyte = ReadByte( file );
  630. *pixbuf++ = red;
  631. *pixbuf++ = green;
  632. *pixbuf++ = blue;
  633. *pixbuf++ = alphabyte;
  634. break;
  635. default:
  636. common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size );
  637. break;
  638. }
  639. }
  640. }
  641. } else if ( targa_header.image_type == 10 ) { // Runlength encoded RGB images
  642. unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
  643. red = 0;
  644. green = 0;
  645. blue = 0;
  646. alphabyte = 0xff;
  647. for( row = 0 ; row < TILE_SIZE ; row++ ) {
  648. pixbuf = targa_rgba + row*columns*4;
  649. for( column = 0; column < columns; ) {
  650. packetHeader= ReadByte( file );
  651. packetSize = 1 + (packetHeader & 0x7f);
  652. if ( packetHeader & 0x80 ) { // run-length packet
  653. switch( targa_header.pixel_size ) {
  654. case 24:
  655. blue = ReadByte( file );
  656. green = ReadByte( file );
  657. red = ReadByte( file );
  658. alphabyte = 255;
  659. break;
  660. case 32:
  661. blue = ReadByte( file );
  662. green = ReadByte( file );
  663. red = ReadByte( file );
  664. alphabyte = ReadByte( file );
  665. break;
  666. default:
  667. common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size );
  668. break;
  669. }
  670. for( j = 0; j < packetSize; j++ ) {
  671. *pixbuf++=red;
  672. *pixbuf++=green;
  673. *pixbuf++=blue;
  674. *pixbuf++=alphabyte;
  675. column++;
  676. if ( column == columns ) { // run spans across rows
  677. common->Error( "TGA had RLE across columns, probably breaks block" );
  678. column = 0;
  679. if ( row > 0) {
  680. row--;
  681. }
  682. else {
  683. goto breakOut;
  684. }
  685. pixbuf = targa_rgba + row*columns*4;
  686. }
  687. }
  688. } else { // non run-length packet
  689. for( j = 0; j < packetSize; j++ ) {
  690. switch( targa_header.pixel_size ) {
  691. case 24:
  692. blue = ReadByte( file );
  693. green = ReadByte( file );
  694. red = ReadByte( file );
  695. *pixbuf++ = red;
  696. *pixbuf++ = green;
  697. *pixbuf++ = blue;
  698. *pixbuf++ = 255;
  699. break;
  700. case 32:
  701. blue = ReadByte( file );
  702. green = ReadByte( file );
  703. red = ReadByte( file );
  704. alphabyte = ReadByte( file );
  705. *pixbuf++ = red;
  706. *pixbuf++ = green;
  707. *pixbuf++ = blue;
  708. *pixbuf++ = alphabyte;
  709. break;
  710. default:
  711. common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size );
  712. break;
  713. }
  714. column++;
  715. if ( column == columns ) { // pixel packet run spans across rows
  716. column = 0;
  717. if ( row > 0 ) {
  718. row--;
  719. }
  720. else {
  721. goto breakOut;
  722. }
  723. pixbuf = targa_rgba + row*columns*4;
  724. }
  725. }
  726. }
  727. }
  728. breakOut: ;
  729. }
  730. }
  731. //
  732. // write out individual blocks from the full row block buffer
  733. //
  734. for ( int rowBlock = 0 ; rowBlock < mtHeader.tilesWide ; rowBlock++ ) {
  735. for ( int y = 0 ; y < TILE_SIZE ; y++ ) {
  736. out->Write( targa_rgba + ( y * targa_header.width + rowBlock * TILE_SIZE ) * 4, TILE_SIZE * 4 );
  737. }
  738. }
  739. }
  740. R_StaticFree( targa_rgba );
  741. GenerateMegaMipMaps( &mtHeader, out );
  742. delete out;
  743. delete file;
  744. GenerateMegaPreview( outName.c_str() );
  745. #if 0
  746. if ( (targa_header.attributes & (1<<5)) ) { // image flp bit
  747. R_VerticalFlip( *pic, *width, *height );
  748. }
  749. #endif
  750. }