ipak.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /*
  2. Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company.
  3. Copyright (C) 2009 Id Software, Inc.
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. */
  16. #include "../doomiphone.h"
  17. pkHeader_t *pkHeader;
  18. int pkSize;
  19. // images and wavs have writable state, so they need separate
  20. // structs that also point to the source in the pak file
  21. pkTexture_t *pkTextures;
  22. pkWav_t *pkWavs;
  23. void PK_LoadTexture( pkTexture_t *image );
  24. /*
  25. ==================
  26. PK_Init
  27. ==================
  28. */
  29. void PK_Init( const char *pakFileName ) {
  30. printf( "PK_Init( %s )\n", pakFileName );
  31. int fd = open( pakFileName, O_RDONLY );
  32. if ( fd == -1 ) {
  33. printf( "Couldn't open file\n" );
  34. assert( 0 );
  35. }
  36. struct stat s;
  37. fstat( fd, &s );
  38. pkSize = s.st_size;
  39. pkHeader = mmap( NULL, pkSize, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0 );
  40. // mmap keeps the file internally, we can close our descriptor
  41. close( fd );
  42. if ( (int)pkHeader == -1 ) {
  43. printf( "mmap failed: %s\n", strerror( errno ) );
  44. assert( 0 );
  45. }
  46. if ( pkHeader->version != PKFILE_VERSION ) {
  47. printf( "bad pak file version: 0x%x != 0x%x\n", pkHeader->version, PKFILE_VERSION );
  48. assert( 0 );
  49. }
  50. // build the local image table
  51. pkTextures = malloc( sizeof( pkTextures[0] ) * pkHeader->textures.count );
  52. memset( pkTextures, 0, sizeof( pkTextures[0] ) * pkHeader->textures.count );
  53. for ( int i = 0 ; i < pkHeader->textures.count ; i++ ) {
  54. pkTextures[i].textureData = (pkTextureData_t *)( (byte *)pkHeader + pkHeader->textures.tableOfs + i * pkHeader->textures.structSize );
  55. }
  56. // build the local wav table
  57. int startLoadingWavs = SysIphoneMicroseconds();
  58. pkWavs = malloc( sizeof( pkWavs[0] ) * pkHeader->wavs.count );
  59. memset( pkWavs, 0, sizeof( pkWavs[0] ) * pkHeader->wavs.count );
  60. for ( int i = 0 ; i < pkHeader->wavs.count ; i++ ) {
  61. pkWav_t *sfx = &pkWavs[i];
  62. sfx->wavData = (pkWavData_t *)( (byte *)pkHeader + pkHeader->wavs.tableOfs + i * pkHeader->wavs.structSize );
  63. // there is no harm in setting the OpenAl static buffer up for everything now
  64. alGenBuffers( 1, &sfx->alBufferNum );
  65. int alFormat;
  66. if ( sfx->wavData->wavChannels == 1 ) {
  67. if ( sfx->wavData->wavChannelBytes == 1 ) {
  68. alFormat = AL_FORMAT_MONO8;
  69. } else {
  70. alFormat = AL_FORMAT_MONO16;
  71. }
  72. } else {
  73. if ( sfx->wavData->wavChannelBytes == 1 ) {
  74. alFormat = AL_FORMAT_STEREO8;
  75. } else {
  76. alFormat = AL_FORMAT_STEREO16;
  77. }
  78. }
  79. alBufferData( sfx->alBufferNum, alFormat, (byte *)pkHeader + sfx->wavData->wavDataOfs
  80. , sfx->wavData->wavChannels*sfx->wavData->wavChannelBytes*sfx->wavData->wavNumSamples
  81. , sfx->wavData->wavRate );
  82. }
  83. int endLoadingWavs = SysIphoneMicroseconds();
  84. printf( "%i usec to load wavs\n", endLoadingWavs - startLoadingWavs );
  85. printf( "Mapped %i bytes of %s at 0x%p\n", pkSize, pakFileName, pkHeader );
  86. printf( "%4i textures\n", pkHeader->textures.count );
  87. printf( "%4i wavs\n", pkHeader->wavs.count );
  88. printf( "%4i raws\n", pkHeader->raws.count );
  89. #if 0
  90. // testing
  91. for ( int j = 0 ; j < 4 ; j++ ) {
  92. int startTime = Sys_Microseconds();
  93. int sum = 0;
  94. for ( int i = 0 ; i < pkSize ; i+=16 ) {
  95. sum += ((byte *)pkHeader)[i];
  96. }
  97. int endTime = Sys_Microseconds();
  98. printf( "%5.1f mb/s page-in speed (%i)\n", (float)pkSize / (endTime - startTime ), endTime - startTime );
  99. }
  100. for ( int i = 0 ; i < pkHeader->numTextures ; i++ ) {
  101. printf( "-------------------------\n" );
  102. for ( int j = 0 ; j < 8 ; j++ ) {
  103. pkTexture_t *tex = &pkTextures[i];
  104. int start = Sys_Microseconds();
  105. PK_LoadTexture( tex );
  106. int middle = Sys_Microseconds();
  107. PK_StretchTexture( tex, 0, 0, 0, 0 );
  108. int middle2 = Sys_Microseconds();
  109. PK_StretchTexture( tex, 0, 0, 0, 0 );
  110. int end = Sys_Microseconds();
  111. printf( "%i usec load, %i usec first draw, %i usec second draw\n",
  112. middle - start, middle2 - middle, end - middle2 );
  113. glDeleteTextures( 1, &tex->glTexNum );
  114. tex->glTexNum = 0;
  115. }
  116. }
  117. #endif
  118. }
  119. /*
  120. ==================
  121. PK_LoadTexture
  122. ==================
  123. */
  124. void PK_LoadTexture( pkTexture_t *tex ) {
  125. int startTime = SysIphoneMicroseconds();
  126. const pkTextureData_t *imd = tex->textureData;
  127. glGenTextures( 1, &tex->glTexNum );
  128. glBindTexture( GL_TEXTURE_2D, tex->glTexNum );
  129. // load the image directly from the mapped file
  130. typedef struct {
  131. int internalFormat;
  132. int externalFormat;
  133. int type;
  134. int bpp;
  135. } formatInfo_t;
  136. static formatInfo_t formatInfo[9] = {
  137. { GL_RGB , GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 16 },
  138. { GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 16 },
  139. { GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 16 },
  140. { GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE, 32 },
  141. { GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 16 },
  142. { GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, 0, 0, 4 },
  143. { GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, 0, 0, 4 },
  144. { GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, 0, 0, 2 },
  145. { GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, 0, 0, 2 },
  146. };
  147. assert( imd->format < 9 );
  148. formatInfo_t *fi = &formatInfo[imd->format];
  149. unsigned char *s = (byte *)pkHeader + imd->picDataOfs;
  150. int w = imd->uploadWidth;
  151. int h = imd->uploadHeight;
  152. // upload each mip level
  153. int l = 0;
  154. int totalSize = 0;
  155. while( 1 ) {
  156. int size = (w*h*fi->bpp)/8;
  157. if ( fi->type == 0 ) {
  158. if ( size < 32 ) {
  159. // minimum PVRTC size
  160. size = 32;
  161. }
  162. glCompressedTexImage2D( GL_TEXTURE_2D, l, fi->internalFormat, w, h, 0,
  163. size, s );
  164. } else {
  165. glTexImage2D( GL_TEXTURE_2D, l, fi->internalFormat, w, h, 0,
  166. fi->externalFormat, fi->type, s );
  167. }
  168. GLCheckError( "texture upload" );
  169. totalSize += size;
  170. if ( ++l == imd->numLevels ) {
  171. break;
  172. }
  173. if ( w == 1 && h == 1 ) {
  174. break;
  175. }
  176. s += size;
  177. w >>= 1;
  178. if ( w == 0 ) {
  179. w = 1;
  180. }
  181. h >>= 1;
  182. if ( h == 0 ) {
  183. h = 1;
  184. }
  185. }
  186. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, imd->minFilter );
  187. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, imd->magFilter );
  188. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, imd->wrapS );
  189. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, imd->wrapT );
  190. glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.0f );
  191. int endTime = SysIphoneMicroseconds();
  192. printf( "%5.1f mb/s TexImage for %s\n", (float)totalSize /
  193. ( endTime - startTime ), imd->name.name );
  194. }
  195. /*
  196. ==================
  197. PK_FindTexture
  198. Fully creates the gl texture before returning.
  199. ==================
  200. */
  201. pkTexture_t *PK_FindTexture( const char *imageName ) {
  202. int index;
  203. pkTexture_t *texData = (pkTexture_t *)PK_FindType( imageName, &pkHeader->textures, &index );
  204. if ( !texData ) {
  205. return NULL;
  206. }
  207. pkTexture_t *tex = pkTextures + index;
  208. if ( tex->glTexNum == 0 ) {
  209. PK_LoadTexture( tex );
  210. }
  211. return tex;
  212. }
  213. /*
  214. ==================
  215. PK_FindWav
  216. ==================
  217. */
  218. pkWav_t *PK_FindWav( const char *soundName ) {
  219. int index;
  220. pkWavData_t *wavData = (pkWavData_t *)PK_FindType( soundName, &pkHeader->wavs, &index );
  221. if ( !wavData ) {
  222. return NULL;
  223. }
  224. pkWav_t *wav = pkWavs + index;
  225. // create the OpenAL buffer
  226. return wav;
  227. }
  228. /*
  229. ==================
  230. PK_FindRaw
  231. ==================
  232. */
  233. const byte *PK_FindRaw( const char *rawName, int *len ) {
  234. pkRawData_t *raw = (pkRawData_t *)PK_FindType( rawName, &pkHeader->raws, NULL );
  235. if ( !raw ) {
  236. if ( len ) {
  237. *len = -1;
  238. }
  239. return NULL;
  240. }
  241. if ( len ) {
  242. *len = raw->rawDataLen;
  243. }
  244. return (byte *)pkHeader + raw->rawDataOfs;
  245. }
  246. /*
  247. ==================
  248. PK_HashName
  249. ==================
  250. */
  251. int PK_HashName( const char *name, char canonical[MAX_PK_NAME] ) {
  252. int o = 0;
  253. int hash = 0;
  254. do {
  255. int c = name[o];
  256. if ( c == 0 ) {
  257. break;
  258. }
  259. // backslashes to forward slashes
  260. if ( c == '\\' ) {
  261. c = '/';
  262. }
  263. // to lowercase
  264. c = tolower( c );
  265. canonical[o++] = c;
  266. hash = (hash << 5) - hash + c;
  267. } while ( o < MAX_PK_NAME-1 );
  268. canonical[o] = 0;
  269. return hash;
  270. }
  271. /*
  272. ==================
  273. PK_FindType
  274. ==================
  275. */
  276. const pkName_t *PK_FindType( const char *rawName, const pkType_t *type, int *indexOutput ) {
  277. char canonicalName[MAX_PK_NAME];
  278. int hash = PK_HashName( rawName, canonicalName );
  279. int hashChain = hash & (PK_HASH_CHAINS-1);
  280. int index = type->hashChains[hashChain];
  281. while ( index != -1 ) {
  282. assert( index >= 0 && index < type->count );
  283. const pkName_t *name = (pkName_t *)((byte *)pkHeader + type->tableOfs + index * type->structSize );
  284. if ( name->nameHash == hash && !strcmp( canonicalName, name->name ) ) {
  285. // this is it
  286. if ( indexOutput ) {
  287. *indexOutput = index;
  288. }
  289. return name;
  290. }
  291. index = name->nextOnHashChain;
  292. }
  293. // not found
  294. if ( indexOutput ) {
  295. *indexOutput = -1;
  296. }
  297. return NULL;
  298. }
  299. /*
  300. ==================
  301. PK_BindTexture
  302. ==================
  303. */
  304. void PK_BindTexture( pkTexture_t *tex ) {
  305. assert( tex->glTexNum );
  306. glBindTexture( GL_TEXTURE_2D, tex->glTexNum );
  307. }
  308. /*
  309. ==================
  310. PK_DrawTexture
  311. ==================
  312. */
  313. void PK_DrawTexture( pkTexture_t *tex, int x, int y ) {
  314. PK_BindTexture( tex );
  315. int w = tex->textureData->srcWidth;
  316. int h = tex->textureData->srcHeight;
  317. glBegin( GL_QUADS );
  318. glTexCoord2f( 0.0f, 0.0f ); glVertex2i( x, y );
  319. glTexCoord2f( tex->textureData->maxS, 0.0f ); glVertex2i( x+w, y );
  320. glTexCoord2f( tex->textureData->maxS, tex->textureData->maxT ); glVertex2i( x+w, y+h );
  321. glTexCoord2f( 0.0f, tex->textureData->maxT ); glVertex2i( x, y+h );
  322. glEnd();
  323. }
  324. void PK_StretchTexture( pkTexture_t *tex, float x, float y, float w, float h ) {
  325. PK_BindTexture( tex );
  326. glBegin( GL_QUADS );
  327. glTexCoord2f( 0.0f, 0.0f ); glVertex2i( x, y );
  328. glTexCoord2f( tex->textureData->maxS, 0.0f ); glVertex2i( x+w, y );
  329. glTexCoord2f( tex->textureData->maxS, tex->textureData->maxT ); glVertex2i( x+w, y+h );
  330. glTexCoord2f( 0.0f, tex->textureData->maxT ); glVertex2i( x, y+h );
  331. glEnd();
  332. }