texture_manager.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380
  1. /*
  2. Copyright (C) 2004 Michael Liebscher
  3. Copyright (C) 1997-2001 Id Software, Inc.
  4. Copyright (C) 1995 Spencer Kimball and Peter Mattis.
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  16. */
  17. /*
  18. * texture_manager.c: Texture manager.
  19. *
  20. * Author: Michael Liebscher <johnnycanuck@users.sourceforge.net>
  21. * Date: 2004
  22. *
  23. * Acknowledgement:
  24. * Portion of this code was derived from
  25. * The GIMP (an image manipulation program) and was originally
  26. * written by Spencer Kimball and Peter Mattis.
  27. *
  28. * Portion of this code was derived from Quake II, and was originally
  29. * written by Id Software, Inc.
  30. *
  31. */
  32. #include "../wolfiphone.h"
  33. PRIVATE texture_t ttextures[ MAX_TEXTURES ];
  34. PRIVATE int numttextures;
  35. PRIVATE texture_t *r_notexture; // use for bad textures
  36. cvar_t *gl_round_down;
  37. int registration_sequence;
  38. W32 texture_registration_sequence;
  39. extern int currentTextures[ 4 ];
  40. extern int currenttmu;
  41. extern int glMaxTexSize;
  42. PRIVATE INLINECALL GLenum WrapToGL( TWrapMode mode )
  43. {
  44. if( mode == Repeat )
  45. {
  46. return GL_REPEAT;
  47. }
  48. else
  49. {
  50. return GL_CLAMP_TO_EDGE;
  51. }
  52. }
  53. PRIVATE INLINECALL GLenum MagFilterToGL( TMagFilter MagFilter )
  54. {
  55. switch( MagFilter )
  56. {
  57. case Nearest:
  58. return GL_NEAREST;
  59. case Linear:
  60. return GL_LINEAR;
  61. default:
  62. break;
  63. }
  64. return GL_LINEAR;
  65. }
  66. PRIVATE INLINECALL GLenum MinFilterToGL( _boolean MipMap, TMinFilter MinFilter )
  67. {
  68. if( MipMap )
  69. {
  70. switch( MinFilter )
  71. {
  72. case NearestMipMapOff:
  73. return GL_NEAREST;
  74. case NearestMipMapNearest:
  75. return GL_NEAREST_MIPMAP_NEAREST;
  76. case NearestMipMapLinear:
  77. return GL_NEAREST_MIPMAP_LINEAR;
  78. case LinearMipMapOff:
  79. return GL_LINEAR;
  80. case LinearMipMapNearest:
  81. return GL_LINEAR_MIPMAP_NEAREST;
  82. case LinearMipMapLinear:
  83. return GL_LINEAR_MIPMAP_LINEAR;
  84. default:
  85. break;
  86. }
  87. }
  88. else
  89. {
  90. switch( MinFilter )
  91. {
  92. case NearestMipMapOff:
  93. case NearestMipMapNearest:
  94. case NearestMipMapLinear:
  95. return GL_NEAREST;
  96. case LinearMipMapOff:
  97. case LinearMipMapNearest:
  98. case LinearMipMapLinear:
  99. return GL_LINEAR;
  100. default:
  101. break;
  102. }
  103. }
  104. return GL_LINEAR;
  105. }
  106. /*
  107. -----------------------------------------------------------------------------
  108. Function: TM_TextureList_f -Console function to list loaded textures.
  109. Parameters: Nothing.
  110. Returns: Nothing.
  111. Notes:
  112. -----------------------------------------------------------------------------
  113. */
  114. PUBLIC void TM_TextureList_f( void )
  115. {
  116. int i;
  117. texture_t *image;
  118. int texels;
  119. const char *palstrings[ 2 ] =
  120. {
  121. "RGB",
  122. "PAL"
  123. };
  124. Com_Printf( "------------------\n" );
  125. texels = 0;
  126. for( i = 0, image = ttextures ; i < numttextures ; ++i, ++image )
  127. {
  128. if( image->texnum <= 0 )
  129. continue;
  130. texels += image->upload_width * image->upload_height;
  131. switch( image->type )
  132. {
  133. case TT_Sprite:
  134. Com_Printf( "S" );
  135. break;
  136. case TT_Wall:
  137. Com_Printf( "W" );
  138. break;
  139. case TT_Pic:
  140. Com_Printf( "P" );
  141. break;
  142. default:
  143. Com_Printf( " " );
  144. break;
  145. }
  146. Com_Printf( " %3i %3i %s: %s\n",
  147. image->upload_width, image->upload_height, palstrings[ 0 ], image->name );
  148. }
  149. Com_Printf( "Total texel count (not counting mipmaps): %i\n", texels );
  150. }
  151. texture_t *TM_AllocateTexture( const char *name ) {
  152. texture_t *tex;
  153. int i;
  154. assert( strlen( name ) < sizeof( tex->name ) );
  155. // find a free texture_t space
  156. for( i = 0, tex = ttextures; i < numttextures; ++i, ++tex )
  157. {
  158. if( ! tex->texnum )
  159. {
  160. break;
  161. }
  162. }
  163. if( i == numttextures )
  164. {
  165. if( numttextures == MAX_TEXTURES )
  166. {
  167. Com_DPrintf( "MAX_TEXTURES reached\n" );
  168. return r_notexture;
  169. }
  170. numttextures++;
  171. }
  172. tex = &ttextures[ i ];
  173. memset( tex, 0, sizeof( *tex ) );
  174. my_strlcpy( tex->name, name, MAX_GAMEPATH );
  175. tex->registration_sequence = texture_registration_sequence;
  176. // don't let R_Bind skip the next bind call
  177. currentTextures[ currenttmu ] = -1;
  178. pfglGenTextures( 1, &tex->texnum );
  179. pfglBindTexture( GL_TEXTURE_2D, tex->texnum );
  180. return tex;
  181. }
  182. /*
  183. -----------------------------------------------------------------------------
  184. Function: TM_LoadTexture -Load raw image into video memory.
  185. Parameters:
  186. name -[in] Name of texture image.
  187. data -[in] Raw pixel data in the format described by PixelFormat.
  188. width -[in] Width of image in pixels.
  189. height -[in] Height of image in pixels.
  190. type -[in]
  191. PixelFormat [in]
  192. Returns: Pointer to filled out texture_t structure.
  193. Notes: Any texture that was not touched on this registration sequence will be freed.
  194. -----------------------------------------------------------------------------
  195. */
  196. PUBLIC texture_t *TM_LoadTexture( const char *name, W8 *data, int width, int height, texturetype_t type, W16 bytes )
  197. {
  198. texture_t *tex;
  199. W8 *scaled;
  200. W16 scaled_width, scaled_height;
  201. tex = TM_AllocateTexture( name );
  202. tex->width = width;
  203. tex->height = height;
  204. tex->type = type;
  205. tex->bytes = bytes;
  206. switch( type )
  207. {
  208. case TT_Pic:
  209. tex->MipMap = false;
  210. tex->WrapS = Clamp;
  211. tex->WrapT = Clamp;
  212. tex->MinFilter = Nearest;
  213. tex->MagFilter = NearestMipMapOff;
  214. break;
  215. case TT_Wall:
  216. tex->MipMap = true;
  217. tex->WrapS = Repeat;
  218. tex->WrapT = Repeat;
  219. // tex->MinFilter = LinearMipMapLinear;
  220. tex->MinFilter = LinearMipMapNearest;
  221. tex->MagFilter = Linear;
  222. break;
  223. default:
  224. tex->WrapS = Repeat;
  225. tex->WrapT = Repeat;
  226. tex->MinFilter = Nearest;
  227. tex->MagFilter = NearestMipMapOff;
  228. break;
  229. }
  230. for( scaled_width = 1 ; scaled_width < tex->width ; scaled_width <<= 1 )
  231. {
  232. ;
  233. }
  234. if( gl_round_down->value && scaled_width > tex->width && tex->MipMap )
  235. {
  236. scaled_width >>= 1;
  237. }
  238. for( scaled_height = 1 ; scaled_height < tex->height ; scaled_height <<= 1 )
  239. {
  240. ;
  241. }
  242. if( gl_round_down->value && scaled_height > tex->height && tex->MipMap )
  243. {
  244. scaled_height >>= 1;
  245. }
  246. // let people sample down the world textures for speed
  247. if( tex->MipMap )
  248. {
  249. scaled_width >>= (int)gl_picmip->value;
  250. scaled_height >>= (int)gl_picmip->value;
  251. }
  252. // don't ever bother with > glMaxTexSize textures
  253. if( scaled_width > glMaxTexSize )
  254. {
  255. scaled_width = glMaxTexSize;
  256. }
  257. if( scaled_height > glMaxTexSize )
  258. {
  259. scaled_height = glMaxTexSize;
  260. }
  261. if( scaled_width < 1 )
  262. {
  263. scaled_width = 1;
  264. }
  265. if( scaled_height < 1 )
  266. {
  267. scaled_height = 1;
  268. }
  269. tex->upload_width = scaled_width;
  270. tex->upload_height = scaled_height;
  271. if( scaled_width == tex->width && scaled_height == tex->height )
  272. {
  273. scaled = data;
  274. }
  275. else
  276. {
  277. scaled = Z_Malloc( scaled_width * scaled_height * tex->bytes );
  278. TM_ResampleTexture( data, tex->width, tex->height, scaled, scaled_width, scaled_height, tex->bytes, INTERPOLATION_NONE );
  279. }
  280. {
  281. // upload base image
  282. GLenum internalFormat[] = { GL_LUMINANCE, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA };
  283. #if 0
  284. GLenum externalFormat[] = { GL_LUMINANCE, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_5_5_5_1 };
  285. pfglTexImage2D( GL_TEXTURE_2D, 0, internalFormat[ tex->bytes ], scaled_width, scaled_height, 0, tex->bytes == 4 ? GL_RGBA : GL_RGB, externalFormat[ tex->bytes ], scaled );
  286. #else
  287. pfglTexImage2D( GL_TEXTURE_2D, 0, internalFormat[ tex->bytes ], scaled_width, scaled_height, 0, tex->bytes == 4 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, scaled );
  288. #endif
  289. // upload mipmaps if required
  290. #ifdef IPHONE
  291. glGenerateMipmapOES( GL_TEXTURE_2D );
  292. #else
  293. if( tex->MipMap )
  294. {
  295. int miplevel = 0;
  296. while( TM_MipMap( scaled, &scaled_width, &scaled_height, tex->bytes ) )
  297. {
  298. pfglTexImage2D( GL_TEXTURE_2D, ++miplevel, internalFormat[ tex->bytes ], scaled_width, scaled_height, 0, tex->bytes == 4 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, scaled );
  299. }
  300. }
  301. #endif
  302. }
  303. if ( scaled != data ) {
  304. Z_Free( scaled );
  305. }
  306. pfglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, WrapToGL( tex->WrapS ) );
  307. pfglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, WrapToGL( tex->WrapT ) );
  308. pfglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, MinFilterToGL( tex->MipMap, tex->MinFilter ) );
  309. pfglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, MagFilterToGL( tex->MagFilter ) );
  310. #ifdef IPHONE
  311. if ( type == TT_Wall ) {
  312. pfglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.0f );
  313. } else {
  314. pfglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 0 );
  315. }
  316. #endif
  317. return tex;
  318. }
  319. /*
  320. -----------------------------------------------------------------------------
  321. Function: TM_FreeUnusedTextures -Free unused textures.
  322. Parameters: Nothing.
  323. Returns: Nothing.
  324. Notes: Any texture that was not touched on this registration sequence will be freed.
  325. -----------------------------------------------------------------------------
  326. */
  327. PUBLIC void TM_FreeUnusedTextures( void )
  328. {
  329. #if 0
  330. int i;
  331. texture_t *tex;
  332. // never free r_notexture texture
  333. r_notexture->registration_sequence = texture_registration_sequence;
  334. for( i = 0, tex = ttextures ; i < numttextures ; ++i, ++tex )
  335. {
  336. if( tex->registration_sequence == texture_registration_sequence )
  337. continue; // used this sequence
  338. if( ! tex->registration_sequence )
  339. continue; // free image_t slot
  340. if( tex->type == TT_Pic )
  341. continue; // don't free pics
  342. // free texture
  343. R_DeleteTexture( tex->texnum );
  344. memset( tex, 0, sizeof( *tex ) );
  345. }
  346. #endif
  347. }
  348. /*
  349. -----------------------------------------------------------------------------
  350. Function: TM_FindTexture -Find texture.
  351. Parameters: name -[in] Name of the texture to find.
  352. type -[in] Type of texture (see texturetype_t).
  353. Returns: r_notexture if the texture is not found, otherwise it will
  354. return a valid texture_t structure.
  355. Notes:
  356. -----------------------------------------------------------------------------
  357. */
  358. PUBLIC texture_t *TM_FindTexture( const char *name, texturetype_t type )
  359. {
  360. texture_t *tex;
  361. int i, len;
  362. W8 *data; /* raw texture data */
  363. W16 width, height; /* width, height of texture */
  364. W16 bytes;
  365. char digested[1024];
  366. filehandle_t *fh;
  367. if( ! name || ! *name )
  368. {
  369. return r_notexture;
  370. }
  371. // Check for file extension
  372. len = strlen( name );
  373. if( len < 5 )
  374. {
  375. return r_notexture;
  376. }
  377. // look for it in the texture cache
  378. for( i = 0, tex = ttextures; i < numttextures; ++i, ++tex )
  379. {
  380. if( ! strcmp( name, tex->name ) )
  381. {
  382. tex->registration_sequence = texture_registration_sequence;
  383. return tex;
  384. }
  385. }
  386. //
  387. // load the texture from disk
  388. //
  389. data = NULL;
  390. if( strcmp( name + len - 4, ".tga" ) ) {
  391. return r_notexture;
  392. }
  393. // look for the pre-digested 5551 version
  394. strcpy( digested, name );
  395. strcpy( digested + len - 4, ".5551" );
  396. fh = FS_OpenFile( digested, 0 );
  397. if ( fh ) {
  398. picHeader_t *ph = (picHeader_t *)fh->filedata;
  399. int w = ph->uploadWidth;
  400. int h = ph->uploadHeight;
  401. int l = 0;
  402. texture_t *tx = TM_AllocateTexture( name );
  403. tx->width = w;
  404. tx->height = h;
  405. tx->upload_width = w;
  406. tx->upload_height = h;
  407. tx->header = *ph;
  408. unsigned short *s = (unsigned short *)(ph+1);
  409. while( 1 ) {
  410. pfglTexImage2D( GL_TEXTURE_2D, l, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, s );
  411. if ( w == 1 && h == 1 ) {
  412. break;
  413. }
  414. l++;
  415. s += w*h;
  416. w >>= 1;
  417. if ( w == 0 ) {
  418. w = 1;
  419. }
  420. h >>= 1;
  421. if ( h == 0 ) {
  422. h = 1;
  423. }
  424. }
  425. FS_CloseFile( fh );
  426. pfglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
  427. pfglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
  428. pfglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
  429. pfglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  430. if ( type == TT_Wall ) {
  431. pfglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.0f );
  432. } else {
  433. pfglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 0 );
  434. }
  435. return tx;
  436. }
  437. // load a normal TGA
  438. LoadTGA( name, &data, &width, &height, &bytes );
  439. if ( data ) {
  440. tex = TM_LoadTexture( name, data, width, height, type, bytes );
  441. MM_FREE( data );
  442. return tex;
  443. }
  444. // load a jpg
  445. {
  446. int jpgSize = 0;
  447. W8 *jpgData;
  448. void iPhoneLoadJPG( W8* jpegData, int jpegBytes, W8 **pic, W16 *width, W16 *height, W16 *bytes );
  449. // try jpeg if no tga exists
  450. strcpy( digested, name );
  451. strcpy( digested + len - 4, ".jpg" );
  452. fh = FS_OpenFile( digested, 0 );
  453. if ( fh == NULL ) {
  454. Com_Printf( "Failed to find texture %s\n", name );
  455. return r_notexture;
  456. }
  457. jpgSize = FS_GetFileSize( fh );
  458. jpgData = fh->ptrStart;
  459. iPhoneLoadJPG( jpgData, jpgSize, &data, &width, &height, &bytes );
  460. FS_CloseFile( fh );
  461. if ( ! data ) {
  462. free( jpgData );
  463. return r_notexture;
  464. }
  465. tex = TM_LoadTexture( name, data, width, height, type, bytes );
  466. MM_FREE( data );
  467. return tex;
  468. }
  469. return NULL;
  470. }
  471. /*
  472. -----------------------------------------------------------------------------
  473. Function: TM_GetTextureSize -Find texture.
  474. Parameters:width -[out] Width of texture.
  475. height -[out] Height of texture.
  476. name -[in] Name of the texture to get dimensions of.
  477. Returns: Nothing.
  478. Notes: If texture is not found, width and height are -1.
  479. -----------------------------------------------------------------------------
  480. */
  481. PUBLIC void TM_GetTextureSize( SW32 *width, SW32 *height, const char *name )
  482. {
  483. texture_t *tex;
  484. tex = TM_FindTexture( name, TT_Pic );
  485. if( ! tex )
  486. {
  487. *width = *height = -1;
  488. return;
  489. }
  490. *width = tex->width;
  491. *height = tex->height;
  492. }
  493. /* Note: cubic function no longer clips result */
  494. PRIVATE INLINECALL double
  495. cubic (double dx,
  496. int jm1,
  497. int j,
  498. int jp1,
  499. int jp2)
  500. {
  501. /* Catmull-Rom - not bad */
  502. return (double) ((( ( - jm1 + 3 * j - 3 * jp1 + jp2 ) * dx +
  503. ( 2 * jm1 - 5 * j + 4 * jp1 - jp2 ) ) * dx +
  504. ( - jm1 + jp1 ) ) * dx + (j + j) ) / 2.0;
  505. }
  506. _boolean pixel_region_has_alpha( int bytes )
  507. {
  508. if( bytes == 2 || bytes == 4 )
  509. {
  510. return true;
  511. }
  512. else
  513. {
  514. return false;
  515. }
  516. }
  517. PRIVATE void
  518. expand_line( double *dest,
  519. double *src,
  520. int bytes,
  521. int old_width,
  522. int width )
  523. {
  524. double ratio;
  525. int x,b;
  526. int src_col;
  527. double frac;
  528. double *s;
  529. ratio = old_width / (double) width;
  530. /* we can overflow src's boundaries, so we expect our caller to have
  531. allocated extra space for us to do so safely (see scale_region ()) */
  532. /* this could be optimized much more by precalculating the coefficients for
  533. each x */
  534. for( x = 0; x < width; ++x )
  535. {
  536. src_col = ((int) (x * ratio + 2.0 - 0.5)) - 2;
  537. /* +2, -2 is there because (int) rounds towards 0 and we need
  538. to round down */
  539. frac = (x * ratio - 0.5) - src_col;
  540. s = &src[ src_col * bytes ];
  541. for( b = 0 ; b < bytes ; b++ )
  542. dest[ b ] = cubic( frac, (int)s[ b - bytes ], (int)s[ b ], (int)s[ b + bytes ], (int)s[ b + bytes * 2 ] );
  543. dest += bytes;
  544. }
  545. }
  546. PRIVATE void
  547. shrink_line( double *dest,
  548. double *src,
  549. int bytes,
  550. int old_width,
  551. int width )
  552. {
  553. int x;
  554. int b;
  555. double *srcp;
  556. double *destp;
  557. double accum[4];
  558. double slice;
  559. const double avg_ratio = (double) width / old_width;
  560. const double inv_width = 1.0 / width;
  561. int slicepos; /* slice position relative to width */
  562. #if 0
  563. Com_DPrintf( "shrink_line bytes=%d old_width=%d width=%d interp=%d "
  564. "avg_ratio=%f\n",
  565. bytes, old_width, width, interp, avg_ratio);
  566. #endif
  567. // g_return_if_fail( bytes <= 4 );
  568. /* This algorithm calculates the weighted average of pixel data that
  569. each output pixel must receive, taking into account that it always
  570. scales down, i.e. there's always more than one input pixel per each
  571. output pixel. */
  572. srcp = src;
  573. destp = dest;
  574. slicepos = 0;
  575. /* Initialize accum to the first pixel slice. As there is no partial
  576. pixel at start, that value is 0. The source data is interleaved, so
  577. we maintain BYTES accumulators at the same time to deal with that
  578. many channels simultaneously. */
  579. for( b = 0 ; b < bytes ; ++b )
  580. {
  581. accum[ b ] = 0.0;
  582. }
  583. for( x = 0 ; x < width ; x++ )
  584. {
  585. /* Accumulate whole pixels. */
  586. do
  587. {
  588. for( b = 0 ; b < bytes ; b++ )
  589. accum[ b ] += *srcp++;
  590. slicepos += width;
  591. }
  592. while( slicepos < old_width );
  593. slicepos -= old_width;
  594. if( ! (slicepos < width))
  595. Com_Printf( "Assertion (slicepos < width) failed. Please report.\n" );
  596. if( slicepos == 0 )
  597. {
  598. /* Simplest case: we have reached a whole pixel boundary. Store
  599. the average value per channel and reset the accumulators for
  600. the next round.
  601. The main reason to treat this case separately is to avoid an
  602. access to out-of-bounds memory for the first pixel. */
  603. for (b = 0; b < bytes; b++)
  604. {
  605. *destp++ = accum[b] * avg_ratio;
  606. accum[b] = 0.0;
  607. }
  608. }
  609. else
  610. {
  611. for( b = 0; b < bytes; b++ )
  612. {
  613. /* We have accumulated a whole pixel per channel where just a
  614. slice of it was needed. Subtract now the previous pixel's
  615. extra slice. */
  616. slice = srcp[- bytes + b] * slicepos * inv_width;
  617. *destp++ = (accum[b] - slice) * avg_ratio;
  618. /* That slice is the initial value for the next round. */
  619. accum[b] = slice;
  620. }
  621. }
  622. }
  623. /* Sanity check: srcp should point to the next-to-last position, and
  624. slicepos should be zero. */
  625. if( ! (srcp - src == old_width * bytes && slicepos == 0) )
  626. {
  627. Com_Printf ("Assertion (srcp - src == old_width * bytes && slicepos == 0)"
  628. " failed. Please report.");
  629. }
  630. }
  631. PRIVATE void pixel_region_get_row( W8 *src, int y, int width, W8 *tmp_src, int BytesPerPixel )
  632. {
  633. int i;
  634. unsigned long k = 0;
  635. unsigned char *scanline = tmp_src;
  636. unsigned char *ptr = src;
  637. for( i = 0 ; i < (width * BytesPerPixel) ; ++i )
  638. {
  639. scanline[ k++ ] = ptr[ y * width * BytesPerPixel + i ];
  640. }
  641. }
  642. PRIVATE void pixel_region_set_row( W8 *dest,
  643. int BytesPerPixel,
  644. int y,
  645. int width,
  646. W8 *data )
  647. {
  648. int i;
  649. unsigned long k = 0;
  650. unsigned char *scanline = dest;
  651. unsigned char *ptr = data;
  652. for( i = 0 ; i < (width * BytesPerPixel) ; ++i )
  653. {
  654. scanline[ y * width * BytesPerPixel + i ] = ptr[ k++ ];
  655. }
  656. }
  657. PRIVATE void
  658. get_premultiplied_double_row( W8 *in,
  659. int PRbytes,
  660. int x,
  661. int y,
  662. int w,
  663. double *row,
  664. W8 *tmp_src,
  665. int n )
  666. {
  667. int b;
  668. int bytes = PRbytes;
  669. pixel_region_get_row( in, y, w, tmp_src, bytes );
  670. if( pixel_region_has_alpha( bytes ) )
  671. {
  672. /* premultiply the alpha into the double array */
  673. double *irow = row;
  674. int alpha = bytes - 1;
  675. double mod_alpha;
  676. for( x = 0; x < w; ++x )
  677. {
  678. mod_alpha = tmp_src[ alpha ] / 255.0;
  679. for( b = 0; b < alpha; ++b )
  680. {
  681. irow[ b ] = mod_alpha * tmp_src[ b ];
  682. }
  683. irow[ b ] = tmp_src[ alpha ];
  684. irow += bytes;
  685. tmp_src += bytes;
  686. }
  687. }
  688. else /* no alpha */
  689. {
  690. for( x = 0; x < w * bytes; ++x )
  691. {
  692. row[ x ] = tmp_src[ x ];
  693. }
  694. }
  695. /* set the off edge pixels to their nearest neighbor */
  696. for( b = 0; b < 2 * bytes; b++ )
  697. {
  698. row[ b - 2 * bytes ] = row[ b % bytes ];
  699. }
  700. for( b = 0; b < bytes * 2; b++ )
  701. {
  702. row[ b + w * bytes ] = row[ (w - 1) * bytes + b % bytes ];
  703. }
  704. }
  705. PRIVATE INLINECALL void
  706. rotate_pointers( W8 **p, W32 n )
  707. {
  708. W32 i;
  709. W8 *tmp;
  710. tmp = p[ 0 ];
  711. for( i = 0 ; i < n-1 ; i++ )
  712. {
  713. p[ i ] = p[ i + 1 ];
  714. }
  715. p[ i ] = tmp;
  716. }
  717. PRIVATE void
  718. get_scaled_row( double **src,
  719. int y,
  720. int new_width,
  721. double *row,
  722. W8 *src_tmp,
  723. W8 *srcPR,
  724. int old_width,
  725. int old_height,
  726. int bytes )
  727. {
  728. /* get the necesary lines from the source image, scale them,
  729. and put them into src[] */
  730. rotate_pointers( (unsigned char **)src, 4 );
  731. if( y < 0 )
  732. {
  733. y = 0;
  734. }
  735. if( y < old_height )
  736. {
  737. get_premultiplied_double_row( srcPR, bytes, 0, y, old_width,
  738. row, src_tmp, 1 );
  739. if( new_width > old_width )
  740. {
  741. expand_line( src[3], row, bytes, old_width, new_width );
  742. }
  743. else if( old_width > new_width )
  744. {
  745. shrink_line( src[3], row, bytes, old_width, new_width );
  746. }
  747. else /* no scailing needed */
  748. {
  749. memcpy( src[3], row, sizeof( double ) * new_width * bytes );
  750. }
  751. }
  752. else
  753. {
  754. memcpy( src[3], src[2], sizeof( double ) * new_width * bytes );
  755. }
  756. }
  757. /*
  758. non-interpolating scale_region.
  759. */
  760. PRIVATE void
  761. scale_region_no_resample( W8 *in, int inwidth, int inheight,
  762. W8 *out, int outwidth, int outheight, char bytes )
  763. {
  764. int *x_src_offsets;
  765. int *y_src_offsets;
  766. W8 *src;
  767. W8 *dest;
  768. int width, height, orig_width, orig_height;
  769. int last_src_y;
  770. int row_bytes;
  771. int x, y, b;
  772. orig_width = inwidth;
  773. orig_height = inheight;
  774. width = outwidth;
  775. height = outheight;
  776. /* the data pointers... */
  777. x_src_offsets = (int *) MM_MALLOC( sizeof( int ) * width * bytes );
  778. y_src_offsets = (int *) MM_MALLOC( sizeof( int ) * height );
  779. src = (unsigned char *) MM_MALLOC( orig_width * bytes);
  780. dest = (unsigned char *) MM_MALLOC( width * bytes);
  781. /* pre-calc the scale tables */
  782. for( b = 0; b < bytes; b++ )
  783. {
  784. for( x = 0; x < width; x++ )
  785. {
  786. x_src_offsets[ b + x * bytes ] =
  787. b + bytes * ((x * orig_width + orig_width / 2) / width);
  788. }
  789. }
  790. for( y = 0; y < height; y++ )
  791. {
  792. y_src_offsets[ y ] = (y * orig_height + orig_height / 2) / height;
  793. }
  794. /* do the scaling */
  795. row_bytes = width * bytes;
  796. last_src_y = -1;
  797. for( y = 0; y < height; y++ )
  798. {
  799. /* if the source of this line was the same as the source
  800. * of the last line, there's no point in re-rescaling.
  801. */
  802. if( y_src_offsets[ y ] != last_src_y )
  803. {
  804. pixel_region_get_row( in, y_src_offsets[ y ], orig_width, src, bytes );
  805. //pixel_region_get_row( srcPR, 0, y_src_offsets[y], orig_width, src, 1 );
  806. for( x = 0 ; x < row_bytes ; x++ )
  807. {
  808. dest[ x ] = src[ x_src_offsets[ x ] ];
  809. }
  810. last_src_y = y_src_offsets[ y ];
  811. }
  812. pixel_region_set_row( out, bytes, y, width, dest );
  813. }
  814. MM_FREE( x_src_offsets );
  815. MM_FREE( y_src_offsets );
  816. MM_FREE( src );
  817. MM_FREE( dest );
  818. }
  819. /*
  820. -----------------------------------------------------------------------------
  821. Function: TM_ResampleTexture -Resize texture.
  822. Parameters:
  823. in -[in] Original texture data.
  824. inwidth -[in] Original width of texture in pixels.
  825. inheight -[in] Original height of texture in pixels.
  826. out -[in/out] Resized texture data.
  827. outwidth -[in] New width of texture in pixels.
  828. outheight -[in] New height of texture in pixels.
  829. bytes -[in] Number of bytes per pixel.
  830. interpolation -[in] see InterpolationType
  831. Returns: Nothing.
  832. Notes:
  833. -----------------------------------------------------------------------------
  834. */
  835. PUBLIC void TM_ResampleTexture( W8 *in, int inwidth, int inheight, W8 *out, int outwidth, int outheight, W8 bytes, InterpolationType interpolation )
  836. {
  837. double *src[ 4 ];
  838. W8 *src_tmp;
  839. W8 *dest;
  840. double *row, *accum;
  841. int b;
  842. int width, height;
  843. int orig_width, orig_height;
  844. double y_rat;
  845. int i;
  846. int old_y = -4;
  847. int new_y;
  848. int x, y;
  849. if( interpolation == INTERPOLATION_NONE )
  850. {
  851. scale_region_no_resample( in, inwidth, inheight, out, outwidth, outheight, bytes );
  852. return;
  853. }
  854. orig_width = inwidth;
  855. orig_height = inheight;
  856. width = outwidth;
  857. height = outheight;
  858. #if 0
  859. Com_DPrintf( "scale_region: (%d x %d) -> (%d x %d)\n",
  860. orig_width, orig_height, width, height );
  861. #endif
  862. /* find the ratios of old y to new y */
  863. y_rat = (double) orig_height / (double) height;
  864. /* the data pointers... */
  865. for( i = 0 ; i < 4 ; ++i )
  866. {
  867. src[ i ] = (double *) MM_MALLOC( sizeof( double ) * width * bytes );
  868. }
  869. dest = (PW8) MM_MALLOC( width * bytes);
  870. src_tmp = (PW8) MM_MALLOC( orig_width * bytes );
  871. /* offset the row pointer by 2*bytes so the range of the array
  872. is [-2*bytes] to [(orig_width + 2)*bytes] */
  873. row = (double *) MM_MALLOC( sizeof( double ) * (orig_width + 2 * 2) * bytes );
  874. row += bytes * 2;
  875. accum = (double *) MM_MALLOC( sizeof( double ) * width * bytes );
  876. /* Scale the selected region */
  877. for( y = 0 ; y < height ; y++ )
  878. {
  879. if( height < orig_height )
  880. {
  881. int max;
  882. double frac;
  883. const double inv_ratio = 1.0 / y_rat;
  884. if( y == 0 ) /* load the first row if this is the first time through */
  885. {
  886. get_scaled_row( &src[0], 0, width, row, src_tmp, in, orig_width, orig_height, bytes );
  887. }
  888. new_y = (int)(y * y_rat);
  889. frac = 1.0 - (y * y_rat - new_y);
  890. for( x = 0 ; x < width * bytes; ++x )
  891. {
  892. accum[x] = src[3][x] * frac;
  893. }
  894. max = (int) ((y + 1) * y_rat) - new_y - 1;
  895. get_scaled_row( &src[ 0 ], ++new_y, width, row, src_tmp, in, orig_width, orig_height, bytes );
  896. while( max > 0 )
  897. {
  898. for( x = 0 ; x < width * bytes ; ++x )
  899. {
  900. accum[x] += src[ 3 ][ x ];
  901. }
  902. get_scaled_row( &src[ 0 ], ++new_y, width, row, src_tmp, in, orig_width, orig_height, bytes );
  903. max--;
  904. }
  905. frac = (y + 1) * y_rat - ((int) ((y + 1) * y_rat));
  906. for( x = 0 ; x < width * bytes ; ++x )
  907. {
  908. accum[ x ] += frac * src[ 3 ][ x ];
  909. accum[ x ] *= inv_ratio;
  910. }
  911. }
  912. else if( height > orig_height )
  913. {
  914. double p0, p1, p2, p3;
  915. double dy;
  916. new_y = (int)floor( y * y_rat - 0.5 );
  917. while( old_y <= new_y )
  918. {
  919. /* get the necesary lines from the source image, scale them,
  920. and put them into src[] */
  921. get_scaled_row( &src[ 0 ], old_y + 2, width, row, src_tmp, in, orig_width, orig_height, bytes );
  922. old_y++;
  923. }
  924. dy = (y * y_rat - 0.5) - new_y;
  925. p0 = cubic( dy, 1, 0, 0, 0 );
  926. p1 = cubic( dy, 0, 1, 0, 0 );
  927. p2 = cubic( dy, 0, 0, 1, 0 );
  928. p3 = cubic( dy, 0, 0, 0, 1 );
  929. for( x = 0 ; x < width * bytes ; ++x )
  930. {
  931. accum[ x ] = ( p0 * src[ 0 ][ x ] + p1 * src[ 1 ][ x ] +
  932. p2 * src[ 2 ][ x ] + p3 * src[ 3 ][ x ] );
  933. }
  934. }
  935. else /* height == orig_height */
  936. {
  937. get_scaled_row( &src[ 0 ], y, width, row, src_tmp, in, orig_width, orig_height, bytes );
  938. memcpy( accum, src[ 3 ], sizeof( double ) * width * bytes );
  939. }
  940. if( pixel_region_has_alpha( bytes ) )
  941. {
  942. /* unmultiply the alpha */
  943. double inv_alpha;
  944. double *p = accum;
  945. int alpha = bytes - 1;
  946. int result;
  947. W8 *d = dest;
  948. for( x = 0 ; x < width ; ++x )
  949. {
  950. if( p[ alpha ] > 0.001 )
  951. {
  952. inv_alpha = 255.0 / p[ alpha ];
  953. for( b = 0 ; b < alpha ; b++ )
  954. {
  955. result = RINT( inv_alpha * p[ b ] );
  956. if( result < 0 )
  957. {
  958. d[ b ] = 0;
  959. }
  960. else if( result > 255 )
  961. {
  962. d[ b ] = 255;
  963. }
  964. else
  965. {
  966. d[ b ] = result;
  967. }
  968. }
  969. result = RINT( p[ alpha ] );
  970. if( result > 255 )
  971. {
  972. d[ alpha ] = 255;
  973. }
  974. else
  975. {
  976. d[ alpha ] = result;
  977. }
  978. }
  979. else /* alpha <= 0 */
  980. {
  981. for( b = 0 ; b <= alpha ; ++b )
  982. {
  983. d[ b ] = 0;
  984. }
  985. }
  986. d += bytes;
  987. p += bytes;
  988. }
  989. }
  990. else
  991. {
  992. int w = width * bytes;
  993. for( x = 0 ; x < w ; ++x )
  994. {
  995. if( accum[ x ] < 0.0 )
  996. {
  997. dest[ x ] = 0;
  998. }
  999. else if( accum[ x ] > 255.0 )
  1000. {
  1001. dest[ x ] = 255;
  1002. }
  1003. else
  1004. {
  1005. dest[ x ] = RINT( accum[ x ] );
  1006. }
  1007. }
  1008. }
  1009. pixel_region_set_row( out, bytes, y, width, dest );
  1010. }
  1011. /* free up temporary arrays */
  1012. MM_FREE( accum );
  1013. for( i = 0 ; i < 4 ; ++i )
  1014. {
  1015. MM_FREE( src[ i ] );
  1016. }
  1017. MM_FREE( src_tmp );
  1018. MM_FREE( dest );
  1019. row -= 2 * bytes;
  1020. MM_FREE( row );
  1021. }
  1022. /*
  1023. -----------------------------------------------------------------------------
  1024. Function: TM_MipMap -Generate MipMap.
  1025. Parameters:
  1026. in -[in/out] Texture data.
  1027. width -[in] Width of texture in pixels.
  1028. height -[in] Height of texture in pixels.
  1029. Returns: Nothing.
  1030. Notes: Operates in place, quartering the size of the texture.
  1031. -----------------------------------------------------------------------------
  1032. */
  1033. PUBLIC _boolean TM_MipMap( PW8 in, W16 *width, W16 *height, W16 bytes )
  1034. {
  1035. W16 new_width, new_height;
  1036. if( *width == 1 && *height == 1 )
  1037. {
  1038. return false;
  1039. }
  1040. if( *width < 2 )
  1041. {
  1042. new_width = 1;
  1043. }
  1044. else
  1045. {
  1046. new_width = *width >> 1;
  1047. }
  1048. if( *height < 2 )
  1049. {
  1050. new_height = 1;
  1051. }
  1052. else
  1053. {
  1054. new_height = *height >> 1;
  1055. }
  1056. TM_ResampleTexture( in, *width, *height, in, new_width, new_height, bytes, INTERPOLATION_CUBIC );
  1057. *width = new_width;
  1058. *height = new_height;
  1059. return true;
  1060. }
  1061. /*
  1062. -----------------------------------------------------------------------------
  1063. Function: TM_Init -Initialize Texture Manager.
  1064. Parameters: Nothing.
  1065. Returns: Nothing.
  1066. Notes: Generates default texture.
  1067. -----------------------------------------------------------------------------
  1068. */
  1069. PUBLIC void TM_Init( void )
  1070. {
  1071. W8 *ptr;
  1072. W8 *data;
  1073. int x, y;
  1074. gl_round_down = Cvar_Get ("gl_round_down", "1", CVAR_INIT);
  1075. texture_registration_sequence = 1;
  1076. // create a checkerboard texture
  1077. data = MM_MALLOC( 16 * 16 * 4 );
  1078. for( y = 0; y < 16; ++y )
  1079. {
  1080. for( x = 0; x < 16; ++x )
  1081. {
  1082. ptr = &data[ (y * 16 + x) * 4 ];
  1083. if( (y < 8) ^ (x < 8) )
  1084. {
  1085. ptr[ 0 ] = ptr[ 1 ] = ptr[ 2 ] = 0x00;
  1086. ptr[ 3 ] = 0xFF;
  1087. }
  1088. else
  1089. {
  1090. ptr[ 0 ] = ptr[ 1 ] = ptr[ 2 ] = 0xFF;
  1091. ptr[ 3 ] = 0xFF;
  1092. }
  1093. }
  1094. }
  1095. r_notexture = TM_LoadTexture( "***r_notexture***", data, 16, 16, TT_Pic, 4 );
  1096. MM_FREE( data );
  1097. Cmd_AddCommand( "listTextures", TM_TextureList_f );
  1098. }
  1099. /*
  1100. -----------------------------------------------------------------------------
  1101. Function: TM_Shutdown -Shutdown Texture Manager.
  1102. Parameters: Nothing.
  1103. Returns: Nothing.
  1104. Notes:
  1105. -----------------------------------------------------------------------------
  1106. */
  1107. PUBLIC void TM_Shutdown( void )
  1108. {
  1109. int i;
  1110. texture_t *tex;
  1111. for( i = 0, tex = ttextures; i < numttextures; ++i, ++tex )
  1112. {
  1113. if( ! tex->registration_sequence )
  1114. {
  1115. continue; // free image_t slot
  1116. }
  1117. // free texture
  1118. R_DeleteTexture( tex->texnum );
  1119. memset( tex, 0, sizeof( *tex ) );
  1120. }
  1121. Cmd_RemoveCommand( "listTextures" );
  1122. }