main.c 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717
  1. #include <libc.h>
  2. #include <assert.h>
  3. #include <ctype.h>
  4. /*
  5. store sprites in an atlas, or as discrete textures?
  6. store audio as 16 bit for direct mmap access, or 4 bit adpcm with dynamic decompress?
  7. render without a depth buffer? NO: it wold defeat the deferred rendering ability
  8. optional script file with extra parameters
  9. youtube script
  10. --------------
  11. ipod music
  12. music icon
  13. landscape orientation
  14. skill level
  15. start game on any episode / map combination
  16. controls
  17. doors opening
  18. shooting
  19. damage indicators
  20. leave game at any time
  21. custom controls
  22. items in the world (ammo, health, treasure, weapons, keys)
  23. changing weapons
  24. secret doors
  25. finishing the level
  26. awards
  27. TASKS:
  28. Web page time check
  29. Data download
  30. Hardware mp3 playback, remove tremor
  31. Independent volume adjustment
  32. Broadcast packet tests
  33. Good console
  34. web media type for game launch and download
  35. Instrumented play data recording
  36. */
  37. #include <dirent.h>
  38. #include <OpenGL/gl.h> // for repeat and filter enums
  39. #include <OpenGL/glext.h>
  40. typedef unsigned char byte;
  41. #include "doomtool.h"
  42. const char *assetDirectory = "/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/assets";
  43. const char *outputFile = "/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/base.iPack";
  44. const char *parmFile = "/Volumes/Work/idMobileDepot/Archive/DoomClassicDepot/base.parm";
  45. pkHeader_t buildHeader;
  46. FILE *pakFile;
  47. #define MAX_IMAGE_TABLE 10000
  48. pkTextureData_t buildTextureTable[MAX_IMAGE_TABLE];
  49. #define MAX_WAV_TABLE 10000
  50. pkWavData_t buildWavTable[MAX_WAV_TABLE];
  51. #define MAX_RAW_TABLE 10000
  52. pkRawData_t buildRawTable[MAX_RAW_TABLE];
  53. // the doom extractor tool writes this out for alpha texels
  54. #define DOOM_ALPHA_TEXEL 0xff00ffff
  55. // the parm file is parsed for modifiers to specify image formats, etc
  56. #define MAX_ARGV 16
  57. typedef struct {
  58. int argc;
  59. char *argv[MAX_ARGV]; // argv[0] should be a filename local to the asset base
  60. } parmLine_t;
  61. #define MAX_PARM_LINES 10000
  62. parmLine_t parmLines[MAX_PARM_LINES];
  63. int numParmLines;
  64. void Error( const char *fmt, ... ) {
  65. va_list argptr;
  66. va_start( argptr, fmt );
  67. vprintf( fmt, argptr );
  68. exit( 1 );
  69. }
  70. int FileLength( FILE *f ) {
  71. fseek( f, 0, SEEK_END );
  72. int len = ftell( f );
  73. fseek( f, 0, SEEK_SET );
  74. return len;
  75. }
  76. //====================================================================
  77. const byte *iff_pdata;
  78. const byte *iff_end;
  79. const byte *iff_last_chunk;
  80. const byte *iff_data;
  81. int iff_chunk_len;
  82. short Wav_GetLittleShort( void )
  83. {
  84. short val = 0;
  85. val = *iff_pdata;
  86. val += (*(iff_pdata + 1) << 8);
  87. iff_pdata += 2;
  88. return val;
  89. }
  90. int Wav_GetLittleLong( void )
  91. {
  92. int val = 0;
  93. val = *iff_pdata;
  94. val += (*(iff_pdata + 1) << 8);
  95. val += (*(iff_pdata + 2) << 16);
  96. val += (*(iff_pdata + 3) << 24);
  97. iff_pdata += 4;
  98. return val;
  99. }
  100. void Wav_FindNextChunk( const char *name )
  101. {
  102. while( 1 )
  103. {
  104. iff_pdata = iff_last_chunk;
  105. if( iff_pdata >= iff_end )
  106. {
  107. // Didn't find the chunk
  108. iff_pdata = NULL;
  109. return;
  110. }
  111. iff_pdata += 4;
  112. iff_chunk_len = Wav_GetLittleLong();
  113. if( iff_chunk_len < 0 )
  114. {
  115. iff_pdata = NULL;
  116. return;
  117. }
  118. iff_pdata -= 8;
  119. iff_last_chunk = iff_pdata + 8 + ((iff_chunk_len + 1) & ~1);
  120. if( ! strncasecmp((const char *)iff_pdata, name, 4) )
  121. {
  122. return;
  123. }
  124. }
  125. }
  126. void Wav_FindChunk( const char *name )
  127. {
  128. iff_last_chunk = iff_data;
  129. Wav_FindNextChunk( name );
  130. }
  131. /*
  132. ========================
  133. AddWAV
  134. ========================
  135. */
  136. void AddWAV( const char *localName, const byte *data, int wavlength ) {
  137. assert( buildHeader.wavs.count < MAX_WAV_TABLE );
  138. pkWavData_t *wav = &buildWavTable[buildHeader.wavs.count++];
  139. iff_data = data;
  140. iff_end = data + wavlength;
  141. // look for RIFF signature
  142. Wav_FindChunk( "RIFF" );
  143. if( ! (iff_pdata && ! strncasecmp( (const char *)iff_pdata + 8, "WAVE", 4 ) ) ) {
  144. Error( "[LoadWavInfo]: Missing RIFF/WAVE chunks (%s)\n", localName );
  145. }
  146. // Get "fmt " chunk
  147. iff_data = iff_pdata + 12;
  148. Wav_FindChunk( "fmt " );
  149. if( ! iff_pdata ) {
  150. Error( "[LoadWavInfo]: Missing fmt chunk (%s)\n", localName );
  151. }
  152. iff_pdata += 8;
  153. if( Wav_GetLittleShort() != 1 ) {
  154. Error( "[LoadWavInfo]: Microsoft PCM format only (%s)\n", localName );
  155. }
  156. int channels = Wav_GetLittleShort();
  157. int sample_rate = Wav_GetLittleLong();
  158. iff_pdata += 4;
  159. // bytes per sample, which includes all channels
  160. // 16 bit stereo = 4 bytes per sample
  161. int sample_size = Wav_GetLittleShort();
  162. int channelBytes = sample_size / channels;
  163. if ( channelBytes != 1 && channelBytes != 2 ) {
  164. Error( "[LoadWavInfo]: only 8 and 16 bit WAV files supported (%s)\n", localName );
  165. }
  166. iff_pdata += 2;
  167. // Find data chunk
  168. Wav_FindChunk( "data" );
  169. if( ! iff_pdata ) {
  170. Error( "[LoadWavInfo]: missing 'data' chunk (%s)\n", localName );
  171. }
  172. iff_pdata += 4;
  173. int numSamples = Wav_GetLittleLong() / sample_size;
  174. if( numSamples <= 0 ) {
  175. Error( "[LoadWavInfo]: file with 0 samples (%s)\n", localName );
  176. }
  177. // as of iphone OS 2.2.1, 8 bit samples cause audible pops at the beginning and end, so
  178. // convert them to 16 bit here
  179. const void *samples = data + (iff_pdata - data);
  180. #if 0
  181. if ( channelBytes == 1 ) {
  182. int numChannelSamples = numSamples * channels;
  183. channelBytes = 2;
  184. sample_size = channelBytes * channels;
  185. short *newSamples = alloca( numChannelSamples * sample_size );
  186. for ( int i = 0; i < numChannelSamples ; i++ ) {
  187. newSamples[i] = ((short)((const byte *)samples)[i] - 128) * 256;
  188. }
  189. samples = newSamples;
  190. }
  191. #endif
  192. // write out the raw data
  193. strcpy( wav->name.name, localName );
  194. wav->wavDataOfs = ftell( pakFile );
  195. fwrite( samples, numSamples, sample_size, pakFile );
  196. wav->wavChannels = channels;
  197. wav->wavChannelBytes = channelBytes;
  198. wav->wavRate = sample_rate;
  199. wav->wavNumSamples = numSamples;
  200. }
  201. /*
  202. ================================================================================================
  203. Bitmap Loading (.bmp)
  204. ================================================================================================
  205. */
  206. typedef struct {
  207. char id[2];
  208. unsigned int fileSize;
  209. unsigned int reserved0;
  210. unsigned int bitmapDataOffset;
  211. unsigned int bitmapHeaderSize;
  212. unsigned int width;
  213. unsigned int height;
  214. unsigned short planes;
  215. unsigned short bitsPerPixel;
  216. unsigned int compression;
  217. unsigned int bitmapDataSize;
  218. unsigned int hRes;
  219. unsigned int vRes;
  220. unsigned int colors;
  221. unsigned int importantColors;
  222. unsigned char palette[256][4];
  223. } BMPHeader_t;
  224. /*
  225. ========================
  226. LoadBMP
  227. ========================
  228. */
  229. static void LoadBMP( const char *name, byte **pic, int *width, int *height ) {
  230. int columns, rows, numPixels;
  231. byte *pixbuf;
  232. int row, column;
  233. byte *buf_p;
  234. byte *buffer;
  235. int length;
  236. BMPHeader_t bmpHeader;
  237. byte *bmpRGBA;
  238. *pic = NULL;
  239. //
  240. // load the file
  241. //
  242. FILE *f = fopen( name, "rb" );
  243. if ( !f ) {
  244. Error( "Can't open '%s'\n", name );
  245. }
  246. length = FileLength( f );
  247. buffer = malloc( length );
  248. fread( buffer, 1, length, f );
  249. fclose( f );
  250. buf_p = buffer;
  251. bmpHeader.id[0] = *buf_p++;
  252. bmpHeader.id[1] = *buf_p++;
  253. bmpHeader.fileSize = * ( int * ) buf_p;
  254. buf_p += 4;
  255. bmpHeader.reserved0 = * ( int * ) buf_p;
  256. buf_p += 4;
  257. bmpHeader.bitmapDataOffset = * ( int * ) buf_p;
  258. buf_p += 4;
  259. bmpHeader.bitmapHeaderSize = * ( int * ) buf_p;
  260. buf_p += 4;
  261. bmpHeader.width = * ( int * ) buf_p;
  262. buf_p += 4;
  263. bmpHeader.height = * ( int * ) buf_p;
  264. buf_p += 4;
  265. bmpHeader.planes = * ( short * ) buf_p;
  266. buf_p += 2;
  267. bmpHeader.bitsPerPixel = * ( short * ) buf_p;
  268. buf_p += 2;
  269. bmpHeader.compression = * ( int * ) buf_p;
  270. buf_p += 4;
  271. bmpHeader.bitmapDataSize = * ( int * ) buf_p;
  272. buf_p += 4;
  273. bmpHeader.hRes = * ( int * ) buf_p;
  274. buf_p += 4;
  275. bmpHeader.vRes = * ( int * ) buf_p;
  276. buf_p += 4;
  277. bmpHeader.colors = * ( int * ) buf_p;
  278. buf_p += 4;
  279. bmpHeader.importantColors = * ( int * ) buf_p;
  280. buf_p += 4;
  281. memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );
  282. if ( bmpHeader.bitsPerPixel == 8 ) {
  283. buf_p += 1024;
  284. }
  285. if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) {
  286. Error( "LoadBMP: only Windows-style BMP files supported (%s)\n", name );
  287. }
  288. if ( bmpHeader.fileSize != length ) {
  289. Error( "LoadBMP: header size does not match file size (%d vs. %d) (%s)\n", bmpHeader.fileSize, length, name );
  290. }
  291. if ( bmpHeader.compression != 0 ) {
  292. Error( "LoadBMP: only uncompressed BMP files supported (%s)\n", name );
  293. }
  294. if ( bmpHeader.bitsPerPixel < 8 ) {
  295. Error( "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name );
  296. }
  297. columns = bmpHeader.width;
  298. rows = bmpHeader.height;
  299. if ( rows < 0 ) {
  300. rows = -rows;
  301. }
  302. numPixels = columns * rows;
  303. if ( width ) {
  304. *width = columns;
  305. }
  306. if ( height ) {
  307. *height = rows;
  308. }
  309. bmpRGBA = (byte *)malloc( numPixels * 4 );
  310. *pic = bmpRGBA;
  311. byte *rowStart = buf_p;
  312. for ( row = rows-1; row >= 0; row-- ) {
  313. pixbuf = bmpRGBA + row*columns*4;
  314. buf_p = rowStart;
  315. for ( column = 0; column < columns; column++ ) {
  316. unsigned char red, green, blue, alpha;
  317. int palIndex;
  318. unsigned short shortPixel;
  319. switch ( bmpHeader.bitsPerPixel ) {
  320. case 8:
  321. palIndex = *buf_p++;
  322. *pixbuf++ = bmpHeader.palette[palIndex][0];
  323. *pixbuf++ = bmpHeader.palette[palIndex][1];
  324. *pixbuf++ = bmpHeader.palette[palIndex][2];
  325. *pixbuf++ = 0xff;
  326. break;
  327. case 16:
  328. shortPixel = * ( unsigned short * ) pixbuf;
  329. pixbuf += 2;
  330. *pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7;
  331. *pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2;
  332. *pixbuf++ = ( shortPixel & ( 31 ) ) << 3;
  333. *pixbuf++ = 0xff;
  334. break;
  335. case 24:
  336. blue = *buf_p++;
  337. green = *buf_p++;
  338. red = *buf_p++;
  339. *pixbuf++ = red;
  340. *pixbuf++ = green;
  341. *pixbuf++ = blue;
  342. *pixbuf++ = 255;
  343. break;
  344. case 32:
  345. blue = *buf_p++;
  346. green = *buf_p++;
  347. red = *buf_p++;
  348. alpha = *buf_p++;
  349. *pixbuf++ = red;
  350. *pixbuf++ = green;
  351. *pixbuf++ = blue;
  352. *pixbuf++ = alpha;
  353. break;
  354. default:
  355. Error( "LoadBMP: illegal pixel_size '%d' in file '%s'\n", bmpHeader.bitsPerPixel, name );
  356. break;
  357. }
  358. }
  359. // rows are always 32 bit aligned
  360. rowStart += ( ( buf_p - rowStart ) + 3 ) &~3;
  361. }
  362. free( buffer );
  363. }
  364. //=====================================================================================
  365. typedef struct TargaHeader_s {
  366. unsigned char id_length;
  367. unsigned char colormap_type;
  368. unsigned char image_type;
  369. unsigned short colormap_index;
  370. unsigned short colormap_length;
  371. unsigned char colormap_size;
  372. unsigned short x_origin;
  373. unsigned short y_origin;
  374. unsigned short width, height;
  375. unsigned char pixel_size;
  376. unsigned char attributes;
  377. } TargaHeaeder_t;
  378. static const int TGA_HEADER_SIZE = 18;
  379. /*
  380. ========================
  381. WriteTGA
  382. Write a TGA to a buffer.
  383. ========================
  384. */
  385. void WriteTGA( byte **bufferOut, size_t *bufferSizeOut, const byte *data, int width, int height,
  386. int sourceDepth, int flipVertical, int swapRGB ) {
  387. size_t i;
  388. int imgStart = TGA_HEADER_SIZE;
  389. assert( sourceDepth == 1 || sourceDepth == 3 || sourceDepth == 4 );
  390. size_t bufferSize = width * height * sourceDepth + TGA_HEADER_SIZE;
  391. *bufferSizeOut = bufferSize;
  392. byte *buffer = (byte*)malloc( bufferSize );
  393. *bufferOut = buffer;
  394. memset( buffer, 0, TGA_HEADER_SIZE );
  395. static const int TGA_IMAGETYPE_GREYSCALE = 3;
  396. static const int TGA_IMAGETYPE_RGB = 2;
  397. buffer[ 2 ] = sourceDepth == 1 ? TGA_IMAGETYPE_GREYSCALE : TGA_IMAGETYPE_RGB;
  398. buffer[ 12 ] = width & 255;
  399. buffer[ 13 ] = width >> 8;
  400. buffer[ 14 ] = height & 255;
  401. buffer[ 15 ] = height >> 8;
  402. buffer[ 16 ] = sourceDepth * 8; // pixel size
  403. if ( !flipVertical ) {
  404. buffer[ 17 ] = ( 1 << 5 ); // flip bit, for normal top to bottom raster order
  405. }
  406. if ( sourceDepth == 4 ) {
  407. if ( swapRGB ) {
  408. // swap rgb to bgr
  409. for ( i = imgStart ; i < bufferSize ; i += sourceDepth ) {
  410. buffer[ i ] = data[ i - imgStart + 2 ]; // blue
  411. buffer[ i + 1 ] = data[ i - imgStart + 1 ]; // green
  412. buffer[ i + 2 ] = data[ i - imgStart ]; // red
  413. buffer[ i + 3 ] = data[ i - imgStart + 3 ]; // alpha
  414. }
  415. } else {
  416. memcpy( buffer + imgStart, data, bufferSize - TGA_HEADER_SIZE );
  417. }
  418. } else if ( sourceDepth == 3 ) {
  419. if ( swapRGB ) {
  420. for ( i = imgStart ; i < bufferSize ; i += sourceDepth ) {
  421. buffer[ i ] = data[ i - imgStart + 2 ]; // blue
  422. buffer[ i + 1 ] = data[ i - imgStart + 1 ]; // green
  423. buffer[ i + 2 ] = data[ i - imgStart + 0 ]; // red
  424. }
  425. } else {
  426. for ( i = imgStart ; i < bufferSize ; i += sourceDepth ) {
  427. buffer[ i ] = data[ i - imgStart ]; // blue
  428. buffer[ i + 1 ] = data[ i - imgStart + 1 ]; // green
  429. buffer[ i + 2 ] = data[ i - imgStart + 2 ]; // red
  430. }
  431. }
  432. } else if ( sourceDepth == 1 ) {
  433. memcpy( buffer + imgStart, data, bufferSize - TGA_HEADER_SIZE );
  434. }
  435. }
  436. void WriteTGAFile( const char *filename, const byte *pic, int w, int h ) {
  437. byte *buf;
  438. size_t bufLen;
  439. WriteTGA( &buf, &bufLen, pic, w, h, 4, 0, 0 );
  440. FILE * f = fopen( filename, "wb" );
  441. assert( f );
  442. fwrite( buf, bufLen, 1, f );
  443. fclose( f );
  444. free( buf );
  445. }
  446. /*
  447. ========================
  448. LoadTGAFromBuffer
  449. Load a TGA from a buffer containing a TGA file.
  450. ========================
  451. */
  452. int LoadTGAFromBuffer( const char *name, const unsigned char *buffer, const int bufferSize,
  453. unsigned char **pic, int *width, int *height ) {
  454. int columns, rows, numPixels;
  455. size_t numBytes;
  456. unsigned char *pixbuf;
  457. int row, column;
  458. const unsigned char *buf_p;
  459. struct TargaHeader_s targa_header;
  460. unsigned char *targa_rgba;
  461. *pic = NULL;
  462. buf_p = buffer;
  463. targa_header.id_length = *buf_p++;
  464. targa_header.colormap_type = *buf_p++;
  465. targa_header.image_type = *buf_p++;
  466. targa_header.colormap_index = *(short *)buf_p;
  467. buf_p += 2;
  468. targa_header.colormap_length = *(short *)buf_p;
  469. buf_p += 2;
  470. targa_header.colormap_size = *buf_p++;
  471. targa_header.x_origin = *(short *)buf_p;
  472. buf_p += 2;
  473. targa_header.y_origin = *(short *)buf_p;
  474. buf_p += 2;
  475. targa_header.width = *(short *)buf_p;
  476. buf_p += 2;
  477. targa_header.height = *(short *)buf_p;
  478. buf_p += 2;
  479. targa_header.pixel_size = *buf_p++;
  480. targa_header.attributes = *buf_p++;
  481. if ( targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3 ) {
  482. printf( "LoadTGA( %s ): Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported", name );
  483. return 0;
  484. }
  485. if ( targa_header.colormap_type != 0 ) {
  486. printf( "LoadTGA( %s ): colormaps not supported", name );
  487. return 0;
  488. }
  489. if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 ) {
  490. printf( "LoadTGA( %s ): Only 32 or 24 bit images supported (no colormaps)", name );
  491. return 0;
  492. }
  493. if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) {
  494. numBytes = targa_header.width * targa_header.height * ( targa_header.pixel_size >> 3 );
  495. if ( numBytes > bufferSize - TGA_HEADER_SIZE - targa_header.id_length ) {
  496. printf( "LoadTGA( %s ): incomplete file", name );
  497. return 0;
  498. }
  499. }
  500. columns = targa_header.width;
  501. rows = targa_header.height;
  502. numPixels = columns * rows;
  503. if ( width ) {
  504. *width = columns;
  505. }
  506. if ( height ) {
  507. *height = rows;
  508. }
  509. targa_rgba = (unsigned char *)malloc( numPixels*4 );
  510. *pic = targa_rgba;
  511. if ( targa_header.id_length != 0 ) {
  512. buf_p += targa_header.id_length; // skip TARGA image comment
  513. }
  514. if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) {
  515. unsigned char red,green,blue,alphabyte;
  516. switch( targa_header.pixel_size ) {
  517. case 8:
  518. // Uncompressed gray scale image
  519. for( row = rows - 1; row >= 0; row-- ) {
  520. pixbuf = targa_rgba + row*columns*4;
  521. for( column = 0; column < columns; column++ ) {
  522. blue = *buf_p++;
  523. green = blue;
  524. red = blue;
  525. *pixbuf++ = red;
  526. *pixbuf++ = green;
  527. *pixbuf++ = blue;
  528. *pixbuf++ = 255;
  529. }
  530. }
  531. break;
  532. case 24:
  533. // Uncompressed RGB image
  534. for( row = rows - 1; row >= 0; row-- ) {
  535. pixbuf = targa_rgba + row*columns*4;
  536. for( column = 0; column < columns; column++ ) {
  537. blue = *buf_p++;
  538. green = *buf_p++;
  539. red = *buf_p++;
  540. *pixbuf++ = red;
  541. *pixbuf++ = green;
  542. *pixbuf++ = blue;
  543. *pixbuf++ = 255;
  544. }
  545. }
  546. break;
  547. case 32:
  548. // Uncompressed RGBA image
  549. for( row = rows - 1; row >= 0; row-- ) {
  550. pixbuf = targa_rgba + row*columns*4;
  551. for( column = 0; column < columns; column++ ) {
  552. blue = *buf_p++;
  553. green = *buf_p++;
  554. red = *buf_p++;
  555. alphabyte = *buf_p++;
  556. *pixbuf++ = red;
  557. *pixbuf++ = green;
  558. *pixbuf++ = blue;
  559. *pixbuf++ = alphabyte;
  560. }
  561. }
  562. break;
  563. default:
  564. printf( "LoadTGA( %s ): illegal pixel_size '%d'", name, targa_header.pixel_size );
  565. free( *pic );
  566. *pic = NULL;
  567. return 0;
  568. }
  569. }
  570. else if ( targa_header.image_type == 10 ) { // Runlength encoded RGB images
  571. unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
  572. red = 0;
  573. green = 0;
  574. blue = 0;
  575. alphabyte = 0xff;
  576. for( row = rows - 1; row >= 0; row-- ) {
  577. pixbuf = targa_rgba + row*columns*4;
  578. for( column = 0; column < columns; ) {
  579. packetHeader= *buf_p++;
  580. packetSize = 1 + (packetHeader & 0x7f);
  581. if ( packetHeader & 0x80 ) { // run-length packet
  582. switch( targa_header.pixel_size ) {
  583. case 24:
  584. blue = *buf_p++;
  585. green = *buf_p++;
  586. red = *buf_p++;
  587. alphabyte = 255;
  588. break;
  589. case 32:
  590. blue = *buf_p++;
  591. green = *buf_p++;
  592. red = *buf_p++;
  593. alphabyte = *buf_p++;
  594. break;
  595. default:
  596. printf( "LoadTGA( %s ): illegal pixel_size '%d'", name, targa_header.pixel_size );
  597. free( *pic );
  598. *pic = NULL;
  599. return 0;
  600. }
  601. for( j = 0; j < packetSize; j++ ) {
  602. *pixbuf++=red;
  603. *pixbuf++=green;
  604. *pixbuf++=blue;
  605. *pixbuf++=alphabyte;
  606. column++;
  607. if ( column == columns ) { // run spans across rows
  608. column = 0;
  609. if ( row > 0) {
  610. row--;
  611. }
  612. else {
  613. goto breakOut;
  614. }
  615. pixbuf = targa_rgba + row*columns*4;
  616. }
  617. }
  618. } else { // non run-length packet
  619. for( j = 0; j < packetSize; j++ ) {
  620. switch( targa_header.pixel_size ) {
  621. case 24:
  622. blue = *buf_p++;
  623. green = *buf_p++;
  624. red = *buf_p++;
  625. *pixbuf++ = red;
  626. *pixbuf++ = green;
  627. *pixbuf++ = blue;
  628. *pixbuf++ = 255;
  629. break;
  630. case 32:
  631. blue = *buf_p++;
  632. green = *buf_p++;
  633. red = *buf_p++;
  634. alphabyte = *buf_p++;
  635. *pixbuf++ = red;
  636. *pixbuf++ = green;
  637. *pixbuf++ = blue;
  638. *pixbuf++ = alphabyte;
  639. break;
  640. default:
  641. printf( "LoadTGA( %s ): illegal pixel_size '%d'", name, targa_header.pixel_size );
  642. free( *pic );
  643. *pic = NULL;
  644. return 0;
  645. }
  646. column++;
  647. if ( column == columns ) { // pixel packet run spans across rows
  648. column = 0;
  649. if ( row > 0 ) {
  650. row--;
  651. }
  652. else {
  653. goto breakOut;
  654. }
  655. pixbuf = targa_rgba + row*columns*4;
  656. }
  657. }
  658. }
  659. }
  660. breakOut: ;
  661. }
  662. }
  663. if ( (targa_header.attributes & (1<<5)) ) { // image flp bit
  664. byte *temp = malloc( *width * *height * 4 );
  665. memcpy( temp, *pic, *width * *height * 4 );
  666. for ( int y = 0 ; y < *height ; y++ ) {
  667. memcpy( *pic + y * *width * 4, temp + (*height-1-y) * *width * 4, *width * 4 );
  668. }
  669. free( temp );
  670. }
  671. return 1;
  672. }
  673. /*
  674. ========================
  675. LoadTGA
  676. Load TGA directly from a file.
  677. ========================
  678. */
  679. int LoadTGA( const char *name, unsigned char **pic, int *width, int *height ) {
  680. int len;
  681. unsigned char *buf;
  682. int ret;
  683. FILE *f = fopen( name, "rb" );
  684. if ( !f ) {
  685. return 0;
  686. }
  687. len = FileLength( f );
  688. buf = malloc( len );
  689. fread( buf, 1, len, f );
  690. fclose( f );
  691. ret = LoadTGAFromBuffer( name, buf, len, pic, width, height );
  692. free( buf );
  693. return ret;
  694. }
  695. void OutlineImage( unsigned char *rgba, int width, int height ) {
  696. unsigned char *data_p;
  697. unsigned char *copy_p;
  698. unsigned char *copy = (unsigned char *)alloca( width * height * 4 );
  699. int x, y;
  700. memcpy( copy, rgba, width * height * 4 );
  701. data_p = rgba;
  702. copy_p = copy;
  703. for ( y = 0 ; y < height ; y++ ) {
  704. for ( x = 0 ; x < width ; x++, data_p+=4, copy_p+=4 ) {
  705. if ( data_p[3] != 0 ) {
  706. continue;
  707. }
  708. if ( x < width-1 && copy_p[7] != 0 ) {
  709. *(int *)data_p = ((int *)copy_p)[1];
  710. } else if ( x > 0 && copy_p[-1] != 0 ) {
  711. *(int *)data_p = ((int *)copy_p)[-1];
  712. } else if ( y < height-1 && copy_p[width*4+3] != 0 ) {
  713. *(int *)data_p = ((int *)copy_p)[width];
  714. } else if ( y > 0 && copy_p[-width*4+3] != 0 ) {
  715. *(int *)data_p = ((int *)copy_p)[-width];
  716. }
  717. data_p[3] = 1;
  718. }
  719. }
  720. }
  721. int RowClear( unsigned char *rgba, int w, int h, int y ) {
  722. int x;
  723. for ( x = 0 ; x < w ; x++ ) {
  724. if ( rgba[(y*w+x)*4+3] != 0 ) {
  725. return 0;
  726. }
  727. }
  728. return 1;
  729. }
  730. int NextPowerOfTwo( int n ) {
  731. int p = 1;
  732. while ( p < n ) {
  733. p <<= 1;
  734. }
  735. return p;
  736. }
  737. /*
  738. ========================
  739. AddTGA
  740. ========================
  741. */
  742. void AddTGA( const char *localName, const byte *data, int dataLen ) {
  743. assert( buildHeader.textures.count < MAX_IMAGE_TABLE );
  744. pkTextureData_t *image = &buildTextureTable[buildHeader.textures.count++];
  745. strcpy( image->name.name, localName );
  746. image->picDataOfs = ftell( pakFile );
  747. // load it
  748. unsigned char *pic;
  749. int width, height;
  750. if ( !LoadTGAFromBuffer( localName, data, dataLen, &pic, &width, &height ) ) {
  751. Error( "failed.\n" );
  752. }
  753. // scan for alpha
  754. int hasAlpha = 0;
  755. for ( int i = 0 ; i < width*height ; i++ ) {
  756. if ( pic[i*4+3] != 255 ) {
  757. hasAlpha = 1;
  758. break;
  759. }
  760. }
  761. // default image format
  762. image->format = TF_5551;
  763. // scan the parmLines for this filename
  764. for ( int i = 0 ; i < numParmLines ; i++ ) {
  765. if ( !strcasecmp( parmLines[i].argv[0], localName ) ) {
  766. for ( int j = 1 ; j < parmLines[i].argc ; j++ ) {
  767. if ( !strcmp( parmLines[i].argv[j], "5551" ) ) {
  768. image->format = TF_5551;
  769. } else if ( !strcmp( parmLines[i].argv[j], "4444" ) ) {
  770. image->format = TF_4444;
  771. } else if ( !strcmp( parmLines[i].argv[j], "565" ) ) {
  772. image->format = TF_565;
  773. } else if ( !strcmp( parmLines[i].argv[j], "8888" ) ) {
  774. image->format = TF_8888;
  775. } else if ( !strcmp( parmLines[i].argv[j], "LA" ) ) {
  776. image->format = TF_LA;
  777. } else if ( !strcmp( parmLines[i].argv[j], "PVR4" ) ) {
  778. if ( hasAlpha ) {
  779. image->format = TF_PVR4;
  780. } else {
  781. image->format = TF_PVR4A;
  782. }
  783. } else if ( !strcmp( parmLines[i].argv[j], "PVR2" ) ) {
  784. if ( hasAlpha ) {
  785. image->format = TF_PVR2;
  786. } else {
  787. image->format = TF_PVR2A;
  788. }
  789. } else {
  790. printf( "bad parm '%s'\n", parmLines[i].argv[j] );
  791. }
  792. }
  793. break;
  794. }
  795. }
  796. // set this true if we need to write a new tga out for compression
  797. // because we modified it in some way from the original (make power of 2, sprite outline, etc)
  798. int imageModified = 0;
  799. // make sure it is a power of two
  800. int potW = NextPowerOfTwo( width );
  801. int potH = NextPowerOfTwo( height );
  802. // the texturetool compressor only supports square textures as of iphone OS 2.2.1
  803. // Not sure if that is a hardware limit or just software. This throws away
  804. // some of the space savings, but it is still a speed savings to use.
  805. if ( image->format == TF_PVR4 || image->format == TF_PVR2 ) {
  806. if ( potW > potH ) {
  807. potH = potW;
  808. }
  809. if ( potH > potW ) {
  810. potW = potH;
  811. }
  812. }
  813. if ( potW > width || potH > height ) {
  814. printf( "Insetting %i x %i image in %i x %i block\n", width, height, potW, potH );
  815. unsigned char *newPic = (unsigned char *)malloc( potW * potH * 4 );
  816. // replicating the last row or column might be better
  817. if ( hasAlpha ) {
  818. memset( newPic, 0, potW * potH * 4 );
  819. } else {
  820. memset( newPic, 255, potW * potH * 4 );
  821. }
  822. for ( int y = 0 ; y < height ; y++ ) {
  823. memcpy( newPic + y * potW * 4, pic + y * width * 4, width * 4 );
  824. }
  825. free( pic );
  826. pic = newPic;
  827. imageModified = 1;
  828. }
  829. image->srcWidth = width;
  830. image->srcHeight = height;
  831. image->uploadWidth = potW;
  832. image->uploadHeight = potH;
  833. image->wrapS = GL_REPEAT;
  834. image->wrapT = GL_REPEAT;
  835. image->minFilter = GL_LINEAR_MIPMAP_NEAREST;
  836. image->magFilter = GL_LINEAR;
  837. image->aniso = 1;
  838. image->numLevels = 0;
  839. image->maxS = (float)image->srcWidth / image->uploadWidth;
  840. image->maxT = (float)image->srcHeight / image->uploadHeight;
  841. int w = image->uploadWidth;
  842. int h = image->uploadHeight;
  843. // determine the number of mip levels. We can't just count as
  844. // we create them, because the PVRTC texturetool creates them
  845. // all in one run
  846. int max = w > h ? w : h;
  847. while ( max >= 1 ) {
  848. image->numLevels++;
  849. max >>= 1;
  850. }
  851. // checkerboard debug tool for testing texel centers
  852. int checker = 0;
  853. if ( checker ) {
  854. for ( int y = 0 ; y < height ; y++ ) {
  855. for ( int x = 0 ; x < width ; x++ ) {
  856. if ( (x^y)&1 ) {
  857. *((int *)pic+y*potW+x) = -1;
  858. } else {
  859. *((int *)pic+y*potW+x) = 0;
  860. }
  861. }
  862. }
  863. imageModified = 1;
  864. }
  865. // sprite image outlining to avoid bilinear filter halos
  866. int sprite = 0;
  867. if ( sprite ) {
  868. for ( int i = 0 ; i < 8 ; i++ ) {
  869. OutlineImage( pic, width, height );
  870. }
  871. for ( int i = 0 ; i < width*height ; i++ ) {
  872. if ( pic[i*4+3] == 1 ) {
  873. pic[i*4+3] = 0;
  874. }
  875. }
  876. imageModified = 1;
  877. }
  878. //-----------------------------------------
  879. // scan for bounding box of opaque texels
  880. //-----------------------------------------
  881. if ( !hasAlpha ) {
  882. image->numBounds = 0;
  883. } else {
  884. int x, y;
  885. // find the bounding boxes for more efficient drawing
  886. image->numBounds = 1;
  887. for ( y = 0 ; y < h ; y++ ) {
  888. if ( !RowClear( pic, w, h, y ) ) {
  889. // this row is needed
  890. image->bounds[0][0][1] = y;
  891. break;
  892. }
  893. }
  894. for ( y = h-1 ; y >= 0 ; y-- ) {
  895. if ( !RowClear( pic, w, h, y ) ) {
  896. // this row is needed
  897. image->bounds[0][1][1] = y;
  898. break;
  899. }
  900. }
  901. // if the middle row is clear, make two boxes
  902. // We could make a better test, but this catches the ones we care about...
  903. if ( image->bounds[0][0][1] < h/2 && image->bounds[0][1][1] > h / 2
  904. && RowClear( pic, w, h, h/2 ) ) {
  905. image->numBounds = 2;
  906. image->bounds[1][1][1] = image->bounds[0][1][1];
  907. for ( y = h/2-1 ; y >= 0 ; y-- ) {
  908. if ( !RowClear( pic, w, h, y ) ) {
  909. image->bounds[0][1][1] = y;
  910. break;
  911. }
  912. }
  913. for ( y = h/2+1 ; y < h ; y++ ) {
  914. if ( !RowClear( pic, w, h, y ) ) {
  915. image->bounds[1][0][1] = y;
  916. break;
  917. }
  918. }
  919. }
  920. for ( int b = 0 ; b < image->numBounds ; b++ ) {
  921. for ( x = 0 ; x < w ; x++ ) {
  922. for ( y = image->bounds[b][0][1] ; y <= image->bounds[b][1][1] ; y++ ) {
  923. if ( pic[(y*w+x)*4+3] != 0 ) {
  924. // this column is needed
  925. image->bounds[b][0][0] = x;
  926. break;
  927. }
  928. }
  929. if ( y <= image->bounds[b][1][1] ) {
  930. break;
  931. }
  932. }
  933. for ( x = w-1 ; x >= 0 ; x-- ) {
  934. for ( y = image->bounds[b][0][1] ; y <= image->bounds[b][1][1] ; y++ ) {
  935. if ( pic[(y*w+x)*4+3] != 0 ) {
  936. // this column is needed
  937. image->bounds[b][1][0] = x;
  938. break;
  939. }
  940. }
  941. if ( y <= image->bounds[b][1][1] ) {
  942. break;
  943. }
  944. }
  945. }
  946. }
  947. //-----------------------------------------
  948. // run texturetool to PVR compress and generate all mip levels
  949. // Arguably, we should do the sprite outlining on each mip level
  950. // independently, and PVR compress each layer seperately.
  951. //-----------------------------------------
  952. if ( image->format == TF_PVR4 || image->format == TF_PVR2
  953. || image->format == TF_PVR4A || image->format == TF_PVR2A ) {
  954. char tempTGAname[L_tmpnam];
  955. // write the modified image data out if necessary
  956. if ( imageModified ) {
  957. tmpnam( tempTGAname );
  958. WriteTGAFile( tempTGAname, pic, w, h );
  959. } else {
  960. sprintf( tempTGAname, "%s/%s", assetDirectory, localName );
  961. }
  962. // run the external compression tool
  963. // FIXME: use an explicit name and timestamp check
  964. char tempPVRname[L_tmpnam];
  965. tmpnam( tempPVRname );
  966. char cmd[1024];
  967. sprintf( cmd, "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/texturetool -m -e PVRTC %s -f Raw -o %s %s",
  968. ( image->format == TF_PVR2 || image->format == TF_PVR2A ) ? "--bits-per-pixel-2" : "--bits-per-pixel-4",
  969. tempPVRname, tempTGAname );
  970. printf( "%s\n", cmd );
  971. system( cmd );
  972. FILE *f = fopen( tempPVRname, "rb" );
  973. if ( !f ) {
  974. Error( "Can't open '%s'\n", tempPVRname );
  975. }
  976. int len = FileLength( f );
  977. unsigned char *raw = alloca( len );
  978. fread( raw, 1, len, f );
  979. fclose( f );
  980. // write to the pak file
  981. fwrite( raw, 1, len, pakFile );
  982. if ( imageModified ) {
  983. remove( tempTGAname );
  984. }
  985. remove( tempPVRname );
  986. return;
  987. }
  988. //-----------------------------------------
  989. // create mip maps and write out simple image formats
  990. //-----------------------------------------
  991. while ( 1 ) {
  992. byte *rgba_p = pic;
  993. // convert to target format
  994. switch ( image->format ) {
  995. case TF_8888:
  996. {
  997. int * processed = alloca( w * h * 4 );
  998. int * s_p = processed;
  999. for ( int i = 0 ; i < w*h ; i++, rgba_p+=4 ) {
  1000. int r = rgba_p[0];
  1001. int g = rgba_p[1];
  1002. int b = rgba_p[2];
  1003. int a = rgba_p[3];
  1004. *s_p++ = (b<<24) | (g<<16) | (r<<8) | a;
  1005. }
  1006. // write it out
  1007. fwrite( processed, w * h, 4, pakFile );
  1008. break;
  1009. }
  1010. case TF_LA:
  1011. {
  1012. byte * processed = alloca( w * h * 2 );
  1013. byte * s_p = processed;
  1014. for ( int i = 0 ; i < w*h ; i++, rgba_p+=4 ) {
  1015. int l = rgba_p[0];
  1016. int a = rgba_p[1]; // this should probably be [3], but Cass's font renderer saved it out as LA01
  1017. *s_p++ = l;
  1018. *s_p++ = a;
  1019. }
  1020. // write it out
  1021. fwrite( processed, w * h, 2, pakFile );
  1022. break;
  1023. }
  1024. case TF_5551:
  1025. {
  1026. short * processed = alloca( w * h * 2 );
  1027. short * s_p = processed;
  1028. for ( int i = 0 ; i < w*h ; i++, rgba_p+=4 ) {
  1029. int r = rgba_p[0];
  1030. int g = rgba_p[1];
  1031. int b = rgba_p[2];
  1032. int a = rgba_p[3];
  1033. *s_p++ = ((r>>3)<<11) | ((g>>3)<<6) | ((b>>3)<<1) | (a>>7);
  1034. }
  1035. // write it out
  1036. fwrite( processed, w * h, 2, pakFile );
  1037. break;
  1038. }
  1039. case TF_565:
  1040. {
  1041. short * processed = alloca( w * h * 2 );
  1042. short * s_p = processed;
  1043. for ( int i = 0 ; i < w*h ; i++, rgba_p+=4 ) {
  1044. int r = rgba_p[0];
  1045. int g = rgba_p[1];
  1046. int b = rgba_p[2];
  1047. *s_p++ = ((r>>3)<<11) | ((g>>2)<<5) | (b>>3);
  1048. }
  1049. // write it out
  1050. fwrite( processed, w * h, 2, pakFile );
  1051. break;
  1052. }
  1053. case TF_4444:
  1054. {
  1055. short * processed = alloca( w * h * 2 );
  1056. short * s_p = processed;
  1057. for ( int i = 0 ; i < w*h ; i++, rgba_p+=4 ) {
  1058. int r = rgba_p[0];
  1059. int g = rgba_p[1];
  1060. int b = rgba_p[2];
  1061. int a = rgba_p[3];
  1062. *s_p++ = ((r>>4)<<12) | ((g>>4)<<8) | ((b>>4)<<4) | (a>>4);
  1063. }
  1064. // write it out
  1065. fwrite( processed, w * h, 2, pakFile );
  1066. break;
  1067. }
  1068. default:
  1069. Error( "unimplemented format: %i\n", image->format );
  1070. }
  1071. if ( w == 1 && h == 1 ) {
  1072. break;
  1073. }
  1074. // mip map
  1075. w >>= 1;
  1076. if ( w == 0 ) {
  1077. w = 1;
  1078. }
  1079. h >>= 1;
  1080. if ( h == 0 ) {
  1081. h = 1;
  1082. }
  1083. byte *tempMip = alloca( w * h * 4 );
  1084. // FIXME: doesn't handle 2x1 and 1x2 cases properly...
  1085. for ( int y = 0 ; y < h ; y++ ) {
  1086. for ( int x = 0 ; x < w ; x++ ) {
  1087. for ( int c = 0 ; c < 4 ; c++ ) {
  1088. tempMip[(y*w+x)*4+c] = (
  1089. pic[((y*2+0)*w*2+(x*2+0))*4+c] +
  1090. pic[((y*2+0)*w*2+(x*2+1))*4+c] +
  1091. pic[((y*2+1)*w*2+(x*2+0))*4+c] +
  1092. pic[((y*2+1)*w*2+(x*2+1))*4+c] ) >> 2;
  1093. }
  1094. }
  1095. }
  1096. pic = tempMip;
  1097. }
  1098. }
  1099. /*
  1100. ========================
  1101. AddRAW
  1102. ========================
  1103. */
  1104. void AddRAW( const char *localName, const byte *data, int dataLen ) {
  1105. assert( buildHeader.raws.count < MAX_RAW_TABLE );
  1106. pkRawData_t *raw = &buildRawTable[buildHeader.raws.count++];
  1107. strcpy( raw->name.name, localName );
  1108. raw->rawDataOfs = ftell( pakFile );
  1109. raw->rawDataLen = dataLen;
  1110. fwrite( data, 1, dataLen, pakFile );
  1111. // always add a 0 after each raw file so text files can be assumed to be
  1112. // c-string terminated
  1113. byte zero = 0;
  1114. fwrite( &zero, 1, 1, pakFile );
  1115. }
  1116. /*
  1117. ========================
  1118. AddDirectoryToPak_r
  1119. ========================
  1120. */
  1121. void AddDirectoryToPak_r( const char *localDirName ) {
  1122. char fullDirName[MAXPATHLEN];
  1123. if ( localDirName[0] == '/' ) {
  1124. localDirName++;
  1125. }
  1126. sprintf( fullDirName, "%s/%s", assetDirectory, localDirName );
  1127. printf( "entering %s\n", fullDirName );
  1128. DIR *dir = opendir( fullDirName );
  1129. assert( dir );
  1130. while( 1 ) {
  1131. // make sure the file pointer is 16 byte aligned, since
  1132. // we will be referencing it with mmap. Alignment greater than
  1133. // 4 might be wasted on iPhone, but it won't be all that much space.
  1134. int ofs = ftell( pakFile );
  1135. if ( ofs & 15 ) {
  1136. byte pad[16];
  1137. memset( pad, 0, sizeof( pad ) );
  1138. fwrite( pad, 16 - ( ofs & 15 ), 1, pakFile );
  1139. }
  1140. // get the next file in the directory
  1141. struct dirent *file = readdir( dir );
  1142. if ( !file ) {
  1143. return;
  1144. }
  1145. char localFileName[MAXPATHLEN];
  1146. if ( localDirName[0] ) {
  1147. sprintf( localFileName, "%s/%s", localDirName, file->d_name );
  1148. } else {
  1149. sprintf( localFileName, "%s", file->d_name );
  1150. }
  1151. if ( file->d_name[0] == '.' ) {
  1152. // ignore . and .. and hidden files
  1153. continue;
  1154. }
  1155. if ( file->d_type == DT_DIR ) {
  1156. // recurse into another directory
  1157. AddDirectoryToPak_r( localFileName );
  1158. continue;
  1159. }
  1160. // make sure name length fits
  1161. assert( strlen( localFileName ) < MAX_PK_NAME - 1 );
  1162. // load the file
  1163. char fullFileName[MAXPATHLEN];
  1164. sprintf( fullFileName, "%s/%s", assetDirectory, localFileName );
  1165. FILE *f = fopen( fullFileName, "rb" );
  1166. if ( !f ) {
  1167. Error( "Can't open '%s'\n", localFileName );
  1168. }
  1169. int len = FileLength( f );
  1170. unsigned char *raw = malloc( len );
  1171. fread( raw, 1, len, f );
  1172. fclose( f );
  1173. printf( "%8i %s\n", len, localFileName );
  1174. if ( strstr( localFileName, ".tga" ) ) {
  1175. AddTGA( localFileName, raw, len );
  1176. } else if ( strstr( localFileName, ".wav" ) ) {
  1177. AddWAV( localFileName, raw, len );
  1178. } else {
  1179. AddRAW( localFileName, raw, len );
  1180. }
  1181. free( raw );
  1182. }
  1183. }
  1184. //======================================================================================
  1185. #define ATLAS_SIZE 1024
  1186. #define ATLAS_EMPTY_ALPHA 128
  1187. byte atlas[ATLAS_SIZE*ATLAS_SIZE*4];
  1188. int atlasNum = 0;
  1189. int FindSpotInAtlas( int w, int h, int *spotX, int *spotY ) {
  1190. int x = 0;
  1191. int y = 0;
  1192. int maxX = ATLAS_SIZE - w;
  1193. int maxY = ATLAS_SIZE - h;
  1194. while( 1 ) {
  1195. retry:
  1196. for ( int yy = 0 ; yy < h ; yy++ ) {
  1197. for ( int xx = 0 ; xx < w ; xx++ ) {
  1198. if ( atlas[((y+yy)*ATLAS_SIZE+x+xx)*4+3] != ATLAS_EMPTY_ALPHA ) {
  1199. // can't use this spot, skip ahead past this solid mark
  1200. x = x + xx + 1;
  1201. if ( x > maxX ) {
  1202. x = 0;
  1203. y++;
  1204. if ( y > maxY ) {
  1205. return 0;
  1206. }
  1207. }
  1208. goto retry;
  1209. }
  1210. }
  1211. }
  1212. *spotX = x;
  1213. *spotY = y;
  1214. return 1;
  1215. }
  1216. return 0;
  1217. }
  1218. void EmptyAtlas() {
  1219. // fill with alpha 128 to signify empty
  1220. memset( atlas, 0, sizeof( atlas ) );
  1221. for ( int i = 0 ; i < ATLAS_SIZE * ATLAS_SIZE ; i++ ) {
  1222. atlas[i*4+3] = ATLAS_EMPTY_ALPHA;
  1223. }
  1224. }
  1225. void ClearBlock( int x, int y, int w, int h ) {
  1226. // fill with black / alpha 0
  1227. for ( int yy = 0 ; yy < h ; yy++ ) {
  1228. memset( atlas + ((y+yy)*ATLAS_SIZE+x)*4, 0, w*4 );
  1229. }
  1230. }
  1231. void FinishAtlas() {
  1232. char filename[1024];
  1233. sprintf( filename, "%s/atlas%i.tga", assetDirectory, atlasNum );
  1234. printf( "Writing %s.\n", filename );
  1235. WriteTGAFile( filename, atlas, ATLAS_SIZE, ATLAS_SIZE );
  1236. // this atlas is complete, write it out
  1237. atlasNum++;
  1238. // clear it and retry the allocation
  1239. EmptyAtlas();
  1240. }
  1241. /*
  1242. ========================
  1243. AtlasDirectory
  1244. ========================
  1245. */
  1246. void AtlasDirectory( const char *fullDirName, const char *prefix ) {
  1247. printf( "atlasing %s* from %s\n", prefix, fullDirName );
  1248. DIR *dir = opendir( fullDirName );
  1249. assert( dir );
  1250. int totalSourceTexels = 0;
  1251. int totalSourceImages = 0;
  1252. int totalBorderedSourceTexels = 0;
  1253. int totalPotTexels = 0;
  1254. EmptyAtlas();
  1255. while( 1 ) {
  1256. // get the next file in the directory
  1257. struct dirent *file = readdir( dir );
  1258. if ( !file ) {
  1259. break;
  1260. }
  1261. if ( file->d_name[0] == '.' ) {
  1262. // ignore . and .. and hidden files
  1263. continue;
  1264. }
  1265. #if 0
  1266. if ( file->d_type == DT_DIR ) {
  1267. // recurse into another directory
  1268. AddDirectoryToPak_r( localFileName );
  1269. continue;
  1270. }
  1271. #endif
  1272. if ( !strstr( file->d_name, ".BMP" ) && !strstr( file->d_name, ".bmp" ) ) {
  1273. continue;
  1274. }
  1275. // only grab the specified images
  1276. if ( strncmp( file->d_name, prefix, strlen( prefix ) ) ) {
  1277. continue;
  1278. }
  1279. // load the image
  1280. char fullFileName[MAXPATHLEN];
  1281. sprintf( fullFileName, "%s/%s", fullDirName, file->d_name );
  1282. byte *pic;
  1283. int width, height;
  1284. LoadBMP( fullFileName, &pic, &width, &height );
  1285. // add a four pixel border around each sprite for mip map outlines
  1286. static const int OUTLINE_WIDTH = 4;
  1287. int widthInAtlas = width + 2*OUTLINE_WIDTH;
  1288. int heightInAtlas = height + 2*OUTLINE_WIDTH;
  1289. int ax, ay;
  1290. if ( !FindSpotInAtlas( widthInAtlas, heightInAtlas, &ax, &ay ) ) {
  1291. FinishAtlas();
  1292. if ( !FindSpotInAtlas( widthInAtlas, heightInAtlas, &ax, &ay ) ) {
  1293. Error( "Couldn't allocate %s: %i,%i in empty atlas", fullFileName, width, height );
  1294. }
  1295. }
  1296. printf( "%4i, %4i at %4i,%4i: %s\n", width, height, ax, ay, fullFileName );
  1297. totalSourceTexels += width * height;
  1298. totalSourceImages++;
  1299. totalBorderedSourceTexels += widthInAtlas * heightInAtlas;
  1300. totalPotTexels += NextPowerOfTwo( width ) * NextPowerOfTwo( height );
  1301. // clear the extended border area to fully transparent
  1302. ClearBlock( ax, ay, widthInAtlas, heightInAtlas );
  1303. // copy the actual image into the inset area past the added borders
  1304. // for Doom graphics, the color key alpha value is always the top left corner texel
  1305. ax += OUTLINE_WIDTH;
  1306. ay += OUTLINE_WIDTH;
  1307. for ( int y = 0 ; y < height ; y++ ) {
  1308. for ( int x = 0 ; x < width ; x++ ) {
  1309. int p = ((int *)pic)[y*width+x];
  1310. if ( p == DOOM_ALPHA_TEXEL ) {
  1311. ((int *)atlas)[ (ay+y)*ATLAS_SIZE+ax+x ] = 0;
  1312. } else {
  1313. ((int *)atlas)[ (ay+y)*ATLAS_SIZE+ax+x ] = p;
  1314. }
  1315. }
  1316. }
  1317. }
  1318. // process and write out the partially filled atlas
  1319. FinishAtlas();
  1320. printf ("%i soource images\n", totalSourceImages );
  1321. printf ("%i atlas images\n", atlasNum );
  1322. printf ("%6.1fk source texels\n", totalSourceTexels*0.001f );
  1323. printf ("%6.1fk bordered source texels\n", totalBorderedSourceTexels*0.001f );
  1324. printf ("%6.1fk atlas texels\n", atlasNum*ATLAS_SIZE*ATLAS_SIZE*0.001f );
  1325. printf ("%6.1fk power of two inset texels\n", totalPotTexels*0.001f );
  1326. }
  1327. /*
  1328. ==================
  1329. PK_HashName
  1330. ==================
  1331. */
  1332. int PK_HashName( const char *name, char canonical[MAX_PK_NAME] ) {
  1333. int o = 0;
  1334. int hash = 0;
  1335. do {
  1336. int c = name[o];
  1337. if ( c == 0 ) {
  1338. break;
  1339. }
  1340. // backslashes to forward slashes
  1341. if ( c == '\\' ) {
  1342. c = '/';
  1343. }
  1344. // to lowercase
  1345. c = tolower( c );
  1346. canonical[o++] = c;
  1347. hash = (hash << 5) - hash + c;
  1348. } while ( o < MAX_PK_NAME-1 );
  1349. canonical[o] = 0;
  1350. return hash;
  1351. }
  1352. /*
  1353. ========================
  1354. WriteType
  1355. ========================
  1356. */
  1357. void WriteType( FILE *pakFile, pkType_t *type, int structSize, pkName_t *table ) {
  1358. type->structSize = structSize;
  1359. type->tableOfs = ftell( pakFile );
  1360. // build hash chains for everything
  1361. for ( int i = 0 ; i < PK_HASH_CHAINS ; i++ ) {
  1362. type->hashChains[i] = -1;
  1363. }
  1364. for ( int i = 0 ; i < type->count ; i++ ) {
  1365. pkName_t *name = (pkName_t *)((unsigned char *)table + i * structSize );
  1366. char original[MAX_PK_NAME];
  1367. strcpy( original, name->name );
  1368. // make the name canonical and get the hash
  1369. name->nameHash = PK_HashName( original, name->name );
  1370. // add it to the hash chain
  1371. int chain = name->nameHash & (PK_HASH_CHAINS-1);
  1372. name->nextOnHashChain = type->hashChains[chain];
  1373. type->hashChains[chain] = i;
  1374. }
  1375. fwrite( table, type->count, type->structSize, pakFile );
  1376. }
  1377. /*
  1378. ========================
  1379. main
  1380. ========================
  1381. */
  1382. int main (int argc, const char * argv[]) {
  1383. int arg;
  1384. for ( arg = 1 ; arg < argc ; arg++ ) {
  1385. if ( argv[arg][0] != '-' ) {
  1386. break;
  1387. }
  1388. if ( !strcmp( argv[arg], "-i" ) ) {
  1389. assetDirectory = argv[arg+1];
  1390. arg++;
  1391. continue;
  1392. }
  1393. if ( !strcmp( argv[arg], "-o" ) ) {
  1394. outputFile = argv[arg+1];
  1395. arg++;
  1396. continue;
  1397. }
  1398. if ( !strcmp( argv[arg], "-p" ) ) {
  1399. parmFile = argv[arg+1];
  1400. arg++;
  1401. continue;
  1402. }
  1403. if ( !strcmp( argv[arg], "-?" ) ) {
  1404. Error( "doomtool [-i inputDirectory] [-o outputFile] [-p parmfile]\n" );
  1405. }
  1406. Error( "unknown option '%s'\n", argv[arg] );
  1407. }
  1408. //-----------------------------
  1409. // parse the parm file
  1410. //-----------------------------
  1411. FILE *f = fopen( parmFile, "rb" );
  1412. numParmLines = 0;
  1413. if ( f ) {
  1414. char line[1024];
  1415. while( fgets( line, sizeof( line ), f ) ) {
  1416. // remove trailing newline
  1417. if ( line[strlen(line)-1] == '\n' ) {
  1418. line[strlen(line)-1] = 0;
  1419. }
  1420. parmLine_t *pl = &parmLines[numParmLines];
  1421. // tokenize
  1422. char *inputString = line;
  1423. char *ap;
  1424. while( ap = strsep( &inputString, " \t" ) ) {
  1425. if ( *ap == '\0' ) {
  1426. continue;
  1427. }
  1428. pl->argv[pl->argc] = strdup( ap );
  1429. if ( ++pl->argc == MAX_ARGV ) {
  1430. break;
  1431. }
  1432. }
  1433. if ( pl->argc > 0 ) {
  1434. numParmLines++;
  1435. }
  1436. }
  1437. fclose( f );
  1438. }
  1439. // AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "" );
  1440. #if 0
  1441. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "BOS2" );
  1442. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "BOSS" );
  1443. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "BSPI" );
  1444. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "CPOS" );
  1445. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "CYBR" );
  1446. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "FAT" );
  1447. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "HEAD" );
  1448. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "PAIN" );
  1449. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "PLAY" );
  1450. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "POSS" );
  1451. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "SARG" );
  1452. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "SKEL" );
  1453. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "SKUL" );
  1454. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "SPID" );
  1455. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "SPOS" );
  1456. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "SSWV" );
  1457. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "TROO" );
  1458. AtlasDirectory( "/Users/johnc/DOOM2/SPRITES", "VILE" );
  1459. #endif
  1460. //-----------------------------
  1461. // start writing the outputFile
  1462. //-----------------------------
  1463. pakFile = fopen( outputFile, "wb" );
  1464. assert( pakFile );
  1465. // leave space for the header, which will be written at the end
  1466. fwrite( &buildHeader, 1, sizeof( buildHeader ), pakFile );
  1467. // recursively process everything under the asset directory
  1468. AddDirectoryToPak_r( "" );
  1469. // write out the tables
  1470. WriteType( pakFile, &buildHeader.textures, sizeof( pkTextureData_t ), &buildTextureTable[0].name );
  1471. WriteType( pakFile, &buildHeader.wavs, sizeof( pkWavData_t ), &buildWavTable[0].name );
  1472. WriteType( pakFile, &buildHeader.raws, sizeof( pkRawData_t ), &buildRawTable[0].name );
  1473. buildHeader.version = PKFILE_VERSION;
  1474. printf( "%s : %i bytes\n", outputFile, ftell( pakFile ) );
  1475. // go back and write the header
  1476. fseek( pakFile, 0, SEEK_SET );
  1477. fwrite( &buildHeader, 1, sizeof( buildHeader ), pakFile );
  1478. fclose( pakFile );
  1479. return 0;
  1480. }