Image_init.cpp 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "tr_local.h"
  23. const char *imageFilter[] = {
  24. "GL_LINEAR_MIPMAP_NEAREST",
  25. "GL_LINEAR_MIPMAP_LINEAR",
  26. "GL_NEAREST",
  27. "GL_LINEAR",
  28. "GL_NEAREST_MIPMAP_NEAREST",
  29. "GL_NEAREST_MIPMAP_LINEAR",
  30. NULL
  31. };
  32. idCVar idImageManager::image_filter( "image_filter", imageFilter[1], CVAR_RENDERER | CVAR_ARCHIVE, "changes texture filtering on mipmapped images", imageFilter, idCmdSystem::ArgCompletion_String<imageFilter> );
  33. idCVar idImageManager::image_anisotropy( "image_anisotropy", "1", CVAR_RENDERER | CVAR_ARCHIVE, "set the maximum texture anisotropy if available" );
  34. idCVar idImageManager::image_lodbias( "image_lodbias", "0", CVAR_RENDERER | CVAR_ARCHIVE, "change lod bias on mipmapped images" );
  35. idCVar idImageManager::image_downSize( "image_downSize", "0", CVAR_RENDERER | CVAR_ARCHIVE, "controls texture downsampling" );
  36. idCVar idImageManager::image_forceDownSize( "image_forceDownSize", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "" );
  37. idCVar idImageManager::image_roundDown( "image_roundDown", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "round bad sizes down to nearest power of two" );
  38. idCVar idImageManager::image_colorMipLevels( "image_colorMipLevels", "0", CVAR_RENDERER | CVAR_BOOL, "development aid to see texture mip usage" );
  39. idCVar idImageManager::image_preload( "image_preload", "1", CVAR_RENDERER | CVAR_BOOL | CVAR_ARCHIVE, "if 0, dynamically load all images" );
  40. idCVar idImageManager::image_useCompression( "image_useCompression", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "0 = force everything to high quality" );
  41. idCVar idImageManager::image_useAllFormats( "image_useAllFormats", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "allow alpha/intensity/luminance/luminance+alpha" );
  42. idCVar idImageManager::image_useNormalCompression( "image_useNormalCompression", "2", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "2 = use rxgb compression for normal maps, 1 = use 256 color compression for normal maps if available" );
  43. idCVar idImageManager::image_usePrecompressedTextures( "image_usePrecompressedTextures", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "use .dds files if present" );
  44. idCVar idImageManager::image_writePrecompressedTextures( "image_writePrecompressedTextures", "0", CVAR_RENDERER | CVAR_BOOL, "write .dds files if necessary" );
  45. idCVar idImageManager::image_writeNormalTGA( "image_writeNormalTGA", "0", CVAR_RENDERER | CVAR_BOOL, "write .tgas of the final normal maps for debugging" );
  46. idCVar idImageManager::image_writeNormalTGAPalletized( "image_writeNormalTGAPalletized", "0", CVAR_RENDERER | CVAR_BOOL, "write .tgas of the final palletized normal maps for debugging" );
  47. idCVar idImageManager::image_writeTGA( "image_writeTGA", "0", CVAR_RENDERER | CVAR_BOOL, "write .tgas of the non normal maps for debugging" );
  48. idCVar idImageManager::image_useOffLineCompression( "image_useOfflineCompression", "0", CVAR_RENDERER | CVAR_BOOL, "write a batch file for offline compression of DDS files" );
  49. idCVar idImageManager::image_cacheMinK( "image_cacheMinK", "200", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "maximum KB of precompressed files to read at specification time" );
  50. idCVar idImageManager::image_cacheMegs( "image_cacheMegs", "20", CVAR_RENDERER | CVAR_ARCHIVE, "maximum MB set aside for temporary loading of full-sized precompressed images" );
  51. idCVar idImageManager::image_useCache( "image_useCache", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "1 = do background load image caching" );
  52. idCVar idImageManager::image_showBackgroundLoads( "image_showBackgroundLoads", "0", CVAR_RENDERER | CVAR_BOOL, "1 = print number of outstanding background loads" );
  53. idCVar idImageManager::image_downSizeSpecular( "image_downSizeSpecular", "0", CVAR_RENDERER | CVAR_ARCHIVE, "controls specular downsampling" );
  54. idCVar idImageManager::image_downSizeBump( "image_downSizeBump", "0", CVAR_RENDERER | CVAR_ARCHIVE, "controls normal map downsampling" );
  55. idCVar idImageManager::image_downSizeSpecularLimit( "image_downSizeSpecularLimit", "64", CVAR_RENDERER | CVAR_ARCHIVE, "controls specular downsampled limit" );
  56. idCVar idImageManager::image_downSizeBumpLimit( "image_downSizeBumpLimit", "128", CVAR_RENDERER | CVAR_ARCHIVE, "controls normal map downsample limit" );
  57. idCVar idImageManager::image_ignoreHighQuality( "image_ignoreHighQuality", "0", CVAR_RENDERER | CVAR_ARCHIVE, "ignore high quality setting on materials" );
  58. idCVar idImageManager::image_downSizeLimit( "image_downSizeLimit", "256", CVAR_RENDERER | CVAR_ARCHIVE, "controls diffuse map downsample limit" );
  59. // do this with a pointer, in case we want to make the actual manager
  60. // a private virtual subclass
  61. idImageManager imageManager;
  62. idImageManager *globalImages = &imageManager;
  63. enum IMAGE_CLASSIFICATION {
  64. IC_NPC,
  65. IC_WEAPON,
  66. IC_MONSTER,
  67. IC_MODELGEOMETRY,
  68. IC_ITEMS,
  69. IC_MODELSOTHER,
  70. IC_GUIS,
  71. IC_WORLDGEOMETRY,
  72. IC_OTHER,
  73. IC_COUNT
  74. };
  75. struct imageClassificate_t {
  76. const char *rootPath;
  77. const char *desc;
  78. int type;
  79. int maxWidth;
  80. int maxHeight;
  81. };
  82. typedef idList< int > intList;
  83. const imageClassificate_t IC_Info[] = {
  84. { "models/characters", "Characters", IC_NPC, 512, 512 },
  85. { "models/weapons", "Weapons", IC_WEAPON, 512, 512 },
  86. { "models/monsters", "Monsters", IC_MONSTER, 512, 512 },
  87. { "models/mapobjects", "Model Geometry", IC_MODELGEOMETRY, 512, 512 },
  88. { "models/items", "Items", IC_ITEMS, 512, 512 },
  89. { "models", "Other model textures", IC_MODELSOTHER, 512, 512 },
  90. { "guis/assets", "Guis", IC_GUIS, 256, 256 },
  91. { "textures", "World Geometry", IC_WORLDGEOMETRY, 256, 256 },
  92. { "", "Other", IC_OTHER, 256, 256 }
  93. };
  94. static int ClassifyImage( const char *name ) {
  95. idStr str;
  96. str = name;
  97. for ( int i = 0; i < IC_COUNT; i++ ) {
  98. if ( str.Find( IC_Info[i].rootPath, false ) == 0 ) {
  99. return IC_Info[i].type;
  100. }
  101. }
  102. return IC_OTHER;
  103. }
  104. /*
  105. ================
  106. R_RampImage
  107. Creates a 0-255 ramp image
  108. ================
  109. */
  110. static void R_RampImage( idImage *image ) {
  111. int x;
  112. byte data[256][4];
  113. for (x=0 ; x<256 ; x++) {
  114. data[x][0] =
  115. data[x][1] =
  116. data[x][2] =
  117. data[x][3] = x;
  118. }
  119. image->GenerateImage( (byte *)data, 256, 1,
  120. TF_NEAREST, false, TR_CLAMP, TD_HIGH_QUALITY );
  121. }
  122. /*
  123. ================
  124. R_SpecularTableImage
  125. Creates a ramp that matches our fudged specular calculation
  126. ================
  127. */
  128. static void R_SpecularTableImage( idImage *image ) {
  129. int x;
  130. byte data[256][4];
  131. for (x=0 ; x<256 ; x++) {
  132. float f = x/255.f;
  133. #if 0
  134. f = pow(f, 16);
  135. #else
  136. // this is the behavior of the hacked up fragment programs that
  137. // can't really do a power function
  138. f = (f-0.75)*4;
  139. if ( f < 0 ) {
  140. f = 0;
  141. }
  142. f = f * f;
  143. #endif
  144. int b = (int)(f * 255);
  145. data[x][0] =
  146. data[x][1] =
  147. data[x][2] =
  148. data[x][3] = b;
  149. }
  150. image->GenerateImage( (byte *)data, 256, 1,
  151. TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY );
  152. }
  153. /*
  154. ================
  155. R_Specular2DTableImage
  156. Create a 2D table that calculates ( reflection dot , specularity )
  157. ================
  158. */
  159. static void R_Specular2DTableImage( idImage *image ) {
  160. int x, y;
  161. byte data[256][256][4];
  162. memset( data, 0, sizeof( data ) );
  163. for ( x = 0 ; x < 256 ; x++ ) {
  164. float f = x / 255.0f;
  165. for ( y = 0; y < 256; y++ ) {
  166. int b = (int)( pow( f, y ) * 255.0f );
  167. if ( b == 0 ) {
  168. // as soon as b equals zero all remaining values in this column are going to be zero
  169. // we early out to avoid pow() underflows
  170. break;
  171. }
  172. data[y][x][0] =
  173. data[y][x][1] =
  174. data[y][x][2] =
  175. data[y][x][3] = b;
  176. }
  177. }
  178. image->GenerateImage( (byte *)data, 256, 256, TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY );
  179. }
  180. /*
  181. ================
  182. R_AlphaRampImage
  183. Creates a 0-255 ramp image
  184. ================
  185. */
  186. static void R_AlphaRampImage( idImage *image ) {
  187. int x;
  188. byte data[256][4];
  189. for (x=0 ; x<256 ; x++) {
  190. data[x][0] =
  191. data[x][1] =
  192. data[x][2] = 255;
  193. data[x][3] = x;
  194. }
  195. image->GenerateImage( (byte *)data, 256, 1,
  196. TF_NEAREST, false, TR_CLAMP, TD_HIGH_QUALITY );
  197. }
  198. /*
  199. ==================
  200. R_CreateDefaultImage
  201. the default image will be grey with a white box outline
  202. to allow you to see the mapping coordinates on a surface
  203. ==================
  204. */
  205. #define DEFAULT_SIZE 16
  206. void idImage::MakeDefault() {
  207. int x, y;
  208. byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
  209. if ( com_developer.GetBool() ) {
  210. // grey center
  211. for ( y = 0 ; y < DEFAULT_SIZE ; y++ ) {
  212. for ( x = 0 ; x < DEFAULT_SIZE ; x++ ) {
  213. data[y][x][0] = 32;
  214. data[y][x][1] = 32;
  215. data[y][x][2] = 32;
  216. data[y][x][3] = 255;
  217. }
  218. }
  219. // white border
  220. for ( x = 0 ; x < DEFAULT_SIZE ; x++ ) {
  221. data[0][x][0] =
  222. data[0][x][1] =
  223. data[0][x][2] =
  224. data[0][x][3] = 255;
  225. data[x][0][0] =
  226. data[x][0][1] =
  227. data[x][0][2] =
  228. data[x][0][3] = 255;
  229. data[DEFAULT_SIZE-1][x][0] =
  230. data[DEFAULT_SIZE-1][x][1] =
  231. data[DEFAULT_SIZE-1][x][2] =
  232. data[DEFAULT_SIZE-1][x][3] = 255;
  233. data[x][DEFAULT_SIZE-1][0] =
  234. data[x][DEFAULT_SIZE-1][1] =
  235. data[x][DEFAULT_SIZE-1][2] =
  236. data[x][DEFAULT_SIZE-1][3] = 255;
  237. }
  238. } else {
  239. for ( y = 0 ; y < DEFAULT_SIZE ; y++ ) {
  240. for ( x = 0 ; x < DEFAULT_SIZE ; x++ ) {
  241. data[y][x][0] = 0;
  242. data[y][x][1] = 0;
  243. data[y][x][2] = 0;
  244. data[y][x][3] = 0;
  245. }
  246. }
  247. }
  248. GenerateImage( (byte *)data,
  249. DEFAULT_SIZE, DEFAULT_SIZE,
  250. TF_DEFAULT, true, TR_REPEAT, TD_DEFAULT );
  251. defaulted = true;
  252. }
  253. static void R_DefaultImage( idImage *image ) {
  254. image->MakeDefault();
  255. }
  256. static void R_WhiteImage( idImage *image ) {
  257. byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
  258. // solid white texture
  259. memset( data, 255, sizeof( data ) );
  260. image->GenerateImage( (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE,
  261. TF_DEFAULT, false, TR_REPEAT, TD_DEFAULT );
  262. }
  263. static void R_BlackImage( idImage *image ) {
  264. byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
  265. // solid black texture
  266. memset( data, 0, sizeof( data ) );
  267. image->GenerateImage( (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE,
  268. TF_DEFAULT, false, TR_REPEAT, TD_DEFAULT );
  269. }
  270. // the size determines how far away from the edge the blocks start fading
  271. static const int BORDER_CLAMP_SIZE = 32;
  272. static void R_BorderClampImage( idImage *image ) {
  273. byte data[BORDER_CLAMP_SIZE][BORDER_CLAMP_SIZE][4];
  274. // solid white texture with a single pixel black border
  275. memset( data, 255, sizeof( data ) );
  276. for ( int i = 0 ; i < BORDER_CLAMP_SIZE ; i++ ) {
  277. data[i][0][0] =
  278. data[i][0][1] =
  279. data[i][0][2] =
  280. data[i][0][3] =
  281. data[i][BORDER_CLAMP_SIZE-1][0] =
  282. data[i][BORDER_CLAMP_SIZE-1][1] =
  283. data[i][BORDER_CLAMP_SIZE-1][2] =
  284. data[i][BORDER_CLAMP_SIZE-1][3] =
  285. data[0][i][0] =
  286. data[0][i][1] =
  287. data[0][i][2] =
  288. data[0][i][3] =
  289. data[BORDER_CLAMP_SIZE-1][i][0] =
  290. data[BORDER_CLAMP_SIZE-1][i][1] =
  291. data[BORDER_CLAMP_SIZE-1][i][2] =
  292. data[BORDER_CLAMP_SIZE-1][i][3] = 0;
  293. }
  294. image->GenerateImage( (byte *)data, BORDER_CLAMP_SIZE, BORDER_CLAMP_SIZE,
  295. TF_LINEAR /* TF_NEAREST */, false, TR_CLAMP_TO_BORDER, TD_DEFAULT );
  296. if ( !glConfig.isInitialized ) {
  297. // can't call qglTexParameterfv yet
  298. return;
  299. }
  300. // explicit zero border
  301. float color[4];
  302. color[0] = color[1] = color[2] = color[3] = 0;
  303. qglTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color );
  304. }
  305. static void R_RGBA8Image( idImage *image ) {
  306. byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
  307. memset( data, 0, sizeof( data ) );
  308. data[0][0][0] = 16;
  309. data[0][0][1] = 32;
  310. data[0][0][2] = 48;
  311. data[0][0][3] = 96;
  312. image->GenerateImage( (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE,
  313. TF_DEFAULT, false, TR_REPEAT, TD_HIGH_QUALITY );
  314. }
  315. static void R_RGB8Image( idImage *image ) {
  316. byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
  317. memset( data, 0, sizeof( data ) );
  318. data[0][0][0] = 16;
  319. data[0][0][1] = 32;
  320. data[0][0][2] = 48;
  321. data[0][0][3] = 255;
  322. image->GenerateImage( (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE,
  323. TF_DEFAULT, false, TR_REPEAT, TD_HIGH_QUALITY );
  324. }
  325. static void R_AlphaNotchImage( idImage *image ) {
  326. byte data[2][4];
  327. // this is used for alpha test clip planes
  328. data[0][0] = data[0][1] = data[0][2] = 255;
  329. data[0][3] = 0;
  330. data[1][0] = data[1][1] = data[1][2] = 255;
  331. data[1][3] = 255;
  332. image->GenerateImage( (byte *)data, 2, 1,
  333. TF_NEAREST, false, TR_CLAMP, TD_HIGH_QUALITY );
  334. }
  335. static void R_FlatNormalImage( idImage *image ) {
  336. byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
  337. int i;
  338. int red = ( globalImages->image_useNormalCompression.GetInteger() == 1 ) ? 0 : 3;
  339. int alpha = ( red == 0 ) ? 3 : 0;
  340. // flat normal map for default bunp mapping
  341. for ( i = 0 ; i < 4 ; i++ ) {
  342. data[0][i][red] = 128;
  343. data[0][i][1] = 128;
  344. data[0][i][2] = 255;
  345. data[0][i][alpha] = 255;
  346. }
  347. image->GenerateImage( (byte *)data, 2, 2,
  348. TF_DEFAULT, true, TR_REPEAT, TD_HIGH_QUALITY );
  349. }
  350. static void R_AmbientNormalImage( idImage *image ) {
  351. byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
  352. int i;
  353. int red = ( globalImages->image_useNormalCompression.GetInteger() == 1 ) ? 0 : 3;
  354. int alpha = ( red == 0 ) ? 3 : 0;
  355. // flat normal map for default bunp mapping
  356. for ( i = 0 ; i < 4 ; i++ ) {
  357. data[0][i][red] = (byte)(255 * tr.ambientLightVector[0]);
  358. data[0][i][1] = (byte)(255 * tr.ambientLightVector[1]);
  359. data[0][i][2] = (byte)(255 * tr.ambientLightVector[2]);
  360. data[0][i][alpha] = 255;
  361. }
  362. const byte *pics[6];
  363. for ( i = 0 ; i < 6 ; i++ ) {
  364. pics[i] = data[0][0];
  365. }
  366. // this must be a cube map for fragment programs to simply substitute for the normalization cube map
  367. image->GenerateCubeImage( pics, 2, TF_DEFAULT, true, TD_HIGH_QUALITY );
  368. }
  369. static void CreateSquareLight( void ) {
  370. byte *buffer;
  371. int x, y;
  372. int dx, dy;
  373. int d;
  374. int width, height;
  375. width = height = 128;
  376. buffer = (byte *)R_StaticAlloc( 128 * 128 * 4 );
  377. for ( x = 0 ; x < 128 ; x++ ) {
  378. if ( x < 32 ) {
  379. dx = 32 - x;
  380. } else if ( x > 96 ) {
  381. dx = x - 96;
  382. } else {
  383. dx = 0;
  384. }
  385. for ( y = 0 ; y < 128 ; y++ ) {
  386. if ( y < 32 ) {
  387. dy = 32 - y;
  388. } else if ( y > 96 ) {
  389. dy = y - 96;
  390. } else {
  391. dy = 0;
  392. }
  393. d = (byte)idMath::Sqrt( dx * dx + dy * dy );
  394. if ( d > 32 ) {
  395. d = 32;
  396. }
  397. d = 255 - d * 8;
  398. if ( d < 0 ) {
  399. d = 0;
  400. }
  401. buffer[(y*128+x)*4+0] =
  402. buffer[(y*128+x)*4+1] =
  403. buffer[(y*128+x)*4+2] = d;
  404. buffer[(y*128+x)*4+3] = 255;
  405. }
  406. }
  407. R_WriteTGA( "lights/squarelight.tga", buffer, width, height );
  408. R_StaticFree( buffer );
  409. }
  410. static void CreateFlashOff( void ) {
  411. byte *buffer;
  412. int x, y;
  413. int d;
  414. int width, height;
  415. width = 256;
  416. height = 4;
  417. buffer = (byte *)R_StaticAlloc( width * height * 4 );
  418. for ( x = 0 ; x < width ; x++ ) {
  419. for ( y = 0 ; y < height ; y++ ) {
  420. d = 255 - ( x * 256 / width );
  421. buffer[(y*width+x)*4+0] =
  422. buffer[(y*width+x)*4+1] =
  423. buffer[(y*width+x)*4+2] = d;
  424. buffer[(y*width+x)*4+3] = 255;
  425. }
  426. }
  427. R_WriteTGA( "lights/flashoff.tga", buffer, width, height );
  428. R_StaticFree( buffer );
  429. }
  430. /*
  431. ===============
  432. CreatePitFogImage
  433. ===============
  434. */
  435. void CreatePitFogImage( void ) {
  436. byte data[16][16][4];
  437. int i, j;
  438. memset( data, 0, sizeof( data ) );
  439. for ( i = 0 ; i < 16 ; i++ ) {
  440. int a;
  441. #if 0
  442. if ( i > 14 ) {
  443. a = 0;
  444. } else
  445. #endif
  446. {
  447. a = i * 255 / 15;
  448. if ( a > 255 ) {
  449. a = 255;
  450. }
  451. }
  452. for ( j = 0 ; j < 16 ; j++ ) {
  453. data[j][i][0] =
  454. data[j][i][1] =
  455. data[j][i][2] = 255;
  456. data[j][i][3] = a;
  457. }
  458. }
  459. R_WriteTGA( "shapes/pitFalloff.tga", data[0][0], 16, 16 );
  460. }
  461. /*
  462. ===============
  463. CreatealphaSquareImage
  464. ===============
  465. */
  466. void CreatealphaSquareImage( void ) {
  467. byte data[16][16][4];
  468. int i, j;
  469. for ( i = 0 ; i < 16 ; i++ ) {
  470. int a;
  471. for ( j = 0 ; j < 16 ; j++ ) {
  472. if ( i == 0 || i == 15 || j == 0 || j == 15 ) {
  473. a = 0;
  474. } else {
  475. a = 255;
  476. }
  477. data[j][i][0] =
  478. data[j][i][1] =
  479. data[j][i][2] = 255;
  480. data[j][i][3] = a;
  481. }
  482. }
  483. R_WriteTGA( "shapes/alphaSquare.tga", data[0][0], 16, 16 );
  484. }
  485. #define NORMAL_MAP_SIZE 32
  486. /*** NORMALIZATION CUBE MAP CONSTRUCTION ***/
  487. /* Given a cube map face index, cube map size, and integer 2D face position,
  488. * return the cooresponding normalized vector.
  489. */
  490. static void getCubeVector(int i, int cubesize, int x, int y, float *vector) {
  491. float s, t, sc, tc, mag;
  492. s = ((float)x + 0.5) / (float)cubesize;
  493. t = ((float)y + 0.5) / (float)cubesize;
  494. sc = s*2.0 - 1.0;
  495. tc = t*2.0 - 1.0;
  496. switch (i) {
  497. case 0:
  498. vector[0] = 1.0;
  499. vector[1] = -tc;
  500. vector[2] = -sc;
  501. break;
  502. case 1:
  503. vector[0] = -1.0;
  504. vector[1] = -tc;
  505. vector[2] = sc;
  506. break;
  507. case 2:
  508. vector[0] = sc;
  509. vector[1] = 1.0;
  510. vector[2] = tc;
  511. break;
  512. case 3:
  513. vector[0] = sc;
  514. vector[1] = -1.0;
  515. vector[2] = -tc;
  516. break;
  517. case 4:
  518. vector[0] = sc;
  519. vector[1] = -tc;
  520. vector[2] = 1.0;
  521. break;
  522. case 5:
  523. vector[0] = -sc;
  524. vector[1] = -tc;
  525. vector[2] = -1.0;
  526. break;
  527. }
  528. mag = idMath::InvSqrt(vector[0]*vector[0] + vector[1]*vector[1] + vector[2]*vector[2]);
  529. vector[0] *= mag;
  530. vector[1] *= mag;
  531. vector[2] *= mag;
  532. }
  533. /* Initialize a cube map texture object that generates RGB values
  534. * that when expanded to a [-1,1] range in the register combiners
  535. * form a normalized vector matching the per-pixel vector used to
  536. * access the cube map.
  537. */
  538. static void makeNormalizeVectorCubeMap( idImage *image ) {
  539. float vector[3];
  540. int i, x, y;
  541. byte *pixels[6];
  542. int size;
  543. size = NORMAL_MAP_SIZE;
  544. pixels[0] = (GLubyte*) Mem_Alloc(size*size*4*6);
  545. for (i = 0; i < 6; i++) {
  546. pixels[i] = pixels[0] + i*size*size*4;
  547. for (y = 0; y < size; y++) {
  548. for (x = 0; x < size; x++) {
  549. getCubeVector(i, size, x, y, vector);
  550. pixels[i][4*(y*size+x) + 0] = (byte)(128 + 127*vector[0]);
  551. pixels[i][4*(y*size+x) + 1] = (byte)(128 + 127*vector[1]);
  552. pixels[i][4*(y*size+x) + 2] = (byte)(128 + 127*vector[2]);
  553. pixels[i][4*(y*size+x) + 3] = 255;
  554. }
  555. }
  556. }
  557. image->GenerateCubeImage( (const byte **)pixels, size,
  558. TF_LINEAR, false, TD_HIGH_QUALITY );
  559. Mem_Free(pixels[0]);
  560. }
  561. /*
  562. ================
  563. R_CreateNoFalloffImage
  564. This is a solid white texture that is zero clamped.
  565. ================
  566. */
  567. static void R_CreateNoFalloffImage( idImage *image ) {
  568. int x,y;
  569. byte data[16][FALLOFF_TEXTURE_SIZE][4];
  570. memset( data, 0, sizeof( data ) );
  571. for (x=1 ; x<FALLOFF_TEXTURE_SIZE-1 ; x++) {
  572. for (y=1 ; y<15 ; y++) {
  573. data[y][x][0] = 255;
  574. data[y][x][1] = 255;
  575. data[y][x][2] = 255;
  576. data[y][x][3] = 255;
  577. }
  578. }
  579. image->GenerateImage( (byte *)data, FALLOFF_TEXTURE_SIZE, 16,
  580. TF_DEFAULT, false, TR_CLAMP_TO_ZERO, TD_HIGH_QUALITY );
  581. }
  582. /*
  583. ================
  584. R_FogImage
  585. We calculate distance correctly in two planes, but the
  586. third will still be projection based
  587. ================
  588. */
  589. const int FOG_SIZE = 128;
  590. void R_FogImage( idImage *image ) {
  591. int x,y;
  592. byte data[FOG_SIZE][FOG_SIZE][4];
  593. int b;
  594. float step[256];
  595. int i;
  596. float remaining = 1.0;
  597. for ( i = 0 ; i < 256 ; i++ ) {
  598. step[i] = remaining;
  599. remaining *= 0.982f;
  600. }
  601. for (x=0 ; x<FOG_SIZE ; x++) {
  602. for (y=0 ; y<FOG_SIZE ; y++) {
  603. float d;
  604. d = idMath::Sqrt( (x - FOG_SIZE/2) * (x - FOG_SIZE/2)
  605. + (y - FOG_SIZE/2) * (y - FOG_SIZE / 2) );
  606. d /= FOG_SIZE/2-1;
  607. b = (byte)(d * 255);
  608. if ( b <= 0 ) {
  609. b = 0;
  610. } else if ( b > 255 ) {
  611. b = 255;
  612. }
  613. b = (byte)(255 * ( 1.0 - step[b] ));
  614. if ( x == 0 || x == FOG_SIZE-1 || y == 0 || y == FOG_SIZE-1 ) {
  615. b = 255; // avoid clamping issues
  616. }
  617. data[y][x][0] =
  618. data[y][x][1] =
  619. data[y][x][2] = 255;
  620. data[y][x][3] = b;
  621. }
  622. }
  623. image->GenerateImage( (byte *)data, FOG_SIZE, FOG_SIZE,
  624. TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY );
  625. }
  626. /*
  627. ================
  628. FogFraction
  629. Height values below zero are inside the fog volume
  630. ================
  631. */
  632. static const float RAMP_RANGE = 8;
  633. static const float DEEP_RANGE = -30;
  634. static float FogFraction( float viewHeight, float targetHeight ) {
  635. float total = idMath::Fabs( targetHeight - viewHeight );
  636. // return targetHeight >= 0 ? 0 : 1.0;
  637. // only ranges that cross the ramp range are special
  638. if ( targetHeight > 0 && viewHeight > 0 ) {
  639. return 0.0;
  640. }
  641. if ( targetHeight < -RAMP_RANGE && viewHeight < -RAMP_RANGE ) {
  642. return 1.0;
  643. }
  644. float above;
  645. if ( targetHeight > 0 ) {
  646. above = targetHeight;
  647. } else if ( viewHeight > 0 ) {
  648. above = viewHeight;
  649. } else {
  650. above = 0;
  651. }
  652. float rampTop, rampBottom;
  653. if ( viewHeight > targetHeight ) {
  654. rampTop = viewHeight;
  655. rampBottom = targetHeight;
  656. } else {
  657. rampTop = targetHeight;
  658. rampBottom = viewHeight;
  659. }
  660. if ( rampTop > 0 ) {
  661. rampTop = 0;
  662. }
  663. if ( rampBottom < -RAMP_RANGE ) {
  664. rampBottom = -RAMP_RANGE;
  665. }
  666. float rampSlope = 1.0 / RAMP_RANGE;
  667. if ( !total ) {
  668. return -viewHeight * rampSlope;
  669. }
  670. float ramp = ( 1.0 - ( rampTop * rampSlope + rampBottom * rampSlope ) * -0.5 ) * ( rampTop - rampBottom );
  671. float frac = ( total - above - ramp ) / total;
  672. // after it gets moderately deep, always use full value
  673. float deepest = viewHeight < targetHeight ? viewHeight : targetHeight;
  674. float deepFrac = deepest / DEEP_RANGE;
  675. if ( deepFrac >= 1.0 ) {
  676. return 1.0;
  677. }
  678. frac = frac * ( 1.0 - deepFrac ) + deepFrac;
  679. return frac;
  680. }
  681. /*
  682. ================
  683. R_FogEnterImage
  684. Modulate the fog alpha density based on the distance of the
  685. start and end points to the terminator plane
  686. ================
  687. */
  688. void R_FogEnterImage( idImage *image ) {
  689. int x,y;
  690. byte data[FOG_ENTER_SIZE][FOG_ENTER_SIZE][4];
  691. int b;
  692. for (x=0 ; x<FOG_ENTER_SIZE ; x++) {
  693. for (y=0 ; y<FOG_ENTER_SIZE ; y++) {
  694. float d;
  695. d = FogFraction( x - (FOG_ENTER_SIZE / 2), y - (FOG_ENTER_SIZE / 2) );
  696. b = (byte)(d * 255);
  697. if ( b <= 0 ) {
  698. b = 0;
  699. } else if ( b > 255 ) {
  700. b = 255;
  701. }
  702. data[y][x][0] =
  703. data[y][x][1] =
  704. data[y][x][2] = 255;
  705. data[y][x][3] = b;
  706. }
  707. }
  708. // if mipmapped, acutely viewed surfaces fade wrong
  709. image->GenerateImage( (byte *)data, FOG_ENTER_SIZE, FOG_ENTER_SIZE,
  710. TF_LINEAR, false, TR_CLAMP, TD_HIGH_QUALITY );
  711. }
  712. /*
  713. ================
  714. R_QuadraticImage
  715. ================
  716. */
  717. static const int QUADRATIC_WIDTH = 32;
  718. static const int QUADRATIC_HEIGHT = 4;
  719. void R_QuadraticImage( idImage *image ) {
  720. int x,y;
  721. byte data[QUADRATIC_HEIGHT][QUADRATIC_WIDTH][4];
  722. int b;
  723. for (x=0 ; x<QUADRATIC_WIDTH ; x++) {
  724. for (y=0 ; y<QUADRATIC_HEIGHT ; y++) {
  725. float d;
  726. d = x - (QUADRATIC_WIDTH/2 - 0.5);
  727. d = idMath::Fabs( d );
  728. d -= 0.5;
  729. d /= QUADRATIC_WIDTH/2;
  730. d = 1.0 - d;
  731. d = d * d;
  732. b = (byte)(d * 255);
  733. if ( b <= 0 ) {
  734. b = 0;
  735. } else if ( b > 255 ) {
  736. b = 255;
  737. }
  738. data[y][x][0] =
  739. data[y][x][1] =
  740. data[y][x][2] = b;
  741. data[y][x][3] = 255;
  742. }
  743. }
  744. image->GenerateImage( (byte *)data, QUADRATIC_WIDTH, QUADRATIC_HEIGHT,
  745. TF_DEFAULT, false, TR_CLAMP, TD_HIGH_QUALITY );
  746. }
  747. //=====================================================================
  748. typedef struct {
  749. char *name;
  750. int minimize, maximize;
  751. } filterName_t;
  752. /*
  753. ===============
  754. ChangeTextureFilter
  755. This resets filtering on all loaded images
  756. New images will automatically pick up the current values.
  757. ===============
  758. */
  759. void idImageManager::ChangeTextureFilter( void ) {
  760. int i;
  761. idImage *glt;
  762. const char *string;
  763. static filterName_t textureFilters[] = {
  764. {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
  765. {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR},
  766. {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
  767. {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
  768. {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
  769. {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}
  770. };
  771. // if these are changed dynamically, it will force another ChangeTextureFilter
  772. image_filter.ClearModified();
  773. image_anisotropy.ClearModified();
  774. image_lodbias.ClearModified();
  775. string = image_filter.GetString();
  776. for ( i = 0; i < 6; i++ ) {
  777. if ( !idStr::Icmp( textureFilters[i].name, string ) ) {
  778. break;
  779. }
  780. }
  781. if ( i == 6 ) {
  782. common->Warning( "bad r_textureFilter: '%s'", string);
  783. // default to LINEAR_MIPMAP_NEAREST
  784. i = 0;
  785. }
  786. // set the values for future images
  787. textureMinFilter = textureFilters[i].minimize;
  788. textureMaxFilter = textureFilters[i].maximize;
  789. textureAnisotropy = image_anisotropy.GetFloat();
  790. if ( textureAnisotropy < 1 ) {
  791. textureAnisotropy = 1;
  792. } else if ( textureAnisotropy > glConfig.maxTextureAnisotropy ) {
  793. textureAnisotropy = glConfig.maxTextureAnisotropy;
  794. }
  795. textureLODBias = image_lodbias.GetFloat();
  796. // change all the existing mipmap texture objects with default filtering
  797. for ( i = 0 ; i < images.Num() ; i++ ) {
  798. unsigned int texEnum = GL_TEXTURE_2D;
  799. glt = images[ i ];
  800. switch( glt->type ) {
  801. case TT_2D:
  802. texEnum = GL_TEXTURE_2D;
  803. break;
  804. case TT_3D:
  805. texEnum = GL_TEXTURE_3D;
  806. break;
  807. case TT_CUBIC:
  808. texEnum = GL_TEXTURE_CUBE_MAP_EXT;
  809. break;
  810. }
  811. // make sure we don't start a background load
  812. if ( glt->texnum == idImage::TEXTURE_NOT_LOADED ) {
  813. continue;
  814. }
  815. glt->Bind();
  816. if ( glt->filter == TF_DEFAULT ) {
  817. qglTexParameterf(texEnum, GL_TEXTURE_MIN_FILTER, globalImages->textureMinFilter );
  818. qglTexParameterf(texEnum, GL_TEXTURE_MAG_FILTER, globalImages->textureMaxFilter );
  819. }
  820. if ( glConfig.anisotropicAvailable ) {
  821. qglTexParameterf(texEnum, GL_TEXTURE_MAX_ANISOTROPY_EXT, globalImages->textureAnisotropy );
  822. }
  823. if ( glConfig.textureLODBiasAvailable ) {
  824. qglTexParameterf(texEnum, GL_TEXTURE_LOD_BIAS_EXT, globalImages->textureLODBias );
  825. }
  826. }
  827. }
  828. /*
  829. ===============
  830. idImage::Reload
  831. ===============
  832. */
  833. void idImage::Reload( bool checkPrecompressed, bool force ) {
  834. // always regenerate functional images
  835. if ( generatorFunction ) {
  836. common->DPrintf( "regenerating %s.\n", imgName.c_str() );
  837. generatorFunction( this );
  838. return;
  839. }
  840. // check file times
  841. if ( !force ) {
  842. ID_TIME_T current;
  843. if ( cubeFiles != CF_2D ) {
  844. R_LoadCubeImages( imgName, cubeFiles, NULL, NULL, &current );
  845. } else {
  846. // get the current values
  847. R_LoadImageProgram( imgName, NULL, NULL, NULL, &current );
  848. }
  849. if ( current <= timestamp ) {
  850. return;
  851. }
  852. }
  853. common->DPrintf( "reloading %s.\n", imgName.c_str() );
  854. PurgeImage();
  855. // force no precompressed image check, which will cause it to be reloaded
  856. // from source, and another precompressed file generated.
  857. // Load is from the front end, so the back end must be synced
  858. ActuallyLoadImage( checkPrecompressed, false );
  859. }
  860. /*
  861. ===============
  862. R_ReloadImages_f
  863. Regenerate all images that came directly from files that have changed, so
  864. any saved changes will show up in place.
  865. New r_texturesize/r_texturedepth variables will take effect on reload
  866. reloadImages <all>
  867. ===============
  868. */
  869. void R_ReloadImages_f( const idCmdArgs &args ) {
  870. int i;
  871. idImage *image;
  872. bool all;
  873. bool checkPrecompressed;
  874. // this probably isn't necessary...
  875. globalImages->ChangeTextureFilter();
  876. all = false;
  877. checkPrecompressed = false; // if we are doing this as a vid_restart, look for precompressed like normal
  878. if ( args.Argc() == 2 ) {
  879. if ( !idStr::Icmp( args.Argv(1), "all" ) ) {
  880. all = true;
  881. } else if ( !idStr::Icmp( args.Argv(1), "reload" ) ) {
  882. all = true;
  883. checkPrecompressed = true;
  884. } else {
  885. common->Printf( "USAGE: reloadImages <all>\n" );
  886. return;
  887. }
  888. }
  889. for ( i = 0 ; i < globalImages->images.Num() ; i++ ) {
  890. image = globalImages->images[ i ];
  891. image->Reload( checkPrecompressed, all );
  892. }
  893. }
  894. typedef struct {
  895. idImage *image;
  896. int size;
  897. } sortedImage_t;
  898. /*
  899. =======================
  900. R_QsortImageSizes
  901. =======================
  902. */
  903. static int R_QsortImageSizes( const void *a, const void *b ) {
  904. const sortedImage_t *ea, *eb;
  905. ea = (sortedImage_t *)a;
  906. eb = (sortedImage_t *)b;
  907. if ( ea->size > eb->size ) {
  908. return -1;
  909. }
  910. if ( ea->size < eb->size ) {
  911. return 1;
  912. }
  913. return idStr::Icmp( ea->image->imgName, eb->image->imgName );
  914. }
  915. /*
  916. ===============
  917. R_ListImages_f
  918. ===============
  919. */
  920. void R_ListImages_f( const idCmdArgs &args ) {
  921. int i, j, partialSize;
  922. idImage *image;
  923. int totalSize;
  924. int count = 0;
  925. int matchTag = 0;
  926. bool uncompressedOnly = false;
  927. bool unloaded = false;
  928. bool partial = false;
  929. bool cached = false;
  930. bool uncached = false;
  931. bool failed = false;
  932. bool touched = false;
  933. bool sorted = false;
  934. bool duplicated = false;
  935. bool byClassification = false;
  936. bool overSized = false;
  937. if ( args.Argc() == 1 ) {
  938. } else if ( args.Argc() == 2 ) {
  939. if ( idStr::Icmp( args.Argv( 1 ), "uncompressed" ) == 0 ) {
  940. uncompressedOnly = true;
  941. } else if ( idStr::Icmp( args.Argv( 1 ), "sorted" ) == 0 ) {
  942. sorted = true;
  943. } else if ( idStr::Icmp( args.Argv( 1 ), "partial" ) == 0 ) {
  944. partial = true;
  945. } else if ( idStr::Icmp( args.Argv( 1 ), "unloaded" ) == 0 ) {
  946. unloaded = true;
  947. } else if ( idStr::Icmp( args.Argv( 1 ), "cached" ) == 0 ) {
  948. cached = true;
  949. } else if ( idStr::Icmp( args.Argv( 1 ), "uncached" ) == 0 ) {
  950. uncached = true;
  951. } else if ( idStr::Icmp( args.Argv( 1 ), "tagged" ) == 0 ) {
  952. matchTag = 1;
  953. } else if ( idStr::Icmp( args.Argv( 1 ), "duplicated" ) == 0 ) {
  954. duplicated = true;
  955. } else if ( idStr::Icmp( args.Argv( 1 ), "touched" ) == 0 ) {
  956. touched = true;
  957. } else if ( idStr::Icmp( args.Argv( 1 ), "classify" ) == 0 ) {
  958. byClassification = true;
  959. sorted = true;
  960. } else if ( idStr::Icmp( args.Argv( 1 ), "oversized" ) == 0 ) {
  961. byClassification = true;
  962. sorted = true;
  963. overSized = true;
  964. } else {
  965. failed = true;
  966. }
  967. } else {
  968. failed = true;
  969. }
  970. if ( failed ) {
  971. common->Printf( "usage: listImages [ sorted | partial | unloaded | cached | uncached | tagged | duplicated | touched | classify | showOverSized ]\n" );
  972. return;
  973. }
  974. const char *header = " -w-- -h-- filt -fmt-- wrap size --name-------\n";
  975. common->Printf( "\n%s", header );
  976. totalSize = 0;
  977. sortedImage_t *sortedArray = (sortedImage_t *)alloca( sizeof( sortedImage_t ) * globalImages->images.Num() );
  978. for ( i = 0 ; i < globalImages->images.Num() ; i++ ) {
  979. image = globalImages->images[ i ];
  980. if ( uncompressedOnly ) {
  981. if ( ( image->internalFormat >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT && image->internalFormat <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT )
  982. || image->internalFormat == GL_COLOR_INDEX8_EXT ) {
  983. continue;
  984. }
  985. }
  986. if ( matchTag && image->classification != matchTag ) {
  987. continue;
  988. }
  989. if ( unloaded && image->texnum != idImage::TEXTURE_NOT_LOADED ) {
  990. continue;
  991. }
  992. if ( partial && !image->isPartialImage ) {
  993. continue;
  994. }
  995. if ( cached && ( !image->partialImage || image->texnum == idImage::TEXTURE_NOT_LOADED ) ) {
  996. continue;
  997. }
  998. if ( uncached && ( !image->partialImage || image->texnum != idImage::TEXTURE_NOT_LOADED ) ) {
  999. continue;
  1000. }
  1001. // only print duplicates (from mismatched wrap / clamp, etc)
  1002. if ( duplicated ) {
  1003. int j;
  1004. for ( j = i+1 ; j < globalImages->images.Num() ; j++ ) {
  1005. if ( idStr::Icmp( image->imgName, globalImages->images[ j ]->imgName ) == 0 ) {
  1006. break;
  1007. }
  1008. }
  1009. if ( j == globalImages->images.Num() ) {
  1010. continue;
  1011. }
  1012. }
  1013. // "listimages touched" will list only images bound since the last "listimages touched" call
  1014. if ( touched ) {
  1015. if ( image->bindCount == 0 ) {
  1016. continue;
  1017. }
  1018. image->bindCount = 0;
  1019. }
  1020. if ( sorted ) {
  1021. sortedArray[count].image = image;
  1022. sortedArray[count].size = image->StorageSize();
  1023. } else {
  1024. common->Printf( "%4i:", i );
  1025. image->Print();
  1026. }
  1027. totalSize += image->StorageSize();
  1028. count++;
  1029. }
  1030. if ( sorted ) {
  1031. qsort( sortedArray, count, sizeof( sortedImage_t ), R_QsortImageSizes );
  1032. partialSize = 0;
  1033. for ( i = 0 ; i < count ; i++ ) {
  1034. common->Printf( "%4i:", i );
  1035. sortedArray[i].image->Print();
  1036. partialSize += sortedArray[i].image->StorageSize();
  1037. if ( ( (i+1) % 10 ) == 0 ) {
  1038. common->Printf( "-------- %5.1f of %5.1f megs --------\n",
  1039. partialSize / (1024*1024.0), totalSize / (1024*1024.0) );
  1040. }
  1041. }
  1042. }
  1043. common->Printf( "%s", header );
  1044. common->Printf( " %i images (%i total)\n", count, globalImages->images.Num() );
  1045. common->Printf( " %5.1f total megabytes of images\n\n\n", totalSize / (1024*1024.0) );
  1046. if ( byClassification ) {
  1047. idList< int > classifications[IC_COUNT];
  1048. for ( i = 0 ; i < count ; i++ ) {
  1049. int cl = ClassifyImage( sortedArray[i].image->imgName );
  1050. classifications[ cl ].Append( i );
  1051. }
  1052. for ( i = 0; i < IC_COUNT; i++ ) {
  1053. partialSize = 0;
  1054. idList< int > overSizedList;
  1055. for ( j = 0; j < classifications[ i ].Num(); j++ ) {
  1056. partialSize += sortedArray[ classifications[ i ][ j ] ].image->StorageSize();
  1057. if ( overSized ) {
  1058. if ( sortedArray[ classifications[ i ][ j ] ].image->uploadWidth > IC_Info[i].maxWidth && sortedArray[ classifications[ i ][ j ] ].image->uploadHeight > IC_Info[i].maxHeight ) {
  1059. overSizedList.Append( classifications[ i ][ j ] );
  1060. }
  1061. }
  1062. }
  1063. common->Printf ( " Classification %s contains %i images using %5.1f megabytes\n", IC_Info[i].desc, classifications[i].Num(), partialSize / ( 1024*1024.0 ) );
  1064. if ( overSized && overSizedList.Num() ) {
  1065. common->Printf( " The following images may be oversized\n" );
  1066. for ( j = 0; j < overSizedList.Num(); j++ ) {
  1067. common->Printf( " " );
  1068. sortedArray[ overSizedList[ j ] ].image->Print();
  1069. common->Printf( "\n" );
  1070. }
  1071. }
  1072. }
  1073. }
  1074. }
  1075. /*
  1076. ==================
  1077. SetNormalPalette
  1078. Create a 256 color palette to be used by compressed normal maps
  1079. ==================
  1080. */
  1081. void idImageManager::SetNormalPalette( void ) {
  1082. int i, j;
  1083. idVec3 v;
  1084. float t;
  1085. //byte temptable[768];
  1086. byte *temptable = compressedPalette;
  1087. int compressedToOriginal[16];
  1088. // make an ad-hoc separable compression mapping scheme
  1089. for ( i = 0 ; i < 8 ; i++ ) {
  1090. float f, y;
  1091. f = ( i + 1 ) / 8.5;
  1092. y = idMath::Sqrt( 1.0 - f * f );
  1093. y = 1.0 - y;
  1094. compressedToOriginal[7-i] = 127 - (int)( y * 127 + 0.5 );
  1095. compressedToOriginal[8+i] = 128 + (int)( y * 127 + 0.5 );
  1096. }
  1097. for ( i = 0 ; i < 256 ; i++ ) {
  1098. if ( i <= compressedToOriginal[0] ) {
  1099. originalToCompressed[i] = 0;
  1100. } else if ( i >= compressedToOriginal[15] ) {
  1101. originalToCompressed[i] = 15;
  1102. } else {
  1103. for ( j = 0 ; j < 14 ; j++ ) {
  1104. if ( i <= compressedToOriginal[j+1] ) {
  1105. break;
  1106. }
  1107. }
  1108. if ( i - compressedToOriginal[j] < compressedToOriginal[j+1] - i ) {
  1109. originalToCompressed[i] = j;
  1110. } else {
  1111. originalToCompressed[i] = j + 1;
  1112. }
  1113. }
  1114. }
  1115. #if 0
  1116. for ( i = 0; i < 16; i++ ) {
  1117. for ( j = 0 ; j < 16 ; j++ ) {
  1118. v[0] = ( i - 7.5 ) / 8;
  1119. v[1] = ( j - 7.5 ) / 8;
  1120. t = 1.0 - ( v[0]*v[0] + v[1]*v[1] );
  1121. if ( t < 0 ) {
  1122. t = 0;
  1123. }
  1124. v[2] = idMath::Sqrt( t );
  1125. temptable[(i*16+j)*3+0] = 128 + floor( 127 * v[0] + 0.5 );
  1126. temptable[(i*16+j)*3+1] = 128 + floor( 127 * v[1] );
  1127. temptable[(i*16+j)*3+2] = 128 + floor( 127 * v[2] );
  1128. }
  1129. }
  1130. #else
  1131. for ( i = 0; i < 16; i++ ) {
  1132. for ( j = 0 ; j < 16 ; j++ ) {
  1133. v[0] = ( compressedToOriginal[i] - 127.5 ) / 128;
  1134. v[1] = ( compressedToOriginal[j] - 127.5 ) / 128;
  1135. t = 1.0 - ( v[0]*v[0] + v[1]*v[1] );
  1136. if ( t < 0 ) {
  1137. t = 0;
  1138. }
  1139. v[2] = idMath::Sqrt( t );
  1140. temptable[(i*16+j)*3+0] = (byte)(128 + floor( 127 * v[0] + 0.5 ));
  1141. temptable[(i*16+j)*3+1] = (byte)(128 + floor( 127 * v[1] ));
  1142. temptable[(i*16+j)*3+2] = (byte)(128 + floor( 127 * v[2] ));
  1143. }
  1144. }
  1145. #endif
  1146. // color 255 will be the "nullnormal" color for no reflection
  1147. temptable[255*3+0] =
  1148. temptable[255*3+1] =
  1149. temptable[255*3+2] = 128;
  1150. if ( !glConfig.sharedTexturePaletteAvailable ) {
  1151. return;
  1152. }
  1153. qglColorTableEXT( GL_SHARED_TEXTURE_PALETTE_EXT,
  1154. GL_RGB,
  1155. 256,
  1156. GL_RGB,
  1157. GL_UNSIGNED_BYTE,
  1158. temptable );
  1159. qglEnable( GL_SHARED_TEXTURE_PALETTE_EXT );
  1160. }
  1161. /*
  1162. ==============
  1163. AllocImage
  1164. Allocates an idImage, adds it to the list,
  1165. copies the name, and adds it to the hash chain.
  1166. ==============
  1167. */
  1168. idImage *idImageManager::AllocImage( const char *name ) {
  1169. idImage *image;
  1170. int hash;
  1171. if (strlen(name) >= MAX_IMAGE_NAME ) {
  1172. common->Error ("idImageManager::AllocImage: \"%s\" is too long\n", name);
  1173. }
  1174. hash = idStr( name ).FileNameHash();
  1175. image = new idImage;
  1176. images.Append( image );
  1177. image->hashNext = imageHashTable[hash];
  1178. imageHashTable[hash] = image;
  1179. image->imgName = name;
  1180. return image;
  1181. }
  1182. /*
  1183. ==================
  1184. ImageFromFunction
  1185. Images that are procedurally generated are allways specified
  1186. with a callback which must work at any time, allowing the OpenGL
  1187. system to be completely regenerated if needed.
  1188. ==================
  1189. */
  1190. idImage *idImageManager::ImageFromFunction( const char *_name, void (*generatorFunction)( idImage *image ) ) {
  1191. idStr name;
  1192. idImage *image;
  1193. int hash;
  1194. if ( !name ) {
  1195. common->FatalError( "idImageManager::ImageFromFunction: NULL name" );
  1196. }
  1197. // strip any .tga file extensions from anywhere in the _name
  1198. name = _name;
  1199. name.Replace( ".tga", "" );
  1200. name.BackSlashesToSlashes();
  1201. // see if the image already exists
  1202. hash = name.FileNameHash();
  1203. for ( image = imageHashTable[hash] ; image; image = image->hashNext ) {
  1204. if ( name.Icmp( image->imgName ) == 0 ) {
  1205. if ( image->generatorFunction != generatorFunction ) {
  1206. common->DPrintf( "WARNING: reused image %s with mixed generators\n", name.c_str() );
  1207. }
  1208. return image;
  1209. }
  1210. }
  1211. // create the image and issue the callback
  1212. image = AllocImage( name );
  1213. image->generatorFunction = generatorFunction;
  1214. if ( image_preload.GetBool() ) {
  1215. // check for precompressed, load is from the front end
  1216. image->referencedOutsideLevelLoad = true;
  1217. image->ActuallyLoadImage( true, false );
  1218. }
  1219. return image;
  1220. }
  1221. /*
  1222. ===============
  1223. ImageFromFile
  1224. Finds or loads the given image, always returning a valid image pointer.
  1225. Loading of the image may be deferred for dynamic loading.
  1226. ==============
  1227. */
  1228. idImage *idImageManager::ImageFromFile( const char *_name, textureFilter_t filter, bool allowDownSize,
  1229. textureRepeat_t repeat, textureDepth_t depth, cubeFiles_t cubeMap ) {
  1230. idStr name;
  1231. idImage *image;
  1232. int hash;
  1233. if ( !_name || !_name[0] || idStr::Icmp( _name, "default" ) == 0 || idStr::Icmp( _name, "_default" ) == 0 ) {
  1234. declManager->MediaPrint( "DEFAULTED\n" );
  1235. return globalImages->defaultImage;
  1236. }
  1237. // strip any .tga file extensions from anywhere in the _name, including image program parameters
  1238. name = _name;
  1239. name.Replace( ".tga", "" );
  1240. name.BackSlashesToSlashes();
  1241. //
  1242. // see if the image is already loaded, unless we
  1243. // are in a reloadImages call
  1244. //
  1245. hash = name.FileNameHash();
  1246. for ( image = imageHashTable[hash]; image; image = image->hashNext ) {
  1247. if ( name.Icmp( image->imgName ) == 0 ) {
  1248. // the built in's, like _white and _flat always match the other options
  1249. if ( name[0] == '_' ) {
  1250. return image;
  1251. }
  1252. if ( image->cubeFiles != cubeMap ) {
  1253. common->Error( "Image '%s' has been referenced with conflicting cube map states", _name );
  1254. }
  1255. if ( image->filter != filter || image->repeat != repeat ) {
  1256. // we might want to have the system reset these parameters on every bind and
  1257. // share the image data
  1258. continue;
  1259. }
  1260. if ( image->allowDownSize == allowDownSize && image->depth == depth ) {
  1261. // note that it is used this level load
  1262. image->levelLoadReferenced = true;
  1263. if ( image->partialImage != NULL ) {
  1264. image->partialImage->levelLoadReferenced = true;
  1265. }
  1266. return image;
  1267. }
  1268. // the same image is being requested, but with a different allowDownSize or depth
  1269. // so pick the highest of the two and reload the old image with those parameters
  1270. if ( !image->allowDownSize ) {
  1271. allowDownSize = false;
  1272. }
  1273. if ( image->depth > depth ) {
  1274. depth = image->depth;
  1275. }
  1276. if ( image->allowDownSize == allowDownSize && image->depth == depth ) {
  1277. // the already created one is already the highest quality
  1278. image->levelLoadReferenced = true;
  1279. if ( image->partialImage != NULL ) {
  1280. image->partialImage->levelLoadReferenced = true;
  1281. }
  1282. return image;
  1283. }
  1284. image->allowDownSize = allowDownSize;
  1285. image->depth = depth;
  1286. image->levelLoadReferenced = true;
  1287. if ( image->partialImage != NULL ) {
  1288. image->partialImage->levelLoadReferenced = true;
  1289. }
  1290. if ( image_preload.GetBool() && !insideLevelLoad ) {
  1291. image->referencedOutsideLevelLoad = true;
  1292. image->ActuallyLoadImage( true, false ); // check for precompressed, load is from front end
  1293. declManager->MediaPrint( "%ix%i %s (reload for mixed referneces)\n", image->uploadWidth, image->uploadHeight, image->imgName.c_str() );
  1294. }
  1295. return image;
  1296. }
  1297. }
  1298. //
  1299. // create a new image
  1300. //
  1301. image = AllocImage( name );
  1302. // HACK: to allow keep fonts from being mip'd, as new ones will be introduced with localization
  1303. // this keeps us from having to make a material for each font tga
  1304. if ( name.Find( "fontImage_") >= 0 ) {
  1305. allowDownSize = false;
  1306. }
  1307. image->allowDownSize = allowDownSize;
  1308. image->repeat = repeat;
  1309. image->depth = depth;
  1310. image->type = TT_2D;
  1311. image->cubeFiles = cubeMap;
  1312. image->filter = filter;
  1313. image->levelLoadReferenced = true;
  1314. // also create a shrunken version if we are going to dynamically cache the full size image
  1315. if ( image->ShouldImageBePartialCached() ) {
  1316. // if we only loaded part of the file, create a new idImage for the shrunken version
  1317. image->partialImage = new idImage;
  1318. image->partialImage->allowDownSize = allowDownSize;
  1319. image->partialImage->repeat = repeat;
  1320. image->partialImage->depth = depth;
  1321. image->partialImage->type = TT_2D;
  1322. image->partialImage->cubeFiles = cubeMap;
  1323. image->partialImage->filter = filter;
  1324. image->partialImage->levelLoadReferenced = true;
  1325. // we don't bother hooking this into the hash table for lookup, but we do add it to the manager
  1326. // list for listImages
  1327. globalImages->images.Append( image->partialImage );
  1328. image->partialImage->imgName = image->imgName;
  1329. image->partialImage->isPartialImage = true;
  1330. // let the background file loader know that we can load
  1331. image->precompressedFile = true;
  1332. if ( image_preload.GetBool() && !insideLevelLoad ) {
  1333. image->partialImage->ActuallyLoadImage( true, false ); // check for precompressed, load is from front end
  1334. declManager->MediaPrint( "%ix%i %s\n", image->partialImage->uploadWidth, image->partialImage->uploadHeight, image->imgName.c_str() );
  1335. } else {
  1336. declManager->MediaPrint( "%s\n", image->imgName.c_str() );
  1337. }
  1338. return image;
  1339. }
  1340. // load it if we aren't in a level preload
  1341. if ( image_preload.GetBool() && !insideLevelLoad ) {
  1342. image->referencedOutsideLevelLoad = true;
  1343. image->ActuallyLoadImage( true, false ); // check for precompressed, load is from front end
  1344. declManager->MediaPrint( "%ix%i %s\n", image->uploadWidth, image->uploadHeight, image->imgName.c_str() );
  1345. } else {
  1346. declManager->MediaPrint( "%s\n", image->imgName.c_str() );
  1347. }
  1348. return image;
  1349. }
  1350. /*
  1351. ===============
  1352. idImageManager::GetImage
  1353. ===============
  1354. */
  1355. idImage *idImageManager::GetImage( const char *_name ) const {
  1356. idStr name;
  1357. idImage *image;
  1358. int hash;
  1359. if ( !_name || !_name[0] || idStr::Icmp( _name, "default" ) == 0 || idStr::Icmp( _name, "_default" ) == 0 ) {
  1360. declManager->MediaPrint( "DEFAULTED\n" );
  1361. return globalImages->defaultImage;
  1362. }
  1363. // strip any .tga file extensions from anywhere in the _name, including image program parameters
  1364. name = _name;
  1365. name.Replace( ".tga", "" );
  1366. name.BackSlashesToSlashes();
  1367. //
  1368. // look in loaded images
  1369. //
  1370. hash = name.FileNameHash();
  1371. for ( image = imageHashTable[hash]; image; image = image->hashNext ) {
  1372. if ( name.Icmp( image->imgName ) == 0 ) {
  1373. return image;
  1374. }
  1375. }
  1376. return NULL;
  1377. }
  1378. /*
  1379. ===============
  1380. PurgeAllImages
  1381. ===============
  1382. */
  1383. void idImageManager::PurgeAllImages() {
  1384. int i;
  1385. idImage *image;
  1386. for ( i = 0; i < images.Num() ; i++ ) {
  1387. image = images[i];
  1388. image->PurgeImage();
  1389. }
  1390. }
  1391. /*
  1392. ===============
  1393. ReloadAllImages
  1394. ===============
  1395. */
  1396. void idImageManager::ReloadAllImages() {
  1397. idCmdArgs args;
  1398. // build the compressed normal map palette
  1399. SetNormalPalette();
  1400. args.TokenizeString( "reloadImages reload", false );
  1401. R_ReloadImages_f( args );
  1402. }
  1403. /*
  1404. ===============
  1405. R_CombineCubeImages_f
  1406. Used to combine animations of six separate tga files into
  1407. a serials of 6x taller tga files, for preparation to roq compress
  1408. ===============
  1409. */
  1410. void R_CombineCubeImages_f( const idCmdArgs &args ) {
  1411. if ( args.Argc() != 2 ) {
  1412. common->Printf( "usage: combineCubeImages <baseName>\n" );
  1413. common->Printf( " combines basename[1-6][0001-9999].tga to basenameCM[0001-9999].tga\n" );
  1414. common->Printf( " 1: forward 2:right 3:back 4:left 5:up 6:down\n" );
  1415. return;
  1416. }
  1417. idStr baseName = args.Argv( 1 );
  1418. common->SetRefreshOnPrint( true );
  1419. for ( int frameNum = 1 ; frameNum < 10000 ; frameNum++ ) {
  1420. char filename[MAX_IMAGE_NAME];
  1421. byte *pics[6];
  1422. int width, height;
  1423. int side;
  1424. int orderRemap[6] = { 1,3,4,2,5,6 };
  1425. for ( side = 0 ; side < 6 ; side++ ) {
  1426. sprintf( filename, "%s%i%04i.tga", baseName.c_str(), orderRemap[side], frameNum );
  1427. common->Printf( "reading %s\n", filename );
  1428. R_LoadImage( filename, &pics[side], &width, &height, NULL, true );
  1429. if ( !pics[side] ) {
  1430. common->Printf( "not found.\n" );
  1431. break;
  1432. }
  1433. // convert from "camera" images to native cube map images
  1434. switch( side ) {
  1435. case 0: // forward
  1436. R_RotatePic( pics[side], width);
  1437. break;
  1438. case 1: // back
  1439. R_RotatePic( pics[side], width);
  1440. R_HorizontalFlip( pics[side], width, height );
  1441. R_VerticalFlip( pics[side], width, height );
  1442. break;
  1443. case 2: // left
  1444. R_VerticalFlip( pics[side], width, height );
  1445. break;
  1446. case 3: // right
  1447. R_HorizontalFlip( pics[side], width, height );
  1448. break;
  1449. case 4: // up
  1450. R_RotatePic( pics[side], width);
  1451. break;
  1452. case 5: // down
  1453. R_RotatePic( pics[side], width);
  1454. break;
  1455. }
  1456. }
  1457. if ( side != 6 ) {
  1458. for ( int i = 0 ; i < side ; side++ ) {
  1459. Mem_Free( pics[side] );
  1460. }
  1461. break;
  1462. }
  1463. byte *combined = (byte *)Mem_Alloc( width*height*6*4 );
  1464. for ( side = 0 ; side < 6 ; side++ ) {
  1465. memcpy( combined+width*height*4*side, pics[side], width*height*4 );
  1466. Mem_Free( pics[side] );
  1467. }
  1468. sprintf( filename, "%sCM%04i.tga", baseName.c_str(), frameNum );
  1469. common->Printf( "writing %s\n", filename );
  1470. R_WriteTGA( filename, combined, width, height*6 );
  1471. Mem_Free( combined );
  1472. }
  1473. common->SetRefreshOnPrint( false );
  1474. }
  1475. /*
  1476. ==================
  1477. idImage::StartBackgroundImageLoad
  1478. ==================
  1479. */
  1480. void idImage::StartBackgroundImageLoad() {
  1481. if ( imageManager.numActiveBackgroundImageLoads >= idImageManager::MAX_BACKGROUND_IMAGE_LOADS ) {
  1482. return;
  1483. }
  1484. if ( globalImages->image_showBackgroundLoads.GetBool() ) {
  1485. common->Printf( "idImage::StartBackgroundImageLoad: %s\n", imgName.c_str() );
  1486. }
  1487. backgroundLoadInProgress = true;
  1488. if ( !precompressedFile ) {
  1489. common->Warning( "idImageManager::StartBackgroundImageLoad: %s wasn't a precompressed file", imgName.c_str() );
  1490. return;
  1491. }
  1492. bglNext = globalImages->backgroundImageLoads;
  1493. globalImages->backgroundImageLoads = this;
  1494. char filename[MAX_IMAGE_NAME];
  1495. ImageProgramStringToCompressedFileName( imgName, filename );
  1496. bgl.completed = false;
  1497. bgl.f = fileSystem->OpenFileRead( filename );
  1498. if ( !bgl.f ) {
  1499. common->Warning( "idImageManager::StartBackgroundImageLoad: Couldn't load %s", imgName.c_str() );
  1500. return;
  1501. }
  1502. bgl.file.position = 0;
  1503. bgl.file.length = bgl.f->Length();
  1504. if ( bgl.file.length < sizeof( ddsFileHeader_t ) ) {
  1505. common->Warning( "idImageManager::StartBackgroundImageLoad: %s had a bad file length", imgName.c_str() );
  1506. return;
  1507. }
  1508. bgl.file.buffer = R_StaticAlloc( bgl.file.length );
  1509. fileSystem->BackgroundDownload( &bgl );
  1510. imageManager.numActiveBackgroundImageLoads++;
  1511. // purge some images if necessary
  1512. int totalSize = 0;
  1513. for ( idImage *check = globalImages->cacheLRU.cacheUsageNext ; check != &globalImages->cacheLRU ; check = check->cacheUsageNext ) {
  1514. totalSize += check->StorageSize();
  1515. }
  1516. int needed = this->StorageSize();
  1517. while ( ( totalSize + needed ) > globalImages->image_cacheMegs.GetFloat() * 1024 * 1024 ) {
  1518. // purge the least recently used
  1519. idImage *check = globalImages->cacheLRU.cacheUsagePrev;
  1520. if ( check->texnum != TEXTURE_NOT_LOADED ) {
  1521. totalSize -= check->StorageSize();
  1522. if ( globalImages->image_showBackgroundLoads.GetBool() ) {
  1523. common->Printf( "purging %s\n", check->imgName.c_str() );
  1524. }
  1525. check->PurgeImage();
  1526. }
  1527. // remove it from the cached list
  1528. check->cacheUsageNext->cacheUsagePrev = check->cacheUsagePrev;
  1529. check->cacheUsagePrev->cacheUsageNext = check->cacheUsageNext;
  1530. check->cacheUsageNext = NULL;
  1531. check->cacheUsagePrev = NULL;
  1532. }
  1533. }
  1534. /*
  1535. ==================
  1536. R_CompleteBackgroundImageLoads
  1537. Do we need to worry about vid_restarts here?
  1538. ==================
  1539. */
  1540. void idImageManager::CompleteBackgroundImageLoads() {
  1541. idImage *remainingList = NULL;
  1542. idImage *next;
  1543. for ( idImage *image = backgroundImageLoads ; image ; image = next ) {
  1544. next = image->bglNext;
  1545. if ( image->bgl.completed ) {
  1546. numActiveBackgroundImageLoads--;
  1547. fileSystem->CloseFile( image->bgl.f );
  1548. // upload the image
  1549. image->UploadPrecompressedImage( (byte *)image->bgl.file.buffer, image->bgl.file.length );
  1550. R_StaticFree( image->bgl.file.buffer );
  1551. if ( image_showBackgroundLoads.GetBool() ) {
  1552. common->Printf( "R_CompleteBackgroundImageLoad: %s\n", image->imgName.c_str() );
  1553. }
  1554. } else {
  1555. image->bglNext = remainingList;
  1556. remainingList = image;
  1557. }
  1558. }
  1559. if ( image_showBackgroundLoads.GetBool() ) {
  1560. static int prev;
  1561. if ( numActiveBackgroundImageLoads != prev ) {
  1562. prev = numActiveBackgroundImageLoads;
  1563. common->Printf( "background Loads: %i\n", numActiveBackgroundImageLoads );
  1564. }
  1565. }
  1566. backgroundImageLoads = remainingList;
  1567. }
  1568. /*
  1569. ===============
  1570. CheckCvars
  1571. ===============
  1572. */
  1573. void idImageManager::CheckCvars() {
  1574. // textureFilter stuff
  1575. if ( image_filter.IsModified() || image_anisotropy.IsModified() || image_lodbias.IsModified() ) {
  1576. ChangeTextureFilter();
  1577. image_filter.ClearModified();
  1578. image_anisotropy.ClearModified();
  1579. image_lodbias.ClearModified();
  1580. }
  1581. }
  1582. /*
  1583. ===============
  1584. SumOfUsedImages
  1585. ===============
  1586. */
  1587. int idImageManager::SumOfUsedImages() {
  1588. int total;
  1589. int i;
  1590. idImage *image;
  1591. total = 0;
  1592. for ( i = 0; i < images.Num(); i++ ) {
  1593. image = images[i];
  1594. if ( image->frameUsed == backEnd.frameCount ) {
  1595. total += image->StorageSize();
  1596. }
  1597. }
  1598. return total;
  1599. }
  1600. /*
  1601. ===============
  1602. BindNull
  1603. ===============
  1604. */
  1605. void idImageManager::BindNull() {
  1606. tmu_t *tmu;
  1607. tmu = &backEnd.glState.tmu[backEnd.glState.currenttmu];
  1608. RB_LogComment( "BindNull()\n" );
  1609. if ( tmu->textureType == TT_CUBIC ) {
  1610. qglDisable( GL_TEXTURE_CUBE_MAP_EXT );
  1611. } else if ( tmu->textureType == TT_3D ) {
  1612. qglDisable( GL_TEXTURE_3D );
  1613. } else if ( tmu->textureType == TT_2D ) {
  1614. qglDisable( GL_TEXTURE_2D );
  1615. }
  1616. tmu->textureType = TT_DISABLED;
  1617. }
  1618. /*
  1619. ===============
  1620. Init
  1621. ===============
  1622. */
  1623. void idImageManager::Init() {
  1624. memset(imageHashTable, 0, sizeof(imageHashTable));
  1625. images.Resize( 1024, 1024 );
  1626. // clear the cached LRU
  1627. cacheLRU.cacheUsageNext = &cacheLRU;
  1628. cacheLRU.cacheUsagePrev = &cacheLRU;
  1629. // set default texture filter modes
  1630. ChangeTextureFilter();
  1631. // create built in images
  1632. defaultImage = ImageFromFunction( "_default", R_DefaultImage );
  1633. whiteImage = ImageFromFunction( "_white", R_WhiteImage );
  1634. blackImage = ImageFromFunction( "_black", R_BlackImage );
  1635. borderClampImage = ImageFromFunction( "_borderClamp", R_BorderClampImage );
  1636. flatNormalMap = ImageFromFunction( "_flat", R_FlatNormalImage );
  1637. ambientNormalMap = ImageFromFunction( "_ambient", R_AmbientNormalImage );
  1638. specularTableImage = ImageFromFunction( "_specularTable", R_SpecularTableImage );
  1639. specular2DTableImage = ImageFromFunction( "_specular2DTable", R_Specular2DTableImage );
  1640. rampImage = ImageFromFunction( "_ramp", R_RampImage );
  1641. alphaRampImage = ImageFromFunction( "_alphaRamp", R_RampImage );
  1642. alphaNotchImage = ImageFromFunction( "_alphaNotch", R_AlphaNotchImage );
  1643. fogImage = ImageFromFunction( "_fog", R_FogImage );
  1644. fogEnterImage = ImageFromFunction( "_fogEnter", R_FogEnterImage );
  1645. normalCubeMapImage = ImageFromFunction( "_normalCubeMap", makeNormalizeVectorCubeMap );
  1646. noFalloffImage = ImageFromFunction( "_noFalloff", R_CreateNoFalloffImage );
  1647. ImageFromFunction( "_quadratic", R_QuadraticImage );
  1648. // cinematicImage is used for cinematic drawing
  1649. // scratchImage is used for screen wipes/doublevision etc..
  1650. cinematicImage = ImageFromFunction("_cinematic", R_RGBA8Image );
  1651. scratchImage = ImageFromFunction("_scratch", R_RGBA8Image );
  1652. scratchImage2 = ImageFromFunction("_scratch2", R_RGBA8Image );
  1653. accumImage = ImageFromFunction("_accum", R_RGBA8Image );
  1654. scratchCubeMapImage = ImageFromFunction("_scratchCubeMap", makeNormalizeVectorCubeMap );
  1655. currentRenderImage = ImageFromFunction("_currentRender", R_RGBA8Image );
  1656. cmdSystem->AddCommand( "reloadImages", R_ReloadImages_f, CMD_FL_RENDERER, "reloads images" );
  1657. cmdSystem->AddCommand( "listImages", R_ListImages_f, CMD_FL_RENDERER, "lists images" );
  1658. cmdSystem->AddCommand( "combineCubeImages", R_CombineCubeImages_f, CMD_FL_RENDERER, "combines six images for roq compression" );
  1659. // should forceLoadImages be here?
  1660. }
  1661. /*
  1662. ===============
  1663. Shutdown
  1664. ===============
  1665. */
  1666. void idImageManager::Shutdown() {
  1667. images.DeleteContents( true );
  1668. }
  1669. /*
  1670. ====================
  1671. BeginLevelLoad
  1672. Mark all file based images as currently unused,
  1673. but don't free anything. Calls to ImageFromFile() will
  1674. either mark the image as used, or create a new image without
  1675. loading the actual data.
  1676. ====================
  1677. */
  1678. void idImageManager::BeginLevelLoad() {
  1679. insideLevelLoad = true;
  1680. for ( int i = 0 ; i < images.Num() ; i++ ) {
  1681. idImage *image = images[ i ];
  1682. // generator function images are always kept around
  1683. if ( image->generatorFunction ) {
  1684. continue;
  1685. }
  1686. if ( com_purgeAll.GetBool() ) {
  1687. image->PurgeImage();
  1688. }
  1689. image->levelLoadReferenced = false;
  1690. }
  1691. }
  1692. /*
  1693. ====================
  1694. EndLevelLoad
  1695. Free all images marked as unused, and load all images that are necessary.
  1696. This architecture prevents us from having the union of two level's
  1697. worth of data present at one time.
  1698. preload everything, never free
  1699. preload everything, free unused after level load
  1700. blocking load on demand
  1701. preload low mip levels, background load remainder on demand
  1702. ====================
  1703. */
  1704. void idImageManager::EndLevelLoad() {
  1705. int start = Sys_Milliseconds();
  1706. insideLevelLoad = false;
  1707. if ( idAsyncNetwork::serverDedicated.GetInteger() ) {
  1708. return;
  1709. }
  1710. common->Printf( "----- idImageManager::EndLevelLoad -----\n" );
  1711. int purgeCount = 0;
  1712. int keepCount = 0;
  1713. int loadCount = 0;
  1714. // purge the ones we don't need
  1715. for ( int i = 0 ; i < images.Num() ; i++ ) {
  1716. idImage *image = images[ i ];
  1717. if ( image->generatorFunction ) {
  1718. continue;
  1719. }
  1720. if ( !image->levelLoadReferenced && !image->referencedOutsideLevelLoad ) {
  1721. // common->Printf( "Purging %s\n", image->imgName.c_str() );
  1722. purgeCount++;
  1723. image->PurgeImage();
  1724. } else if ( image->texnum != idImage::TEXTURE_NOT_LOADED ) {
  1725. // common->Printf( "Keeping %s\n", image->imgName.c_str() );
  1726. keepCount++;
  1727. }
  1728. }
  1729. // load the ones we do need, if we are preloading
  1730. for ( int i = 0 ; i < images.Num() ; i++ ) {
  1731. idImage *image = images[ i ];
  1732. if ( image->generatorFunction ) {
  1733. continue;
  1734. }
  1735. if ( image->levelLoadReferenced && image->texnum == idImage::TEXTURE_NOT_LOADED && !image->partialImage ) {
  1736. // common->Printf( "Loading %s\n", image->imgName.c_str() );
  1737. loadCount++;
  1738. image->ActuallyLoadImage( true, false );
  1739. if ( ( loadCount & 15 ) == 0 ) {
  1740. session->PacifierUpdate();
  1741. }
  1742. }
  1743. }
  1744. int end = Sys_Milliseconds();
  1745. common->Printf( "%5i purged from previous\n", purgeCount );
  1746. common->Printf( "%5i kept from previous\n", keepCount );
  1747. common->Printf( "%5i new loaded\n", loadCount );
  1748. common->Printf( "all images loaded in %5.1f seconds\n", (end-start) * 0.001 );
  1749. common->Printf( "----------------------------------------\n" );
  1750. }
  1751. /*
  1752. ===============
  1753. idImageManager::StartBuild
  1754. ===============
  1755. */
  1756. void idImageManager::StartBuild() {
  1757. ddsList.Clear();
  1758. ddsHash.Free();
  1759. }
  1760. /*
  1761. ===============
  1762. idImageManager::FinishBuild
  1763. ===============
  1764. */
  1765. void idImageManager::FinishBuild( bool removeDups ) {
  1766. idFile *batchFile;
  1767. if ( removeDups ) {
  1768. ddsList.Clear();
  1769. char *buffer = NULL;
  1770. fileSystem->ReadFile( "makedds.bat", (void**)&buffer );
  1771. if ( buffer ) {
  1772. idStr str = buffer;
  1773. while ( str.Length() ) {
  1774. int n = str.Find( '\n' );
  1775. if ( n > 0 ) {
  1776. idStr line = str.Left( n + 1 );
  1777. idStr right;
  1778. str.Right( str.Length() - n - 1, right );
  1779. str = right;
  1780. ddsList.AddUnique( line );
  1781. } else {
  1782. break;
  1783. }
  1784. }
  1785. }
  1786. }
  1787. batchFile = fileSystem->OpenFileWrite( ( removeDups ) ? "makedds2.bat" : "makedds.bat" );
  1788. if ( batchFile ) {
  1789. int i;
  1790. int ddsNum = ddsList.Num();
  1791. for ( i = 0; i < ddsNum; i++ ) {
  1792. batchFile->WriteFloatString( "%s", ddsList[ i ].c_str() );
  1793. batchFile->Printf( "@echo Finished compressing %d of %d. %.1f percent done.\n", i+1, ddsNum, ((float)(i+1)/(float)ddsNum)*100.f );
  1794. }
  1795. fileSystem->CloseFile( batchFile );
  1796. }
  1797. ddsList.Clear();
  1798. ddsHash.Free();
  1799. }
  1800. /*
  1801. ===============
  1802. idImageManager::AddDDSCommand
  1803. ===============
  1804. */
  1805. void idImageManager::AddDDSCommand( const char *cmd ) {
  1806. int i, key;
  1807. if ( !( cmd && *cmd ) ) {
  1808. return;
  1809. }
  1810. key = ddsHash.GenerateKey( cmd, false );
  1811. for ( i = ddsHash.First( key ); i != -1; i = ddsHash.Next( i ) ) {
  1812. if ( ddsList[i].Icmp( cmd ) == 0 ) {
  1813. break;
  1814. }
  1815. }
  1816. if ( i == -1 ) {
  1817. ddsList.Append( cmd );
  1818. }
  1819. }
  1820. /*
  1821. ===============
  1822. idImageManager::PrintMemInfo
  1823. ===============
  1824. */
  1825. void idImageManager::PrintMemInfo( MemInfo_t *mi ) {
  1826. int i, j, total = 0;
  1827. int *sortIndex;
  1828. idFile *f;
  1829. f = fileSystem->OpenFileWrite( mi->filebase + "_images.txt" );
  1830. if ( !f ) {
  1831. return;
  1832. }
  1833. // sort first
  1834. sortIndex = new int[images.Num()];
  1835. for ( i = 0; i < images.Num(); i++ ) {
  1836. sortIndex[i] = i;
  1837. }
  1838. for ( i = 0; i < images.Num() - 1; i++ ) {
  1839. for ( j = i + 1; j < images.Num(); j++ ) {
  1840. if ( images[sortIndex[i]]->StorageSize() < images[sortIndex[j]]->StorageSize() ) {
  1841. int temp = sortIndex[i];
  1842. sortIndex[i] = sortIndex[j];
  1843. sortIndex[j] = temp;
  1844. }
  1845. }
  1846. }
  1847. // print next
  1848. for ( i = 0; i < images.Num(); i++ ) {
  1849. idImage *im = images[sortIndex[i]];
  1850. int size;
  1851. size = im->StorageSize();
  1852. total += size;
  1853. f->Printf( "%s %3i %s\n", idStr::FormatNumber( size ).c_str(), im->refCount, im->imgName.c_str() );
  1854. }
  1855. delete sortIndex;
  1856. mi->imageAssetsTotal = total;
  1857. f->Printf( "\nTotal image bytes allocated: %s\n", idStr::FormatNumber( total ).c_str() );
  1858. fileSystem->CloseFile( f );
  1859. }