Image_load.cpp 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213
  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. /*
  24. PROBLEM: compressed textures may break the zero clamp rule!
  25. */
  26. static bool FormatIsDXT( int internalFormat ) {
  27. if ( internalFormat < GL_COMPRESSED_RGB_S3TC_DXT1_EXT
  28. || internalFormat > GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ) {
  29. return false;
  30. }
  31. return true;
  32. }
  33. int MakePowerOfTwo( int num ) {
  34. int pot;
  35. for (pot = 1 ; pot < num ; pot<<=1) {
  36. }
  37. return pot;
  38. }
  39. /*
  40. ================
  41. BitsForInternalFormat
  42. Used for determining memory utilization
  43. ================
  44. */
  45. int idImage::BitsForInternalFormat( int internalFormat ) const {
  46. switch ( internalFormat ) {
  47. case GL_INTENSITY8:
  48. case 1:
  49. return 8;
  50. case 2:
  51. case GL_LUMINANCE8_ALPHA8:
  52. return 16;
  53. case 3:
  54. return 32; // on some future hardware, this may actually be 24, but be conservative
  55. case 4:
  56. return 32;
  57. case GL_LUMINANCE8:
  58. return 8;
  59. case GL_ALPHA8:
  60. return 8;
  61. case GL_RGBA8:
  62. return 32;
  63. case GL_RGB8:
  64. return 32; // on some future hardware, this may actually be 24, but be conservative
  65. case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
  66. return 4;
  67. case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  68. return 4;
  69. case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  70. return 8;
  71. case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  72. return 8;
  73. case GL_RGBA4:
  74. return 16;
  75. case GL_RGB5:
  76. return 16;
  77. case GL_COLOR_INDEX8_EXT:
  78. return 8;
  79. case GL_COLOR_INDEX:
  80. return 8;
  81. case GL_COMPRESSED_RGB_ARB:
  82. return 4; // not sure
  83. case GL_COMPRESSED_RGBA_ARB:
  84. return 8; // not sure
  85. default:
  86. common->Error( "R_BitsForInternalFormat: BAD FORMAT:%i", internalFormat );
  87. }
  88. return 0;
  89. }
  90. /*
  91. ==================
  92. UploadCompressedNormalMap
  93. Create a 256 color palette to be used by compressed normal maps
  94. ==================
  95. */
  96. void idImage::UploadCompressedNormalMap( int width, int height, const byte *rgba, int mipLevel ) {
  97. byte *normals;
  98. const byte *in;
  99. byte *out;
  100. int i, j;
  101. int x, y, z;
  102. int row;
  103. // OpenGL's pixel packing rule
  104. row = width < 4 ? 4 : width;
  105. normals = (byte *)_alloca( row * height );
  106. if ( !normals ) {
  107. common->Error( "R_UploadCompressedNormalMap: _alloca failed" );
  108. }
  109. in = rgba;
  110. out = normals;
  111. for ( i = 0 ; i < height ; i++, out += row, in += width * 4 ) {
  112. for ( j = 0 ; j < width ; j++ ) {
  113. x = in[ j * 4 + 0 ];
  114. y = in[ j * 4 + 1 ];
  115. z = in[ j * 4 + 2 ];
  116. int c;
  117. if ( x == 128 && y == 128 && z == 128 ) {
  118. // the "nullnormal" color
  119. c = 255;
  120. } else {
  121. c = ( globalImages->originalToCompressed[x] << 4 ) | globalImages->originalToCompressed[y];
  122. if ( c == 255 ) {
  123. c = 254; // don't use the nullnormal color
  124. }
  125. }
  126. out[j] = c;
  127. }
  128. }
  129. if ( mipLevel == 0 ) {
  130. // Optionally write out the paletized normal map to a .tga
  131. if ( globalImages->image_writeNormalTGAPalletized.GetBool() ) {
  132. char filename[MAX_IMAGE_NAME];
  133. ImageProgramStringToCompressedFileName( imgName, filename );
  134. char *ext = strrchr(filename, '.');
  135. if ( ext ) {
  136. strcpy(ext, "_pal.tga");
  137. R_WritePalTGA( filename, normals, globalImages->compressedPalette, width, height);
  138. }
  139. }
  140. }
  141. if ( glConfig.sharedTexturePaletteAvailable ) {
  142. qglTexImage2D( GL_TEXTURE_2D,
  143. mipLevel,
  144. GL_COLOR_INDEX8_EXT,
  145. width,
  146. height,
  147. 0,
  148. GL_COLOR_INDEX,
  149. GL_UNSIGNED_BYTE,
  150. normals );
  151. }
  152. }
  153. //=======================================================================
  154. static byte mipBlendColors[16][4] = {
  155. {0,0,0,0},
  156. {255,0,0,128},
  157. {0,255,0,128},
  158. {0,0,255,128},
  159. {255,0,0,128},
  160. {0,255,0,128},
  161. {0,0,255,128},
  162. {255,0,0,128},
  163. {0,255,0,128},
  164. {0,0,255,128},
  165. {255,0,0,128},
  166. {0,255,0,128},
  167. {0,0,255,128},
  168. {255,0,0,128},
  169. {0,255,0,128},
  170. {0,0,255,128},
  171. };
  172. /*
  173. ===============
  174. SelectInternalFormat
  175. This may need to scan six cube map images
  176. ===============
  177. */
  178. GLenum idImage::SelectInternalFormat( const byte **dataPtrs, int numDataPtrs, int width, int height,
  179. textureDepth_t minimumDepth, bool *monochromeResult ) const {
  180. int i, c;
  181. const byte *scan;
  182. int rgbOr, rgbAnd, aOr, aAnd;
  183. int rgbDiffer, rgbaDiffer;
  184. // determine if the rgb channels are all the same
  185. // and if either all rgb or all alpha are 255
  186. c = width*height;
  187. rgbDiffer = 0;
  188. rgbaDiffer = 0;
  189. rgbOr = 0;
  190. rgbAnd = -1;
  191. aOr = 0;
  192. aAnd = -1;
  193. *monochromeResult = true; // until shown otherwise
  194. for ( int side = 0 ; side < numDataPtrs ; side++ ) {
  195. scan = dataPtrs[side];
  196. for ( i = 0; i < c; i++, scan += 4 ) {
  197. int cor, cand;
  198. aOr |= scan[3];
  199. aAnd &= scan[3];
  200. cor = scan[0] | scan[1] | scan[2];
  201. cand = scan[0] & scan[1] & scan[2];
  202. // if rgb are all the same, the or and and will match
  203. rgbDiffer |= ( cor ^ cand );
  204. // our "isMonochrome" test is more lax than rgbDiffer,
  205. // allowing the values to be off by several units and
  206. // still use the NV20 mono path
  207. if ( *monochromeResult ) {
  208. if ( abs( scan[0] - scan[1] ) > 16
  209. || abs( scan[0] - scan[2] ) > 16 ) {
  210. *monochromeResult = false;
  211. }
  212. }
  213. rgbOr |= cor;
  214. rgbAnd &= cand;
  215. cor |= scan[3];
  216. cand &= scan[3];
  217. rgbaDiffer |= ( cor ^ cand );
  218. }
  219. }
  220. // we assume that all 0 implies that the alpha channel isn't needed,
  221. // because some tools will spit out 32 bit images with a 0 alpha instead
  222. // of 255 alpha, but if the alpha actually is referenced, there will be
  223. // different behavior in the compressed vs uncompressed states.
  224. bool needAlpha;
  225. if ( aAnd == 255 || aOr == 0 ) {
  226. needAlpha = false;
  227. } else {
  228. needAlpha = true;
  229. }
  230. // catch normal maps first
  231. if ( minimumDepth == TD_BUMP ) {
  232. if ( globalImages->image_useCompression.GetBool() && globalImages->image_useNormalCompression.GetInteger() == 1 && glConfig.sharedTexturePaletteAvailable ) {
  233. // image_useNormalCompression should only be set to 1 on nv_10 and nv_20 paths
  234. return GL_COLOR_INDEX8_EXT;
  235. } else if ( globalImages->image_useCompression.GetBool() && globalImages->image_useNormalCompression.GetInteger() && glConfig.textureCompressionAvailable ) {
  236. // image_useNormalCompression == 2 uses rxgb format which produces really good quality for medium settings
  237. return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
  238. } else {
  239. // we always need the alpha channel for bump maps for swizzling
  240. return GL_RGBA8;
  241. }
  242. }
  243. // allow a complete override of image compression with a cvar
  244. if ( !globalImages->image_useCompression.GetBool() ) {
  245. minimumDepth = TD_HIGH_QUALITY;
  246. }
  247. if ( minimumDepth == TD_SPECULAR ) {
  248. // we are assuming that any alpha channel is unintentional
  249. if ( glConfig.textureCompressionAvailable ) {
  250. return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
  251. } else {
  252. return GL_RGB5;
  253. }
  254. }
  255. if ( minimumDepth == TD_DIFFUSE ) {
  256. // we might intentionally have an alpha channel for alpha tested textures
  257. if ( glConfig.textureCompressionAvailable ) {
  258. if ( !needAlpha ) {
  259. return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
  260. } else {
  261. return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
  262. }
  263. } else if ( ( aAnd == 255 || aOr == 0 ) ) {
  264. return GL_RGB5;
  265. } else {
  266. return GL_RGBA4;
  267. }
  268. }
  269. // there will probably be some drivers that don't
  270. // correctly handle the intensity/alpha/luminance/luminance+alpha
  271. // formats, so provide a fallback that only uses the rgb/rgba formats
  272. if ( !globalImages->image_useAllFormats.GetBool() ) {
  273. // pretend rgb is varying and inconsistant, which
  274. // prevents any of the more compact forms
  275. rgbDiffer = 1;
  276. rgbaDiffer = 1;
  277. rgbAnd = 0;
  278. }
  279. // cases without alpha
  280. if ( !needAlpha ) {
  281. if ( minimumDepth == TD_HIGH_QUALITY ) {
  282. return GL_RGB8; // four bytes
  283. }
  284. if ( glConfig.textureCompressionAvailable ) {
  285. return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; // half byte
  286. }
  287. return GL_RGB5; // two bytes
  288. }
  289. // cases with alpha
  290. if ( !rgbaDiffer ) {
  291. if ( minimumDepth != TD_HIGH_QUALITY && glConfig.textureCompressionAvailable ) {
  292. return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; // one byte
  293. }
  294. return GL_INTENSITY8; // single byte for all channels
  295. }
  296. #if 0
  297. // we don't support alpha textures any more, because there
  298. // is a discrepancy in the definition of TEX_ENV_COMBINE that
  299. // causes them to be treated as 0 0 0 A, instead of 1 1 1 A as
  300. // normal texture modulation treats them
  301. if ( rgbAnd == 255 ) {
  302. return GL_ALPHA8; // single byte, only alpha
  303. }
  304. #endif
  305. if ( minimumDepth == TD_HIGH_QUALITY ) {
  306. return GL_RGBA8; // four bytes
  307. }
  308. if ( glConfig.textureCompressionAvailable ) {
  309. return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; // one byte
  310. }
  311. if ( !rgbDiffer ) {
  312. return GL_LUMINANCE8_ALPHA8; // two bytes, max quality
  313. }
  314. return GL_RGBA4; // two bytes
  315. }
  316. /*
  317. ==================
  318. SetImageFilterAndRepeat
  319. ==================
  320. */
  321. void idImage::SetImageFilterAndRepeat() const {
  322. // set the minimize / maximize filtering
  323. switch( filter ) {
  324. case TF_DEFAULT:
  325. qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, globalImages->textureMinFilter );
  326. qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, globalImages->textureMaxFilter );
  327. break;
  328. case TF_LINEAR:
  329. qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  330. qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  331. break;
  332. case TF_NEAREST:
  333. qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  334. qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  335. break;
  336. default:
  337. common->FatalError( "R_CreateImage: bad texture filter" );
  338. }
  339. if ( glConfig.anisotropicAvailable ) {
  340. // only do aniso filtering on mip mapped images
  341. if ( filter == TF_DEFAULT ) {
  342. qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, globalImages->textureAnisotropy );
  343. } else {
  344. qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 );
  345. }
  346. }
  347. if ( glConfig.textureLODBiasAvailable ) {
  348. qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_EXT, globalImages->textureLODBias );
  349. }
  350. // set the wrap/clamp modes
  351. switch( repeat ) {
  352. case TR_REPEAT:
  353. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
  354. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
  355. break;
  356. case TR_CLAMP_TO_BORDER:
  357. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
  358. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
  359. break;
  360. case TR_CLAMP_TO_ZERO:
  361. case TR_CLAMP_TO_ZERO_ALPHA:
  362. case TR_CLAMP:
  363. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
  364. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
  365. break;
  366. default:
  367. common->FatalError( "R_CreateImage: bad texture repeat" );
  368. }
  369. }
  370. /*
  371. ================
  372. idImage::Downsize
  373. helper function that takes the current width/height and might make them smaller
  374. ================
  375. */
  376. void idImage::GetDownsize( int &scaled_width, int &scaled_height ) const {
  377. int size = 0;
  378. // perform optional picmip operation to save texture memory
  379. if ( depth == TD_SPECULAR && globalImages->image_downSizeSpecular.GetInteger() ) {
  380. size = globalImages->image_downSizeSpecularLimit.GetInteger();
  381. if ( size == 0 ) {
  382. size = 64;
  383. }
  384. } else if ( depth == TD_BUMP && globalImages->image_downSizeBump.GetInteger() ) {
  385. size = globalImages->image_downSizeBumpLimit.GetInteger();
  386. if ( size == 0 ) {
  387. size = 64;
  388. }
  389. } else if ( ( allowDownSize || globalImages->image_forceDownSize.GetBool() ) && globalImages->image_downSize.GetInteger() ) {
  390. size = globalImages->image_downSizeLimit.GetInteger();
  391. if ( size == 0 ) {
  392. size = 256;
  393. }
  394. }
  395. if ( size > 0 ) {
  396. while ( scaled_width > size || scaled_height > size ) {
  397. if ( scaled_width > 1 ) {
  398. scaled_width >>= 1;
  399. }
  400. if ( scaled_height > 1 ) {
  401. scaled_height >>= 1;
  402. }
  403. }
  404. }
  405. // clamp to minimum size
  406. if ( scaled_width < 1 ) {
  407. scaled_width = 1;
  408. }
  409. if ( scaled_height < 1 ) {
  410. scaled_height = 1;
  411. }
  412. // clamp size to the hardware specific upper limit
  413. // scale both axis down equally so we don't have to
  414. // deal with a half mip resampling
  415. // This causes a 512*256 texture to sample down to
  416. // 256*128 on a voodoo3, even though it could be 256*256
  417. while ( scaled_width > glConfig.maxTextureSize
  418. || scaled_height > glConfig.maxTextureSize ) {
  419. scaled_width >>= 1;
  420. scaled_height >>= 1;
  421. }
  422. }
  423. /*
  424. ================
  425. GenerateImage
  426. The alpha channel bytes should be 255 if you don't
  427. want the channel.
  428. We need a material characteristic to ask for specific texture modes.
  429. Designed limitations of flexibility:
  430. No support for texture borders.
  431. No support for texture border color.
  432. No support for texture environment colors or GL_BLEND or GL_DECAL
  433. texture environments, because the automatic optimization to single
  434. or dual component textures makes those modes potentially undefined.
  435. No non-power-of-two images.
  436. No palettized textures.
  437. There is no way to specify separate wrap/clamp values for S and T
  438. There is no way to specify explicit mip map levels
  439. ================
  440. */
  441. void idImage::GenerateImage( const byte *pic, int width, int height,
  442. textureFilter_t filterParm, bool allowDownSizeParm,
  443. textureRepeat_t repeatParm, textureDepth_t depthParm ) {
  444. bool preserveBorder;
  445. byte *scaledBuffer;
  446. int scaled_width, scaled_height;
  447. byte *shrunk;
  448. PurgeImage();
  449. filter = filterParm;
  450. allowDownSize = allowDownSizeParm;
  451. repeat = repeatParm;
  452. depth = depthParm;
  453. // if we don't have a rendering context, just return after we
  454. // have filled in the parms. We must have the values set, or
  455. // an image match from a shader before OpenGL starts would miss
  456. // the generated texture
  457. if ( !glConfig.isInitialized ) {
  458. return;
  459. }
  460. // don't let mip mapping smear the texture into the clamped border
  461. if ( repeat == TR_CLAMP_TO_ZERO ) {
  462. preserveBorder = true;
  463. } else {
  464. preserveBorder = false;
  465. }
  466. // make sure it is a power of 2
  467. scaled_width = MakePowerOfTwo( width );
  468. scaled_height = MakePowerOfTwo( height );
  469. if ( scaled_width != width || scaled_height != height ) {
  470. common->Error( "R_CreateImage: not a power of 2 image" );
  471. }
  472. // Optionally modify our width/height based on options/hardware
  473. GetDownsize( scaled_width, scaled_height );
  474. scaledBuffer = NULL;
  475. // generate the texture number
  476. qglGenTextures( 1, &texnum );
  477. // select proper internal format before we resample
  478. internalFormat = SelectInternalFormat( &pic, 1, width, height, depth, &isMonochrome );
  479. // copy or resample data as appropriate for first MIP level
  480. if ( ( scaled_width == width ) && ( scaled_height == height ) ) {
  481. // we must copy even if unchanged, because the border zeroing
  482. // would otherwise modify const data
  483. scaledBuffer = (byte *)R_StaticAlloc( sizeof( unsigned ) * scaled_width * scaled_height );
  484. memcpy (scaledBuffer, pic, width*height*4);
  485. } else {
  486. // resample down as needed (FIXME: this doesn't seem like it resamples anymore!)
  487. // scaledBuffer = R_ResampleTexture( pic, width, height, width >>= 1, height >>= 1 );
  488. scaledBuffer = R_MipMap( pic, width, height, preserveBorder );
  489. width >>= 1;
  490. height >>= 1;
  491. if ( width < 1 ) {
  492. width = 1;
  493. }
  494. if ( height < 1 ) {
  495. height = 1;
  496. }
  497. while ( width > scaled_width || height > scaled_height ) {
  498. shrunk = R_MipMap( scaledBuffer, width, height, preserveBorder );
  499. R_StaticFree( scaledBuffer );
  500. scaledBuffer = shrunk;
  501. width >>= 1;
  502. height >>= 1;
  503. if ( width < 1 ) {
  504. width = 1;
  505. }
  506. if ( height < 1 ) {
  507. height = 1;
  508. }
  509. }
  510. // one might have shrunk down below the target size
  511. scaled_width = width;
  512. scaled_height = height;
  513. }
  514. uploadHeight = scaled_height;
  515. uploadWidth = scaled_width;
  516. type = TT_2D;
  517. // zero the border if desired, allowing clamped projection textures
  518. // even after picmip resampling or careless artists.
  519. if ( repeat == TR_CLAMP_TO_ZERO ) {
  520. byte rgba[4];
  521. rgba[0] = rgba[1] = rgba[2] = 0;
  522. rgba[3] = 255;
  523. R_SetBorderTexels( (byte *)scaledBuffer, width, height, rgba );
  524. }
  525. if ( repeat == TR_CLAMP_TO_ZERO_ALPHA ) {
  526. byte rgba[4];
  527. rgba[0] = rgba[1] = rgba[2] = 255;
  528. rgba[3] = 0;
  529. R_SetBorderTexels( (byte *)scaledBuffer, width, height, rgba );
  530. }
  531. if ( generatorFunction == NULL && ( depth == TD_BUMP && globalImages->image_writeNormalTGA.GetBool() || depth != TD_BUMP && globalImages->image_writeTGA.GetBool() ) ) {
  532. // Optionally write out the texture to a .tga
  533. char filename[MAX_IMAGE_NAME];
  534. ImageProgramStringToCompressedFileName( imgName, filename );
  535. char *ext = strrchr(filename, '.');
  536. if ( ext ) {
  537. strcpy( ext, ".tga" );
  538. // swap the red/alpha for the write
  539. /*
  540. if ( depth == TD_BUMP ) {
  541. for ( int i = 0; i < scaled_width * scaled_height * 4; i += 4 ) {
  542. scaledBuffer[ i ] = scaledBuffer[ i + 3 ];
  543. scaledBuffer[ i + 3 ] = 0;
  544. }
  545. }
  546. */
  547. R_WriteTGA( filename, scaledBuffer, scaled_width, scaled_height, false );
  548. // put it back
  549. /*
  550. if ( depth == TD_BUMP ) {
  551. for ( int i = 0; i < scaled_width * scaled_height * 4; i += 4 ) {
  552. scaledBuffer[ i + 3 ] = scaledBuffer[ i ];
  553. scaledBuffer[ i ] = 0;
  554. }
  555. }
  556. */
  557. }
  558. }
  559. // swap the red and alpha for rxgb support
  560. // do this even on tga normal maps so we only have to use
  561. // one fragment program
  562. // if the image is precompressed ( either in palletized mode or true rxgb mode )
  563. // then it is loaded above and the swap never happens here
  564. if ( depth == TD_BUMP && globalImages->image_useNormalCompression.GetInteger() != 1 ) {
  565. for ( int i = 0; i < scaled_width * scaled_height * 4; i += 4 ) {
  566. scaledBuffer[ i + 3 ] = scaledBuffer[ i ];
  567. scaledBuffer[ i ] = 0;
  568. }
  569. }
  570. // upload the main image level
  571. Bind();
  572. if ( internalFormat == GL_COLOR_INDEX8_EXT ) {
  573. /*
  574. if ( depth == TD_BUMP ) {
  575. for ( int i = 0; i < scaled_width * scaled_height * 4; i += 4 ) {
  576. scaledBuffer[ i ] = scaledBuffer[ i + 3 ];
  577. scaledBuffer[ i + 3 ] = 0;
  578. }
  579. }
  580. */
  581. UploadCompressedNormalMap( scaled_width, scaled_height, scaledBuffer, 0 );
  582. } else {
  583. qglTexImage2D( GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer );
  584. }
  585. // create and upload the mip map levels, which we do in all cases, even if we don't think they are needed
  586. int miplevel;
  587. miplevel = 0;
  588. while ( scaled_width > 1 || scaled_height > 1 ) {
  589. // preserve the border after mip map unless repeating
  590. shrunk = R_MipMap( scaledBuffer, scaled_width, scaled_height, preserveBorder );
  591. R_StaticFree( scaledBuffer );
  592. scaledBuffer = shrunk;
  593. scaled_width >>= 1;
  594. scaled_height >>= 1;
  595. if ( scaled_width < 1 ) {
  596. scaled_width = 1;
  597. }
  598. if ( scaled_height < 1 ) {
  599. scaled_height = 1;
  600. }
  601. miplevel++;
  602. // this is a visualization tool that shades each mip map
  603. // level with a different color so you can see the
  604. // rasterizer's texture level selection algorithm
  605. // Changing the color doesn't help with lumminance/alpha/intensity formats...
  606. if ( depth == TD_DIFFUSE && globalImages->image_colorMipLevels.GetBool() ) {
  607. R_BlendOverTexture( (byte *)scaledBuffer, scaled_width * scaled_height, mipBlendColors[miplevel] );
  608. }
  609. // upload the mip map
  610. if ( internalFormat == GL_COLOR_INDEX8_EXT ) {
  611. UploadCompressedNormalMap( scaled_width, scaled_height, scaledBuffer, miplevel );
  612. } else {
  613. qglTexImage2D( GL_TEXTURE_2D, miplevel, internalFormat, scaled_width, scaled_height,
  614. 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer );
  615. }
  616. }
  617. if ( scaledBuffer != 0 ) {
  618. R_StaticFree( scaledBuffer );
  619. }
  620. SetImageFilterAndRepeat();
  621. // see if we messed anything up
  622. GL_CheckErrors();
  623. }
  624. /*
  625. ==================
  626. Generate3DImage
  627. ==================
  628. */
  629. void idImage::Generate3DImage( const byte *pic, int width, int height, int picDepth,
  630. textureFilter_t filterParm, bool allowDownSizeParm,
  631. textureRepeat_t repeatParm, textureDepth_t minDepthParm ) {
  632. int scaled_width, scaled_height, scaled_depth;
  633. PurgeImage();
  634. filter = filterParm;
  635. allowDownSize = allowDownSizeParm;
  636. repeat = repeatParm;
  637. depth = minDepthParm;
  638. // if we don't have a rendering context, just return after we
  639. // have filled in the parms. We must have the values set, or
  640. // an image match from a shader before OpenGL starts would miss
  641. // the generated texture
  642. if ( !glConfig.isInitialized ) {
  643. return;
  644. }
  645. // make sure it is a power of 2
  646. scaled_width = MakePowerOfTwo( width );
  647. scaled_height = MakePowerOfTwo( height );
  648. scaled_depth = MakePowerOfTwo( picDepth );
  649. if ( scaled_width != width || scaled_height != height || scaled_depth != picDepth ) {
  650. common->Error( "R_Create3DImage: not a power of 2 image" );
  651. }
  652. // FIXME: allow picmip here
  653. // generate the texture number
  654. qglGenTextures( 1, &texnum );
  655. // select proper internal format before we resample
  656. // this function doesn't need to know it is 3D, so just make it very "tall"
  657. internalFormat = SelectInternalFormat( &pic, 1, width, height * picDepth, minDepthParm, &isMonochrome );
  658. uploadHeight = scaled_height;
  659. uploadWidth = scaled_width;
  660. uploadDepth = scaled_depth;
  661. type = TT_3D;
  662. // upload the main image level
  663. Bind();
  664. qglTexImage3D(GL_TEXTURE_3D, 0, internalFormat, scaled_width, scaled_height, scaled_depth,
  665. 0, GL_RGBA, GL_UNSIGNED_BYTE, pic );
  666. // create and upload the mip map levels
  667. int miplevel;
  668. byte *scaledBuffer, *shrunk;
  669. scaledBuffer = (byte *)R_StaticAlloc( scaled_width * scaled_height * scaled_depth * 4 );
  670. memcpy( scaledBuffer, pic, scaled_width * scaled_height * scaled_depth * 4 );
  671. miplevel = 0;
  672. while ( scaled_width > 1 || scaled_height > 1 || scaled_depth > 1 ) {
  673. // preserve the border after mip map unless repeating
  674. shrunk = R_MipMap3D( scaledBuffer, scaled_width, scaled_height, scaled_depth,
  675. (bool)(repeat != TR_REPEAT) );
  676. R_StaticFree( scaledBuffer );
  677. scaledBuffer = shrunk;
  678. scaled_width >>= 1;
  679. scaled_height >>= 1;
  680. scaled_depth >>= 1;
  681. if ( scaled_width < 1 ) {
  682. scaled_width = 1;
  683. }
  684. if ( scaled_height < 1 ) {
  685. scaled_height = 1;
  686. }
  687. if ( scaled_depth < 1 ) {
  688. scaled_depth = 1;
  689. }
  690. miplevel++;
  691. // upload the mip map
  692. qglTexImage3D(GL_TEXTURE_3D, miplevel, internalFormat, scaled_width, scaled_height, scaled_depth,
  693. 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer );
  694. }
  695. R_StaticFree( scaledBuffer );
  696. // set the minimize / maximize filtering
  697. switch( filter ) {
  698. case TF_DEFAULT:
  699. qglTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, globalImages->textureMinFilter );
  700. qglTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, globalImages->textureMaxFilter );
  701. break;
  702. case TF_LINEAR:
  703. qglTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  704. qglTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  705. break;
  706. case TF_NEAREST:
  707. qglTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  708. qglTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  709. break;
  710. default:
  711. common->FatalError( "R_CreateImage: bad texture filter" );
  712. }
  713. // set the wrap/clamp modes
  714. switch( repeat ) {
  715. case TR_REPEAT:
  716. qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT );
  717. qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT );
  718. qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT );
  719. break;
  720. case TR_CLAMP_TO_BORDER:
  721. qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER );
  722. qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER );
  723. break;
  724. case TR_CLAMP_TO_ZERO:
  725. case TR_CLAMP_TO_ZERO_ALPHA:
  726. case TR_CLAMP:
  727. qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
  728. qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
  729. qglTexParameterf( GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );
  730. break;
  731. default:
  732. common->FatalError( "R_CreateImage: bad texture repeat" );
  733. }
  734. // see if we messed anything up
  735. GL_CheckErrors();
  736. }
  737. /*
  738. ====================
  739. GenerateCubeImage
  740. Non-square cube sides are not allowed
  741. ====================
  742. */
  743. void idImage::GenerateCubeImage( const byte *pic[6], int size,
  744. textureFilter_t filterParm, bool allowDownSizeParm,
  745. textureDepth_t depthParm ) {
  746. int scaled_width, scaled_height;
  747. int width, height;
  748. int i;
  749. PurgeImage();
  750. filter = filterParm;
  751. allowDownSize = allowDownSizeParm;
  752. depth = depthParm;
  753. type = TT_CUBIC;
  754. // if we don't have a rendering context, just return after we
  755. // have filled in the parms. We must have the values set, or
  756. // an image match from a shader before OpenGL starts would miss
  757. // the generated texture
  758. if ( !glConfig.isInitialized ) {
  759. return;
  760. }
  761. if ( ! glConfig.cubeMapAvailable ) {
  762. return;
  763. }
  764. width = height = size;
  765. // generate the texture number
  766. qglGenTextures( 1, &texnum );
  767. // select proper internal format before we resample
  768. internalFormat = SelectInternalFormat( pic, 6, width, height, depth, &isMonochrome );
  769. // don't bother with downsample for now
  770. scaled_width = width;
  771. scaled_height = height;
  772. uploadHeight = scaled_height;
  773. uploadWidth = scaled_width;
  774. Bind();
  775. // no other clamp mode makes sense
  776. qglTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  777. qglTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  778. // set the minimize / maximize filtering
  779. switch( filter ) {
  780. case TF_DEFAULT:
  781. qglTexParameterf(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, globalImages->textureMinFilter );
  782. qglTexParameterf(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, globalImages->textureMaxFilter );
  783. break;
  784. case TF_LINEAR:
  785. qglTexParameterf(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  786. qglTexParameterf(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  787. break;
  788. case TF_NEAREST:
  789. qglTexParameterf(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  790. qglTexParameterf(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  791. break;
  792. default:
  793. common->FatalError( "R_CreateImage: bad texture filter" );
  794. }
  795. // upload the base level
  796. // FIXME: support GL_COLOR_INDEX8_EXT?
  797. for ( i = 0 ; i < 6 ; i++ ) {
  798. qglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT+i, 0, internalFormat, scaled_width, scaled_height, 0,
  799. GL_RGBA, GL_UNSIGNED_BYTE, pic[i] );
  800. }
  801. // create and upload the mip map levels
  802. int miplevel;
  803. byte *shrunk[6];
  804. for ( i = 0 ; i < 6 ; i++ ) {
  805. shrunk[i] = R_MipMap( pic[i], scaled_width, scaled_height, false );
  806. }
  807. miplevel = 1;
  808. while ( scaled_width > 1 ) {
  809. for ( i = 0 ; i < 6 ; i++ ) {
  810. byte *shrunken;
  811. qglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT+i, miplevel, internalFormat,
  812. scaled_width / 2, scaled_height / 2, 0,
  813. GL_RGBA, GL_UNSIGNED_BYTE, shrunk[i] );
  814. if ( scaled_width > 2 ) {
  815. shrunken = R_MipMap( shrunk[i], scaled_width/2, scaled_height/2, false );
  816. } else {
  817. shrunken = NULL;
  818. }
  819. R_StaticFree( shrunk[i] );
  820. shrunk[i] = shrunken;
  821. }
  822. scaled_width >>= 1;
  823. scaled_height >>= 1;
  824. miplevel++;
  825. }
  826. // see if we messed anything up
  827. GL_CheckErrors();
  828. }
  829. /*
  830. ================
  831. ImageProgramStringToFileCompressedFileName
  832. ================
  833. */
  834. void idImage::ImageProgramStringToCompressedFileName( const char *imageProg, char *fileName ) const {
  835. const char *s;
  836. char *f;
  837. strcpy( fileName, "dds/" );
  838. f = fileName + strlen( fileName );
  839. int depth = 0;
  840. // convert all illegal characters to underscores
  841. // this could conceivably produce a duplicated mapping, but we aren't going to worry about it
  842. for ( s = imageProg ; *s ; s++ ) {
  843. if ( *s == '/' || *s == '\\' || *s == '(') {
  844. if ( depth < 4 ) {
  845. *f = '/';
  846. depth ++;
  847. } else {
  848. *f = ' ';
  849. }
  850. f++;
  851. } else if ( *s == '<' || *s == '>' || *s == ':' || *s == '|' || *s == '"' || *s == '.' ) {
  852. *f = '_';
  853. f++;
  854. } else if ( *s == ' ' && *(f-1) == '/' ) { // ignore a space right after a slash
  855. } else if ( *s == ')' || *s == ',' ) { // always ignore these
  856. } else {
  857. *f = *s;
  858. f++;
  859. }
  860. }
  861. *f++ = 0;
  862. strcat( fileName, ".dds" );
  863. }
  864. /*
  865. ==================
  866. NumLevelsForImageSize
  867. ==================
  868. */
  869. int idImage::NumLevelsForImageSize( int width, int height ) const {
  870. int numLevels = 1;
  871. while ( width > 1 || height > 1 ) {
  872. numLevels++;
  873. width >>= 1;
  874. height >>= 1;
  875. }
  876. return numLevels;
  877. }
  878. /*
  879. ================
  880. WritePrecompressedImage
  881. When we are happy with our source data, we can write out precompressed
  882. versions of everything to speed future load times.
  883. ================
  884. */
  885. void idImage::WritePrecompressedImage() {
  886. // Always write the precompressed image if we're making a build
  887. if ( !com_makingBuild.GetBool() ) {
  888. if ( !globalImages->image_writePrecompressedTextures.GetBool() || !globalImages->image_usePrecompressedTextures.GetBool() ) {
  889. return;
  890. }
  891. }
  892. if ( !glConfig.isInitialized ) {
  893. return;
  894. }
  895. char filename[MAX_IMAGE_NAME];
  896. ImageProgramStringToCompressedFileName( imgName, filename );
  897. int numLevels = NumLevelsForImageSize( uploadWidth, uploadHeight );
  898. if ( numLevels > MAX_TEXTURE_LEVELS ) {
  899. common->Warning( "R_WritePrecompressedImage: level > MAX_TEXTURE_LEVELS for image %s", filename );
  900. return;
  901. }
  902. // glGetTexImage only supports a small subset of all the available internal formats
  903. // We have to use BGRA because DDS is a windows based format
  904. int altInternalFormat = 0;
  905. int bitSize = 0;
  906. switch ( internalFormat ) {
  907. case GL_COLOR_INDEX8_EXT:
  908. case GL_COLOR_INDEX:
  909. // this will not work with dds viewers but we need it in this format to save disk
  910. // load speed ( i.e. size )
  911. altInternalFormat = GL_COLOR_INDEX;
  912. bitSize = 24;
  913. break;
  914. case 1:
  915. case GL_INTENSITY8:
  916. case GL_LUMINANCE8:
  917. case 3:
  918. case GL_RGB8:
  919. altInternalFormat = GL_BGR_EXT;
  920. bitSize = 24;
  921. break;
  922. case GL_LUMINANCE8_ALPHA8:
  923. case 4:
  924. case GL_RGBA8:
  925. altInternalFormat = GL_BGRA_EXT;
  926. bitSize = 32;
  927. break;
  928. case GL_ALPHA8:
  929. altInternalFormat = GL_ALPHA;
  930. bitSize = 8;
  931. break;
  932. default:
  933. if ( FormatIsDXT( internalFormat ) ) {
  934. altInternalFormat = internalFormat;
  935. } else {
  936. common->Warning("Unknown or unsupported format for %s", filename);
  937. return;
  938. }
  939. }
  940. if ( globalImages->image_useOffLineCompression.GetBool() && FormatIsDXT( altInternalFormat ) ) {
  941. idStr outFile = fileSystem->RelativePathToOSPath( filename, "fs_basepath" );
  942. idStr inFile = outFile;
  943. inFile.StripFileExtension();
  944. inFile.SetFileExtension( "tga" );
  945. idStr format;
  946. if ( depth == TD_BUMP ) {
  947. format = "RXGB +red 0.0 +green 0.5 +blue 0.5";
  948. } else {
  949. switch ( altInternalFormat ) {
  950. case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
  951. format = "DXT1";
  952. break;
  953. case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  954. format = "DXT1 -alpha_threshold";
  955. break;
  956. case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  957. format = "DXT3";
  958. break;
  959. case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  960. format = "DXT5";
  961. break;
  962. }
  963. }
  964. globalImages->AddDDSCommand( va( "z:/d3xp/compressonator/thecompressonator -convert \"%s\" \"%s\" %s -mipmaps\n", inFile.c_str(), outFile.c_str(), format.c_str() ) );
  965. return;
  966. }
  967. ddsFileHeader_t header;
  968. memset( &header, 0, sizeof(header) );
  969. header.dwSize = sizeof(header);
  970. header.dwFlags = DDSF_CAPS | DDSF_PIXELFORMAT | DDSF_WIDTH | DDSF_HEIGHT;
  971. header.dwHeight = uploadHeight;
  972. header.dwWidth = uploadWidth;
  973. // hack in our monochrome flag for the NV20 optimization
  974. if ( isMonochrome ) {
  975. header.dwFlags |= DDSF_ID_MONOCHROME;
  976. }
  977. if ( FormatIsDXT( altInternalFormat ) ) {
  978. // size (in bytes) of the compressed base image
  979. header.dwFlags |= DDSF_LINEARSIZE;
  980. header.dwPitchOrLinearSize = ( ( uploadWidth + 3 ) / 4 ) * ( ( uploadHeight + 3 ) / 4 )*
  981. (altInternalFormat <= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16);
  982. }
  983. else {
  984. // 4 Byte aligned line width (from nv_dds)
  985. header.dwFlags |= DDSF_PITCH;
  986. header.dwPitchOrLinearSize = ( ( uploadWidth * bitSize + 31 ) & -32 ) >> 3;
  987. }
  988. header.dwCaps1 = DDSF_TEXTURE;
  989. if ( numLevels > 1 ) {
  990. header.dwMipMapCount = numLevels;
  991. header.dwFlags |= DDSF_MIPMAPCOUNT;
  992. header.dwCaps1 |= DDSF_MIPMAP | DDSF_COMPLEX;
  993. }
  994. header.ddspf.dwSize = sizeof(header.ddspf);
  995. if ( FormatIsDXT( altInternalFormat ) ) {
  996. header.ddspf.dwFlags = DDSF_FOURCC;
  997. switch ( altInternalFormat ) {
  998. case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
  999. header.ddspf.dwFourCC = DDS_MAKEFOURCC('D','X','T','1');
  1000. break;
  1001. case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  1002. header.ddspf.dwFlags |= DDSF_ALPHAPIXELS;
  1003. header.ddspf.dwFourCC = DDS_MAKEFOURCC('D','X','T','1');
  1004. break;
  1005. case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  1006. header.ddspf.dwFourCC = DDS_MAKEFOURCC('D','X','T','3');
  1007. break;
  1008. case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  1009. header.ddspf.dwFourCC = DDS_MAKEFOURCC('D','X','T','5');
  1010. break;
  1011. }
  1012. } else {
  1013. header.ddspf.dwFlags = ( internalFormat == GL_COLOR_INDEX8_EXT ) ? DDSF_RGB | DDSF_ID_INDEXCOLOR : DDSF_RGB;
  1014. header.ddspf.dwRGBBitCount = bitSize;
  1015. switch ( altInternalFormat ) {
  1016. case GL_BGRA_EXT:
  1017. case GL_LUMINANCE_ALPHA:
  1018. header.ddspf.dwFlags |= DDSF_ALPHAPIXELS;
  1019. header.ddspf.dwABitMask = 0xFF000000;
  1020. // Fall through
  1021. case GL_BGR_EXT:
  1022. case GL_LUMINANCE:
  1023. case GL_COLOR_INDEX:
  1024. header.ddspf.dwRBitMask = 0x00FF0000;
  1025. header.ddspf.dwGBitMask = 0x0000FF00;
  1026. header.ddspf.dwBBitMask = 0x000000FF;
  1027. break;
  1028. case GL_ALPHA:
  1029. header.ddspf.dwFlags = DDSF_ALPHAPIXELS;
  1030. header.ddspf.dwABitMask = 0xFF000000;
  1031. break;
  1032. default:
  1033. common->Warning( "Unknown or unsupported format for %s", filename );
  1034. return;
  1035. }
  1036. }
  1037. idFile *f = fileSystem->OpenFileWrite( filename );
  1038. if ( f == NULL ) {
  1039. common->Warning( "Could not open %s trying to write precompressed image", filename );
  1040. return;
  1041. }
  1042. common->Printf( "Writing precompressed image: %s\n", filename );
  1043. f->Write( "DDS ", 4 );
  1044. f->Write( &header, sizeof(header) );
  1045. // bind to the image so we can read back the contents
  1046. Bind();
  1047. qglPixelStorei( GL_PACK_ALIGNMENT, 1 ); // otherwise small rows get padded to 32 bits
  1048. int uw = uploadWidth;
  1049. int uh = uploadHeight;
  1050. // Will be allocated first time through the loop
  1051. byte *data = NULL;
  1052. for ( int level = 0 ; level < numLevels ; level++ ) {
  1053. int size = 0;
  1054. if ( FormatIsDXT( altInternalFormat ) ) {
  1055. size = ( ( uw + 3 ) / 4 ) * ( ( uh + 3 ) / 4 ) *
  1056. (altInternalFormat <= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16);
  1057. } else {
  1058. size = uw * uh * (bitSize / 8);
  1059. }
  1060. if (data == NULL) {
  1061. data = (byte *)R_StaticAlloc( size );
  1062. }
  1063. if ( FormatIsDXT( altInternalFormat ) ) {
  1064. qglGetCompressedTexImageARB( GL_TEXTURE_2D, level, data );
  1065. } else {
  1066. qglGetTexImage( GL_TEXTURE_2D, level, altInternalFormat, GL_UNSIGNED_BYTE, data );
  1067. }
  1068. f->Write( data, size );
  1069. uw /= 2;
  1070. uh /= 2;
  1071. if (uw < 1) {
  1072. uw = 1;
  1073. }
  1074. if (uh < 1) {
  1075. uh = 1;
  1076. }
  1077. }
  1078. if (data != NULL) {
  1079. R_StaticFree( data );
  1080. }
  1081. fileSystem->CloseFile( f );
  1082. }
  1083. /*
  1084. ================
  1085. ShouldImageBePartialCached
  1086. Returns true if there is a precompressed image, and it is large enough
  1087. to be worth caching
  1088. ================
  1089. */
  1090. bool idImage::ShouldImageBePartialCached() {
  1091. if ( !glConfig.textureCompressionAvailable ) {
  1092. return false;
  1093. }
  1094. if ( !globalImages->image_useCache.GetBool() ) {
  1095. return false;
  1096. }
  1097. // the allowDownSize flag does double-duty as don't-partial-load
  1098. if ( !allowDownSize ) {
  1099. return false;
  1100. }
  1101. if ( globalImages->image_cacheMinK.GetInteger() <= 0 ) {
  1102. return false;
  1103. }
  1104. // if we are doing a copyFiles, make sure the original images are referenced
  1105. if ( fileSystem->PerformingCopyFiles() ) {
  1106. return false;
  1107. }
  1108. char filename[MAX_IMAGE_NAME];
  1109. ImageProgramStringToCompressedFileName( imgName, filename );
  1110. // get the file timestamp
  1111. fileSystem->ReadFile( filename, NULL, &timestamp );
  1112. if ( timestamp == FILE_NOT_FOUND_TIMESTAMP ) {
  1113. return false;
  1114. }
  1115. // open it and get the file size
  1116. idFile *f;
  1117. f = fileSystem->OpenFileRead( filename );
  1118. if ( !f ) {
  1119. return false;
  1120. }
  1121. int len = f->Length();
  1122. fileSystem->CloseFile( f );
  1123. if ( len <= globalImages->image_cacheMinK.GetInteger() * 1024 ) {
  1124. return false;
  1125. }
  1126. // we do want to do a partial load
  1127. return true;
  1128. }
  1129. /*
  1130. ================
  1131. CheckPrecompressedImage
  1132. If fullLoad is false, only the small mip levels of the image will be loaded
  1133. ================
  1134. */
  1135. bool idImage::CheckPrecompressedImage( bool fullLoad ) {
  1136. if ( !glConfig.isInitialized || !glConfig.textureCompressionAvailable ) {
  1137. return false;
  1138. }
  1139. #if 1 // ( _D3XP had disabled ) - Allow grabbing of DDS's from original Doom pak files
  1140. // if we are doing a copyFiles, make sure the original images are referenced
  1141. if ( fileSystem->PerformingCopyFiles() ) {
  1142. return false;
  1143. }
  1144. #endif
  1145. if ( depth == TD_BUMP && globalImages->image_useNormalCompression.GetInteger() != 2 ) {
  1146. return false;
  1147. }
  1148. // god i love last minute hacks :-)
  1149. if ( com_machineSpec.GetInteger() >= 1 && com_videoRam.GetInteger() >= 128 && imgName.Icmpn( "lights/", 7 ) == 0 ) {
  1150. return false;
  1151. }
  1152. char filename[MAX_IMAGE_NAME];
  1153. ImageProgramStringToCompressedFileName( imgName, filename );
  1154. // get the file timestamp
  1155. ID_TIME_T precompTimestamp;
  1156. fileSystem->ReadFile( filename, NULL, &precompTimestamp );
  1157. if ( precompTimestamp == FILE_NOT_FOUND_TIMESTAMP ) {
  1158. return false;
  1159. }
  1160. if ( !generatorFunction && timestamp != FILE_NOT_FOUND_TIMESTAMP ) {
  1161. if ( precompTimestamp < timestamp ) {
  1162. // The image has changed after being precompressed
  1163. return false;
  1164. }
  1165. }
  1166. timestamp = precompTimestamp;
  1167. // open it and just read the header
  1168. idFile *f;
  1169. f = fileSystem->OpenFileRead( filename );
  1170. if ( !f ) {
  1171. return false;
  1172. }
  1173. int len = f->Length();
  1174. if ( len < sizeof( ddsFileHeader_t ) ) {
  1175. fileSystem->CloseFile( f );
  1176. return false;
  1177. }
  1178. if ( !fullLoad && len > globalImages->image_cacheMinK.GetInteger() * 1024 ) {
  1179. len = globalImages->image_cacheMinK.GetInteger() * 1024;
  1180. }
  1181. byte *data = (byte *)R_StaticAlloc( len );
  1182. f->Read( data, len );
  1183. fileSystem->CloseFile( f );
  1184. unsigned long magic = LittleLong( *(unsigned long *)data );
  1185. ddsFileHeader_t *_header = (ddsFileHeader_t *)(data + 4);
  1186. int ddspf_dwFlags = LittleLong( _header->ddspf.dwFlags );
  1187. if ( magic != DDS_MAKEFOURCC('D', 'D', 'S', ' ')) {
  1188. common->Printf( "CheckPrecompressedImage( %s ): magic != 'DDS '\n", imgName.c_str() );
  1189. R_StaticFree( data );
  1190. return false;
  1191. }
  1192. // if we don't support color index textures, we must load the full image
  1193. // should we just expand the 256 color image to 32 bit for upload?
  1194. if ( ddspf_dwFlags & DDSF_ID_INDEXCOLOR && !glConfig.sharedTexturePaletteAvailable ) {
  1195. R_StaticFree( data );
  1196. return false;
  1197. }
  1198. // upload all the levels
  1199. UploadPrecompressedImage( data, len );
  1200. R_StaticFree( data );
  1201. return true;
  1202. }
  1203. /*
  1204. ===================
  1205. UploadPrecompressedImage
  1206. This can be called by the front end during nromal loading,
  1207. or by the backend after a background read of the file
  1208. has completed
  1209. ===================
  1210. */
  1211. void idImage::UploadPrecompressedImage( byte *data, int len ) {
  1212. ddsFileHeader_t *header = (ddsFileHeader_t *)(data + 4);
  1213. // ( not byte swapping dwReserved1 dwReserved2 )
  1214. header->dwSize = LittleLong( header->dwSize );
  1215. header->dwFlags = LittleLong( header->dwFlags );
  1216. header->dwHeight = LittleLong( header->dwHeight );
  1217. header->dwWidth = LittleLong( header->dwWidth );
  1218. header->dwPitchOrLinearSize = LittleLong( header->dwPitchOrLinearSize );
  1219. header->dwDepth = LittleLong( header->dwDepth );
  1220. header->dwMipMapCount = LittleLong( header->dwMipMapCount );
  1221. header->dwCaps1 = LittleLong( header->dwCaps1 );
  1222. header->dwCaps2 = LittleLong( header->dwCaps2 );
  1223. header->ddspf.dwSize = LittleLong( header->ddspf.dwSize );
  1224. header->ddspf.dwFlags = LittleLong( header->ddspf.dwFlags );
  1225. header->ddspf.dwFourCC = LittleLong( header->ddspf.dwFourCC );
  1226. header->ddspf.dwRGBBitCount = LittleLong( header->ddspf.dwRGBBitCount );
  1227. header->ddspf.dwRBitMask = LittleLong( header->ddspf.dwRBitMask );
  1228. header->ddspf.dwGBitMask = LittleLong( header->ddspf.dwGBitMask );
  1229. header->ddspf.dwBBitMask = LittleLong( header->ddspf.dwBBitMask );
  1230. header->ddspf.dwABitMask = LittleLong( header->ddspf.dwABitMask );
  1231. // generate the texture number
  1232. qglGenTextures( 1, &texnum );
  1233. int externalFormat = 0;
  1234. precompressedFile = true;
  1235. uploadWidth = header->dwWidth;
  1236. uploadHeight = header->dwHeight;
  1237. if ( header->ddspf.dwFlags & DDSF_FOURCC ) {
  1238. switch ( header->ddspf.dwFourCC ) {
  1239. case DDS_MAKEFOURCC( 'D', 'X', 'T', '1' ):
  1240. if ( header->ddspf.dwFlags & DDSF_ALPHAPIXELS ) {
  1241. internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
  1242. } else {
  1243. internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
  1244. }
  1245. break;
  1246. case DDS_MAKEFOURCC( 'D', 'X', 'T', '3' ):
  1247. internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
  1248. break;
  1249. case DDS_MAKEFOURCC( 'D', 'X', 'T', '5' ):
  1250. internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
  1251. break;
  1252. case DDS_MAKEFOURCC( 'R', 'X', 'G', 'B' ):
  1253. internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
  1254. break;
  1255. default:
  1256. common->Warning( "Invalid compressed internal format\n" );
  1257. return;
  1258. }
  1259. } else if ( ( header->ddspf.dwFlags & DDSF_RGBA ) && header->ddspf.dwRGBBitCount == 32 ) {
  1260. externalFormat = GL_BGRA_EXT;
  1261. internalFormat = GL_RGBA8;
  1262. } else if ( ( header->ddspf.dwFlags & DDSF_RGB ) && header->ddspf.dwRGBBitCount == 32 ) {
  1263. externalFormat = GL_BGRA_EXT;
  1264. internalFormat = GL_RGBA8;
  1265. } else if ( ( header->ddspf.dwFlags & DDSF_RGB ) && header->ddspf.dwRGBBitCount == 24 ) {
  1266. if ( header->ddspf.dwFlags & DDSF_ID_INDEXCOLOR ) {
  1267. externalFormat = GL_COLOR_INDEX;
  1268. internalFormat = GL_COLOR_INDEX8_EXT;
  1269. } else {
  1270. externalFormat = GL_BGR_EXT;
  1271. internalFormat = GL_RGB8;
  1272. }
  1273. } else if ( header->ddspf.dwRGBBitCount == 8 ) {
  1274. externalFormat = GL_ALPHA;
  1275. internalFormat = GL_ALPHA8;
  1276. } else {
  1277. common->Warning( "Invalid uncompressed internal format\n" );
  1278. return;
  1279. }
  1280. // we need the monochrome flag for the NV20 optimized path
  1281. if ( header->dwFlags & DDSF_ID_MONOCHROME ) {
  1282. isMonochrome = true;
  1283. }
  1284. type = TT_2D; // FIXME: we may want to support pre-compressed cube maps in the future
  1285. Bind();
  1286. int numMipmaps = 1;
  1287. if ( header->dwFlags & DDSF_MIPMAPCOUNT ) {
  1288. numMipmaps = header->dwMipMapCount;
  1289. }
  1290. int uw = uploadWidth;
  1291. int uh = uploadHeight;
  1292. // We may skip some mip maps if we are downsizing
  1293. int skipMip = 0;
  1294. GetDownsize( uploadWidth, uploadHeight );
  1295. byte *imagedata = data + sizeof(ddsFileHeader_t) + 4;
  1296. for ( int i = 0 ; i < numMipmaps; i++ ) {
  1297. int size = 0;
  1298. if ( FormatIsDXT( internalFormat ) ) {
  1299. size = ( ( uw + 3 ) / 4 ) * ( ( uh + 3 ) / 4 ) *
  1300. (internalFormat <= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16);
  1301. } else {
  1302. size = uw * uh * (header->ddspf.dwRGBBitCount / 8);
  1303. }
  1304. if ( uw > uploadWidth || uh > uploadHeight ) {
  1305. skipMip++;
  1306. } else {
  1307. if ( FormatIsDXT( internalFormat ) ) {
  1308. qglCompressedTexImage2DARB( GL_TEXTURE_2D, i - skipMip, internalFormat, uw, uh, 0, size, imagedata );
  1309. } else {
  1310. qglTexImage2D( GL_TEXTURE_2D, i - skipMip, internalFormat, uw, uh, 0, externalFormat, GL_UNSIGNED_BYTE, imagedata );
  1311. }
  1312. }
  1313. imagedata += size;
  1314. uw /= 2;
  1315. uh /= 2;
  1316. if (uw < 1) {
  1317. uw = 1;
  1318. }
  1319. if (uh < 1) {
  1320. uh = 1;
  1321. }
  1322. }
  1323. SetImageFilterAndRepeat();
  1324. }
  1325. /*
  1326. ===============
  1327. ActuallyLoadImage
  1328. Absolutely every image goes through this path
  1329. On exit, the idImage will have a valid OpenGL texture number that can be bound
  1330. ===============
  1331. */
  1332. void idImage::ActuallyLoadImage( bool checkForPrecompressed, bool fromBackEnd ) {
  1333. int width, height;
  1334. byte *pic;
  1335. // this is the ONLY place generatorFunction will ever be called
  1336. if ( generatorFunction ) {
  1337. generatorFunction( this );
  1338. return;
  1339. }
  1340. // if we are a partial image, we are only going to load from a compressed file
  1341. if ( isPartialImage ) {
  1342. if ( CheckPrecompressedImage( false ) ) {
  1343. return;
  1344. }
  1345. // this is an error -- the partial image failed to load
  1346. MakeDefault();
  1347. return;
  1348. }
  1349. //
  1350. // load the image from disk
  1351. //
  1352. if ( cubeFiles != CF_2D ) {
  1353. byte *pics[6];
  1354. // we don't check for pre-compressed cube images currently
  1355. R_LoadCubeImages( imgName, cubeFiles, pics, &width, &timestamp );
  1356. if ( pics[0] == NULL ) {
  1357. common->Warning( "Couldn't load cube image: %s", imgName.c_str() );
  1358. MakeDefault();
  1359. return;
  1360. }
  1361. GenerateCubeImage( (const byte **)pics, width, filter, allowDownSize, depth );
  1362. precompressedFile = false;
  1363. for ( int i = 0 ; i < 6 ; i++ ) {
  1364. if ( pics[i] ) {
  1365. R_StaticFree( pics[i] );
  1366. }
  1367. }
  1368. } else {
  1369. // see if we have a pre-generated image file that is
  1370. // already image processed and compressed
  1371. if ( checkForPrecompressed && globalImages->image_usePrecompressedTextures.GetBool() ) {
  1372. if ( CheckPrecompressedImage( true ) ) {
  1373. // we got the precompressed image
  1374. return;
  1375. }
  1376. // fall through to load the normal image
  1377. }
  1378. R_LoadImageProgram( imgName, &pic, &width, &height, &timestamp, &depth );
  1379. if ( pic == NULL ) {
  1380. common->Warning( "Couldn't load image: %s", imgName.c_str() );
  1381. MakeDefault();
  1382. return;
  1383. }
  1384. /*
  1385. // swap the red and alpha for rxgb support
  1386. // do this even on tga normal maps so we only have to use
  1387. // one fragment program
  1388. // if the image is precompressed ( either in palletized mode or true rxgb mode )
  1389. // then it is loaded above and the swap never happens here
  1390. if ( depth == TD_BUMP && globalImages->image_useNormalCompression.GetInteger() != 1 ) {
  1391. for ( int i = 0; i < width * height * 4; i += 4 ) {
  1392. pic[ i + 3 ] = pic[ i ];
  1393. pic[ i ] = 0;
  1394. }
  1395. }
  1396. */
  1397. // build a hash for checking duplicate image files
  1398. // NOTE: takes about 10% of image load times (SD)
  1399. // may not be strictly necessary, but some code uses it, so let's leave it in
  1400. imageHash = MD4_BlockChecksum( pic, width * height * 4 );
  1401. GenerateImage( pic, width, height, filter, allowDownSize, repeat, depth );
  1402. timestamp = timestamp;
  1403. precompressedFile = false;
  1404. R_StaticFree( pic );
  1405. // write out the precompressed version of this file if needed
  1406. WritePrecompressedImage();
  1407. }
  1408. }
  1409. //=========================================================================================================
  1410. /*
  1411. ===============
  1412. PurgeImage
  1413. ===============
  1414. */
  1415. void idImage::PurgeImage() {
  1416. if ( texnum != TEXTURE_NOT_LOADED ) {
  1417. // sometimes is NULL when exiting with an error
  1418. if ( qglDeleteTextures ) {
  1419. qglDeleteTextures( 1, &texnum ); // this should be the ONLY place it is ever called!
  1420. }
  1421. texnum = TEXTURE_NOT_LOADED;
  1422. }
  1423. // clear all the current binding caches, so the next bind will do a real one
  1424. for ( int i = 0 ; i < MAX_MULTITEXTURE_UNITS ; i++ ) {
  1425. backEnd.glState.tmu[i].current2DMap = -1;
  1426. backEnd.glState.tmu[i].current3DMap = -1;
  1427. backEnd.glState.tmu[i].currentCubeMap = -1;
  1428. }
  1429. }
  1430. /*
  1431. ==============
  1432. Bind
  1433. Automatically enables 2D mapping, cube mapping, or 3D texturing if needed
  1434. ==============
  1435. */
  1436. void idImage::Bind() {
  1437. if ( tr.logFile ) {
  1438. RB_LogComment( "idImage::Bind( %s )\n", imgName.c_str() );
  1439. }
  1440. // if this is an image that we are caching, move it to the front of the LRU chain
  1441. if ( partialImage ) {
  1442. if ( cacheUsageNext ) {
  1443. // unlink from old position
  1444. cacheUsageNext->cacheUsagePrev = cacheUsagePrev;
  1445. cacheUsagePrev->cacheUsageNext = cacheUsageNext;
  1446. }
  1447. // link in at the head of the list
  1448. cacheUsageNext = globalImages->cacheLRU.cacheUsageNext;
  1449. cacheUsagePrev = &globalImages->cacheLRU;
  1450. cacheUsageNext->cacheUsagePrev = this;
  1451. cacheUsagePrev->cacheUsageNext = this;
  1452. }
  1453. // load the image if necessary (FIXME: not SMP safe!)
  1454. if ( texnum == TEXTURE_NOT_LOADED ) {
  1455. if ( partialImage ) {
  1456. // if we have a partial image, go ahead and use that
  1457. this->partialImage->Bind();
  1458. // start a background load of the full thing if it isn't already in the queue
  1459. if ( !backgroundLoadInProgress ) {
  1460. StartBackgroundImageLoad();
  1461. }
  1462. return;
  1463. }
  1464. // load the image on demand here, which isn't our normal game operating mode
  1465. ActuallyLoadImage( true, true ); // check for precompressed, load is from back end
  1466. }
  1467. // bump our statistic counters
  1468. frameUsed = backEnd.frameCount;
  1469. bindCount++;
  1470. tmu_t *tmu = &backEnd.glState.tmu[backEnd.glState.currenttmu];
  1471. // enable or disable apropriate texture modes
  1472. if ( tmu->textureType != type && ( backEnd.glState.currenttmu < glConfig.maxTextureUnits ) ) {
  1473. if ( tmu->textureType == TT_CUBIC ) {
  1474. qglDisable( GL_TEXTURE_CUBE_MAP_EXT );
  1475. } else if ( tmu->textureType == TT_3D ) {
  1476. qglDisable( GL_TEXTURE_3D );
  1477. } else if ( tmu->textureType == TT_2D ) {
  1478. qglDisable( GL_TEXTURE_2D );
  1479. }
  1480. if ( type == TT_CUBIC ) {
  1481. qglEnable( GL_TEXTURE_CUBE_MAP_EXT );
  1482. } else if ( type == TT_3D ) {
  1483. qglEnable( GL_TEXTURE_3D );
  1484. } else if ( type == TT_2D ) {
  1485. qglEnable( GL_TEXTURE_2D );
  1486. }
  1487. tmu->textureType = type;
  1488. }
  1489. // bind the texture
  1490. if ( type == TT_2D ) {
  1491. if ( tmu->current2DMap != texnum ) {
  1492. tmu->current2DMap = texnum;
  1493. qglBindTexture( GL_TEXTURE_2D, texnum );
  1494. }
  1495. } else if ( type == TT_CUBIC ) {
  1496. if ( tmu->currentCubeMap != texnum ) {
  1497. tmu->currentCubeMap = texnum;
  1498. qglBindTexture( GL_TEXTURE_CUBE_MAP_EXT, texnum );
  1499. }
  1500. } else if ( type == TT_3D ) {
  1501. if ( tmu->current3DMap != texnum ) {
  1502. tmu->current3DMap = texnum;
  1503. qglBindTexture( GL_TEXTURE_3D, texnum );
  1504. }
  1505. }
  1506. if ( com_purgeAll.GetBool() ) {
  1507. GLclampf priority = 1.0f;
  1508. qglPrioritizeTextures( 1, &texnum, &priority );
  1509. }
  1510. }
  1511. /*
  1512. ==============
  1513. BindFragment
  1514. Fragment programs explicitly say which type of map they want, so we don't need to
  1515. do any enable / disable changes
  1516. ==============
  1517. */
  1518. void idImage::BindFragment() {
  1519. if ( tr.logFile ) {
  1520. RB_LogComment( "idImage::BindFragment %s )\n", imgName.c_str() );
  1521. }
  1522. // if this is an image that we are caching, move it to the front of the LRU chain
  1523. if ( partialImage ) {
  1524. if ( cacheUsageNext ) {
  1525. // unlink from old position
  1526. cacheUsageNext->cacheUsagePrev = cacheUsagePrev;
  1527. cacheUsagePrev->cacheUsageNext = cacheUsageNext;
  1528. }
  1529. // link in at the head of the list
  1530. cacheUsageNext = globalImages->cacheLRU.cacheUsageNext;
  1531. cacheUsagePrev = &globalImages->cacheLRU;
  1532. cacheUsageNext->cacheUsagePrev = this;
  1533. cacheUsagePrev->cacheUsageNext = this;
  1534. }
  1535. // load the image if necessary (FIXME: not SMP safe!)
  1536. if ( texnum == TEXTURE_NOT_LOADED ) {
  1537. if ( partialImage ) {
  1538. // if we have a partial image, go ahead and use that
  1539. this->partialImage->BindFragment();
  1540. // start a background load of the full thing if it isn't already in the queue
  1541. if ( !backgroundLoadInProgress ) {
  1542. StartBackgroundImageLoad();
  1543. }
  1544. return;
  1545. }
  1546. // load the image on demand here, which isn't our normal game operating mode
  1547. ActuallyLoadImage( true, true ); // check for precompressed, load is from back end
  1548. }
  1549. // bump our statistic counters
  1550. frameUsed = backEnd.frameCount;
  1551. bindCount++;
  1552. // bind the texture
  1553. if ( type == TT_2D ) {
  1554. qglBindTexture( GL_TEXTURE_2D, texnum );
  1555. } else if ( type == TT_RECT ) {
  1556. qglBindTexture( GL_TEXTURE_RECTANGLE_NV, texnum );
  1557. } else if ( type == TT_CUBIC ) {
  1558. qglBindTexture( GL_TEXTURE_CUBE_MAP_EXT, texnum );
  1559. } else if ( type == TT_3D ) {
  1560. qglBindTexture( GL_TEXTURE_3D, texnum );
  1561. }
  1562. }
  1563. /*
  1564. ====================
  1565. CopyFramebuffer
  1566. ====================
  1567. */
  1568. void idImage::CopyFramebuffer( int x, int y, int imageWidth, int imageHeight, bool useOversizedBuffer ) {
  1569. Bind();
  1570. if ( cvarSystem->GetCVarBool( "g_lowresFullscreenFX" ) ) {
  1571. imageWidth = 512;
  1572. imageHeight = 512;
  1573. }
  1574. // if the size isn't a power of 2, the image must be increased in size
  1575. int potWidth, potHeight;
  1576. potWidth = MakePowerOfTwo( imageWidth );
  1577. potHeight = MakePowerOfTwo( imageHeight );
  1578. GetDownsize( imageWidth, imageHeight );
  1579. GetDownsize( potWidth, potHeight );
  1580. qglReadBuffer( GL_BACK );
  1581. // only resize if the current dimensions can't hold it at all,
  1582. // otherwise subview renderings could thrash this
  1583. if ( ( useOversizedBuffer && ( uploadWidth < potWidth || uploadHeight < potHeight ) )
  1584. || ( !useOversizedBuffer && ( uploadWidth != potWidth || uploadHeight != potHeight ) ) ) {
  1585. uploadWidth = potWidth;
  1586. uploadHeight = potHeight;
  1587. if ( potWidth == imageWidth && potHeight == imageHeight ) {
  1588. qglCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, x, y, imageWidth, imageHeight, 0 );
  1589. } else {
  1590. byte *junk;
  1591. // we need to create a dummy image with power of two dimensions,
  1592. // then do a qglCopyTexSubImage2D of the data we want
  1593. // this might be a 16+ meg allocation, which could fail on _alloca
  1594. junk = (byte *)Mem_Alloc( potWidth * potHeight * 4 );
  1595. memset( junk, 0, potWidth * potHeight * 4 ); //!@#
  1596. #if 0 // Disabling because it's unnecessary and introduces a green strip on edge of _currentRender
  1597. for ( int i = 0 ; i < potWidth * potHeight * 4 ; i+=4 ) {
  1598. junk[i+1] = 255;
  1599. }
  1600. #endif
  1601. qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, potWidth, potHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, junk );
  1602. Mem_Free( junk );
  1603. qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, x, y, imageWidth, imageHeight );
  1604. }
  1605. } else {
  1606. // otherwise, just subimage upload it so that drivers can tell we are going to be changing
  1607. // it and don't try and do a texture compression or some other silliness
  1608. qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, x, y, imageWidth, imageHeight );
  1609. }
  1610. // if the image isn't a full power of two, duplicate an extra row and/or column to fix bilerps
  1611. if ( imageWidth != potWidth ) {
  1612. qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, imageWidth, 0, x+imageWidth-1, y, 1, imageHeight );
  1613. }
  1614. if ( imageHeight != potHeight ) {
  1615. qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, imageHeight, x, y+imageHeight-1, imageWidth, 1 );
  1616. }
  1617. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  1618. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  1619. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
  1620. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
  1621. backEnd.c_copyFrameBuffer++;
  1622. }
  1623. /*
  1624. ====================
  1625. CopyDepthbuffer
  1626. This should just be part of copyFramebuffer once we have a proper image type field
  1627. ====================
  1628. */
  1629. void idImage::CopyDepthbuffer( int x, int y, int imageWidth, int imageHeight ) {
  1630. Bind();
  1631. // if the size isn't a power of 2, the image must be increased in size
  1632. int potWidth, potHeight;
  1633. potWidth = MakePowerOfTwo( imageWidth );
  1634. potHeight = MakePowerOfTwo( imageHeight );
  1635. if ( uploadWidth != potWidth || uploadHeight != potHeight ) {
  1636. uploadWidth = potWidth;
  1637. uploadHeight = potHeight;
  1638. if ( potWidth == imageWidth && potHeight == imageHeight ) {
  1639. qglCopyTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, x, y, imageWidth, imageHeight, 0 );
  1640. } else {
  1641. // we need to create a dummy image with power of two dimensions,
  1642. // then do a qglCopyTexSubImage2D of the data we want
  1643. qglTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, potWidth, potHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );
  1644. qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, x, y, imageWidth, imageHeight );
  1645. }
  1646. } else {
  1647. // otherwise, just subimage upload it so that drivers can tell we are going to be changing
  1648. // it and don't try and do a texture compression or some other silliness
  1649. qglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, x, y, imageWidth, imageHeight );
  1650. }
  1651. // qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  1652. // qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  1653. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
  1654. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
  1655. }
  1656. /*
  1657. =============
  1658. RB_UploadScratchImage
  1659. if rows = cols * 6, assume it is a cube map animation
  1660. =============
  1661. */
  1662. void idImage::UploadScratch( const byte *data, int cols, int rows ) {
  1663. int i;
  1664. // if rows = cols * 6, assume it is a cube map animation
  1665. if ( rows == cols * 6 ) {
  1666. if ( type != TT_CUBIC ) {
  1667. type = TT_CUBIC;
  1668. uploadWidth = -1; // for a non-sub upload
  1669. }
  1670. Bind();
  1671. rows /= 6;
  1672. // if the scratchImage isn't in the format we want, specify it as a new texture
  1673. if ( cols != uploadWidth || rows != uploadHeight ) {
  1674. uploadWidth = cols;
  1675. uploadHeight = rows;
  1676. // upload the base level
  1677. for ( i = 0 ; i < 6 ; i++ ) {
  1678. qglTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT+i, 0, GL_RGB8, cols, rows, 0,
  1679. GL_RGBA, GL_UNSIGNED_BYTE, data + cols*rows*4*i );
  1680. }
  1681. } else {
  1682. // otherwise, just subimage upload it so that drivers can tell we are going to be changing
  1683. // it and don't try and do a texture compression
  1684. for ( i = 0 ; i < 6 ; i++ ) {
  1685. qglTexSubImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT+i, 0, 0, 0, cols, rows,
  1686. GL_RGBA, GL_UNSIGNED_BYTE, data + cols*rows*4*i );
  1687. }
  1688. }
  1689. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  1690. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  1691. // no other clamp mode makes sense
  1692. qglTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  1693. qglTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  1694. } else {
  1695. // otherwise, it is a 2D image
  1696. if ( type != TT_2D ) {
  1697. type = TT_2D;
  1698. uploadWidth = -1; // for a non-sub upload
  1699. }
  1700. Bind();
  1701. // if the scratchImage isn't in the format we want, specify it as a new texture
  1702. if ( cols != uploadWidth || rows != uploadHeight ) {
  1703. uploadWidth = cols;
  1704. uploadHeight = rows;
  1705. qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
  1706. } else {
  1707. // otherwise, just subimage upload it so that drivers can tell we are going to be changing
  1708. // it and don't try and do a texture compression
  1709. qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );
  1710. }
  1711. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  1712. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  1713. // these probably should be clamp, but we have a lot of issues with editor
  1714. // geometry coming out with texcoords slightly off one side, resulting in
  1715. // a smear across the entire polygon
  1716. #if 1
  1717. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
  1718. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
  1719. #else
  1720. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
  1721. qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
  1722. #endif
  1723. }
  1724. }
  1725. void idImage::SetClassification( int tag ) {
  1726. classification = tag;
  1727. }
  1728. /*
  1729. ==================
  1730. StorageSize
  1731. ==================
  1732. */
  1733. int idImage::StorageSize() const {
  1734. int baseSize;
  1735. if ( texnum == TEXTURE_NOT_LOADED ) {
  1736. return 0;
  1737. }
  1738. switch ( type ) {
  1739. default:
  1740. case TT_2D:
  1741. baseSize = uploadWidth*uploadHeight;
  1742. break;
  1743. case TT_3D:
  1744. baseSize = uploadWidth*uploadHeight*uploadDepth;
  1745. break;
  1746. case TT_CUBIC:
  1747. baseSize = 6 * uploadWidth*uploadHeight;
  1748. break;
  1749. }
  1750. baseSize *= BitsForInternalFormat( internalFormat );
  1751. baseSize /= 8;
  1752. // account for mip mapping
  1753. baseSize = baseSize * 4 / 3;
  1754. return baseSize;
  1755. }
  1756. /*
  1757. ==================
  1758. Print
  1759. ==================
  1760. */
  1761. void idImage::Print() const {
  1762. if ( precompressedFile ) {
  1763. common->Printf( "P" );
  1764. } else if ( generatorFunction ) {
  1765. common->Printf( "F" );
  1766. } else {
  1767. common->Printf( " " );
  1768. }
  1769. switch ( type ) {
  1770. case TT_2D:
  1771. common->Printf( " " );
  1772. break;
  1773. case TT_3D:
  1774. common->Printf( "3" );
  1775. break;
  1776. case TT_CUBIC:
  1777. common->Printf( "C" );
  1778. break;
  1779. case TT_RECT:
  1780. common->Printf( "R" );
  1781. break;
  1782. default:
  1783. common->Printf( "<BAD TYPE:%i>", type );
  1784. break;
  1785. }
  1786. common->Printf( "%4i %4i ", uploadWidth, uploadHeight );
  1787. switch( filter ) {
  1788. case TF_DEFAULT:
  1789. common->Printf( "dflt " );
  1790. break;
  1791. case TF_LINEAR:
  1792. common->Printf( "linr " );
  1793. break;
  1794. case TF_NEAREST:
  1795. common->Printf( "nrst " );
  1796. break;
  1797. default:
  1798. common->Printf( "<BAD FILTER:%i>", filter );
  1799. break;
  1800. }
  1801. switch ( internalFormat ) {
  1802. case GL_INTENSITY8:
  1803. case 1:
  1804. common->Printf( "I " );
  1805. break;
  1806. case 2:
  1807. case GL_LUMINANCE8_ALPHA8:
  1808. common->Printf( "LA " );
  1809. break;
  1810. case 3:
  1811. common->Printf( "RGB " );
  1812. break;
  1813. case 4:
  1814. common->Printf( "RGBA " );
  1815. break;
  1816. case GL_LUMINANCE8:
  1817. common->Printf( "L " );
  1818. break;
  1819. case GL_ALPHA8:
  1820. common->Printf( "A " );
  1821. break;
  1822. case GL_RGBA8:
  1823. common->Printf( "RGBA8 " );
  1824. break;
  1825. case GL_RGB8:
  1826. common->Printf( "RGB8 " );
  1827. break;
  1828. case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
  1829. common->Printf( "DXT1 " );
  1830. break;
  1831. case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  1832. common->Printf( "DXT1A " );
  1833. break;
  1834. case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  1835. common->Printf( "DXT3 " );
  1836. break;
  1837. case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  1838. common->Printf( "DXT5 " );
  1839. break;
  1840. case GL_RGBA4:
  1841. common->Printf( "RGBA4 " );
  1842. break;
  1843. case GL_RGB5:
  1844. common->Printf( "RGB5 " );
  1845. break;
  1846. case GL_COLOR_INDEX8_EXT:
  1847. common->Printf( "CI8 " );
  1848. break;
  1849. case GL_COLOR_INDEX:
  1850. common->Printf( "CI " );
  1851. break;
  1852. case GL_COMPRESSED_RGB_ARB:
  1853. common->Printf( "RGBC " );
  1854. break;
  1855. case GL_COMPRESSED_RGBA_ARB:
  1856. common->Printf( "RGBAC " );
  1857. break;
  1858. case 0:
  1859. common->Printf( " " );
  1860. break;
  1861. default:
  1862. common->Printf( "<BAD FORMAT:%i>", internalFormat );
  1863. break;
  1864. }
  1865. switch ( repeat ) {
  1866. case TR_REPEAT:
  1867. common->Printf( "rept " );
  1868. break;
  1869. case TR_CLAMP_TO_ZERO:
  1870. common->Printf( "zero " );
  1871. break;
  1872. case TR_CLAMP_TO_ZERO_ALPHA:
  1873. common->Printf( "azro " );
  1874. break;
  1875. case TR_CLAMP:
  1876. common->Printf( "clmp " );
  1877. break;
  1878. default:
  1879. common->Printf( "<BAD REPEAT:%i>", repeat );
  1880. break;
  1881. }
  1882. common->Printf( "%4ik ", StorageSize() / 1024 );
  1883. common->Printf( " %s\n", imgName.c_str() );
  1884. }