ImageManager.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition 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 BFG Edition 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. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. #include "tr_local.h"
  23. // do this with a pointer, in case we want to make the actual manager
  24. // a private virtual subclass
  25. idImageManager imageManager;
  26. idImageManager * globalImages = &imageManager;
  27. idCVar preLoad_Images( "preLoad_Images", "1", CVAR_SYSTEM | CVAR_BOOL, "preload images during beginlevelload" );
  28. /*
  29. ===============
  30. R_ReloadImages_f
  31. Regenerate all images that came directly from files that have changed, so
  32. any saved changes will show up in place.
  33. New r_texturesize/r_texturedepth variables will take effect on reload
  34. reloadImages <all>
  35. ===============
  36. */
  37. void R_ReloadImages_f( const idCmdArgs &args ) {
  38. bool all = false;
  39. if ( args.Argc() == 2 ) {
  40. if ( !idStr::Icmp( args.Argv(1), "all" ) ) {
  41. all = true;
  42. } else {
  43. common->Printf( "USAGE: reloadImages <all>\n" );
  44. return;
  45. }
  46. }
  47. globalImages->ReloadImages( all );
  48. }
  49. typedef struct {
  50. idImage *image;
  51. int size;
  52. int index;
  53. } sortedImage_t;
  54. /*
  55. =======================
  56. R_QsortImageSizes
  57. =======================
  58. */
  59. static int R_QsortImageSizes( const void *a, const void *b ) {
  60. const sortedImage_t *ea, *eb;
  61. ea = (sortedImage_t *)a;
  62. eb = (sortedImage_t *)b;
  63. if ( ea->size > eb->size ) {
  64. return -1;
  65. }
  66. if ( ea->size < eb->size ) {
  67. return 1;
  68. }
  69. return idStr::Icmp( ea->image->GetName(), eb->image->GetName() );
  70. }
  71. /*
  72. =======================
  73. R_QsortImageName
  74. =======================
  75. */
  76. static int R_QsortImageName( const void* a, const void* b ) {
  77. const sortedImage_t *ea, *eb;
  78. ea = (sortedImage_t *)a;
  79. eb = (sortedImage_t *)b;
  80. return idStr::Icmp( ea->image->GetName(), eb->image->GetName() );
  81. }
  82. /*
  83. ===============
  84. R_ListImages_f
  85. ===============
  86. */
  87. void R_ListImages_f( const idCmdArgs &args ) {
  88. int i, partialSize;
  89. idImage *image;
  90. int totalSize;
  91. int count = 0;
  92. bool uncompressedOnly = false;
  93. bool unloaded = false;
  94. bool failed = false;
  95. bool sorted = false;
  96. bool duplicated = false;
  97. bool overSized = false;
  98. bool sortByName = false;
  99. if ( args.Argc() == 1 ) {
  100. } else if ( args.Argc() == 2 ) {
  101. if ( idStr::Icmp( args.Argv( 1 ), "uncompressed" ) == 0 ) {
  102. uncompressedOnly = true;
  103. } else if ( idStr::Icmp( args.Argv( 1 ), "sorted" ) == 0 ) {
  104. sorted = true;
  105. } else if ( idStr::Icmp( args.Argv( 1 ), "namesort" ) == 0 ) {
  106. sortByName = true;
  107. } else if ( idStr::Icmp( args.Argv( 1 ), "unloaded" ) == 0 ) {
  108. unloaded = true;
  109. } else if ( idStr::Icmp( args.Argv( 1 ), "duplicated" ) == 0 ) {
  110. duplicated = true;
  111. } else if ( idStr::Icmp( args.Argv( 1 ), "oversized" ) == 0 ) {
  112. sorted = true;
  113. overSized = true;
  114. } else {
  115. failed = true;
  116. }
  117. } else {
  118. failed = true;
  119. }
  120. if ( failed ) {
  121. common->Printf( "usage: listImages [ sorted | namesort | unloaded | duplicated | showOverSized ]\n" );
  122. return;
  123. }
  124. const char *header = " -w-- -h-- filt -fmt-- wrap size --name-------\n";
  125. common->Printf( "\n%s", header );
  126. totalSize = 0;
  127. sortedImage_t *sortedArray = (sortedImage_t *)alloca( sizeof( sortedImage_t ) * globalImages->images.Num() );
  128. for ( i = 0 ; i < globalImages->images.Num() ; i++ ) {
  129. image = globalImages->images[ i ];
  130. if ( uncompressedOnly ) {
  131. if ( image->IsCompressed() ) {
  132. continue;
  133. }
  134. }
  135. if ( unloaded == image->IsLoaded() ) {
  136. continue;
  137. }
  138. // only print duplicates (from mismatched wrap / clamp, etc)
  139. if ( duplicated ) {
  140. int j;
  141. for ( j = i+1 ; j < globalImages->images.Num() ; j++ ) {
  142. if ( idStr::Icmp( image->GetName(), globalImages->images[ j ]->GetName() ) == 0 ) {
  143. break;
  144. }
  145. }
  146. if ( j == globalImages->images.Num() ) {
  147. continue;
  148. }
  149. }
  150. if ( sorted || sortByName ) {
  151. sortedArray[count].image = image;
  152. sortedArray[count].size = image->StorageSize();
  153. sortedArray[count].index = i;
  154. } else {
  155. common->Printf( "%4i:", i );
  156. image->Print();
  157. }
  158. totalSize += image->StorageSize();
  159. count++;
  160. }
  161. if ( sorted || sortByName ) {
  162. if ( sortByName) {
  163. qsort( sortedArray, count, sizeof( sortedImage_t ), R_QsortImageName );
  164. } else {
  165. qsort( sortedArray, count, sizeof( sortedImage_t ), R_QsortImageSizes );
  166. }
  167. partialSize = 0;
  168. for ( i = 0 ; i < count ; i++ ) {
  169. common->Printf( "%4i:", sortedArray[i].index );
  170. sortedArray[i].image->Print();
  171. partialSize += sortedArray[i].image->StorageSize();
  172. if ( ( (i+1) % 10 ) == 0 ) {
  173. common->Printf( "-------- %5.1f of %5.1f megs --------\n",
  174. partialSize / (1024*1024.0), totalSize / (1024*1024.0) );
  175. }
  176. }
  177. }
  178. common->Printf( "%s", header );
  179. common->Printf( " %i images (%i total)\n", count, globalImages->images.Num() );
  180. common->Printf( " %5.1f total megabytes of images\n\n\n", totalSize / (1024*1024.0) );
  181. }
  182. /*
  183. ==============
  184. AllocImage
  185. Allocates an idImage, adds it to the list,
  186. copies the name, and adds it to the hash chain.
  187. ==============
  188. */
  189. idImage *idImageManager::AllocImage( const char *name ) {
  190. if (strlen(name) >= MAX_IMAGE_NAME ) {
  191. common->Error ("idImageManager::AllocImage: \"%s\" is too long\n", name);
  192. }
  193. int hash = idStr( name ).FileNameHash();
  194. idImage * image = new (TAG_IMAGE) idImage( name );
  195. imageHash.Add( hash, images.Append( image ) );
  196. return image;
  197. }
  198. /*
  199. ==============
  200. AllocStandaloneImage
  201. Allocates an idImage,does not add it to the list or hash chain
  202. ==============
  203. */
  204. idImage *idImageManager::AllocStandaloneImage( const char *name ) {
  205. if (strlen(name) >= MAX_IMAGE_NAME ) {
  206. common->Error ("idImageManager::AllocImage: \"%s\" is too long\n", name);
  207. }
  208. idImage * image = new (TAG_IMAGE) idImage( name );
  209. return image;
  210. }
  211. /*
  212. ==================
  213. ImageFromFunction
  214. Images that are procedurally generated are allways specified
  215. with a callback which must work at any time, allowing the OpenGL
  216. system to be completely regenerated if needed.
  217. ==================
  218. */
  219. idImage *idImageManager::ImageFromFunction( const char *_name, void (*generatorFunction)( idImage *image ) ) {
  220. // strip any .tga file extensions from anywhere in the _name
  221. idStr name = _name;
  222. name.Replace( ".tga", "" );
  223. name.BackSlashesToSlashes();
  224. // see if the image already exists
  225. int hash = name.FileNameHash();
  226. for ( int i = imageHash.First( hash ); i != -1; i = imageHash.Next( i ) ) {
  227. idImage * image = images[i];
  228. if ( name.Icmp( image->GetName() ) == 0 ) {
  229. if ( image->generatorFunction != generatorFunction ) {
  230. common->DPrintf( "WARNING: reused image %s with mixed generators\n", name.c_str() );
  231. }
  232. return image;
  233. }
  234. }
  235. // create the image and issue the callback
  236. idImage * image = AllocImage( name );
  237. image->generatorFunction = generatorFunction;
  238. // check for precompressed, load is from the front end
  239. image->referencedOutsideLevelLoad = true;
  240. image->ActuallyLoadImage( false );
  241. return image;
  242. }
  243. /*
  244. ===============
  245. GetImageWithParameters
  246. ==============
  247. */
  248. idImage *idImageManager::GetImageWithParameters( const char *_name, textureFilter_t filter, textureRepeat_t repeat, textureUsage_t usage, cubeFiles_t cubeMap ) const {
  249. if ( !_name || !_name[0] || idStr::Icmp( _name, "default" ) == 0 || idStr::Icmp( _name, "_default" ) == 0 ) {
  250. declManager->MediaPrint( "DEFAULTED\n" );
  251. return globalImages->defaultImage;
  252. }
  253. if ( idStr::Icmpn( _name, "fonts", 5 ) == 0 || idStr::Icmpn( _name, "newfonts", 8 ) == 0 ) {
  254. usage = TD_FONT;
  255. }
  256. if ( idStr::Icmpn( _name, "lights", 6 ) == 0 ) {
  257. usage = TD_LIGHT;
  258. }
  259. // strip any .tga file extensions from anywhere in the _name, including image program parameters
  260. idStrStatic< MAX_OSPATH > name = _name;
  261. name.Replace( ".tga", "" );
  262. name.BackSlashesToSlashes();
  263. int hash = name.FileNameHash();
  264. for ( int i = imageHash.First( hash ); i != -1; i = imageHash.Next( i ) ) {
  265. idImage * image = images[i];
  266. if ( name.Icmp( image->GetName() ) == 0 ) {
  267. // the built in's, like _white and _flat always match the other options
  268. if ( name[0] == '_' ) {
  269. return image;
  270. }
  271. if ( image->cubeFiles != cubeMap ) {
  272. common->Error( "Image '%s' has been referenced with conflicting cube map states", _name );
  273. }
  274. if ( image->filter != filter || image->repeat != repeat ) {
  275. // we might want to have the system reset these parameters on every bind and
  276. // share the image data
  277. continue;
  278. }
  279. if ( image->usage != usage ) {
  280. // If an image is used differently then we need 2 copies of it because usage affects the way it's compressed and swizzled
  281. continue;
  282. }
  283. return image;
  284. }
  285. }
  286. return NULL;
  287. }
  288. /*
  289. ===============
  290. ImageFromFile
  291. Finds or loads the given image, always returning a valid image pointer.
  292. Loading of the image may be deferred for dynamic loading.
  293. ==============
  294. */
  295. idImage *idImageManager::ImageFromFile( const char *_name, textureFilter_t filter,
  296. textureRepeat_t repeat, textureUsage_t usage, cubeFiles_t cubeMap ) {
  297. if ( !_name || !_name[0] || idStr::Icmp( _name, "default" ) == 0 || idStr::Icmp( _name, "_default" ) == 0 ) {
  298. declManager->MediaPrint( "DEFAULTED\n" );
  299. return globalImages->defaultImage;
  300. }
  301. if ( idStr::Icmpn( _name, "fonts", 5 ) == 0 || idStr::Icmpn( _name, "newfonts", 8 ) == 0 ) {
  302. usage = TD_FONT;
  303. }
  304. if ( idStr::Icmpn( _name, "lights", 6 ) == 0 ) {
  305. usage = TD_LIGHT;
  306. }
  307. // strip any .tga file extensions from anywhere in the _name, including image program parameters
  308. idStrStatic< MAX_OSPATH > name = _name;
  309. name.Replace( ".tga", "" );
  310. name.BackSlashesToSlashes();
  311. //
  312. // see if the image is already loaded, unless we
  313. // are in a reloadImages call
  314. //
  315. int hash = name.FileNameHash();
  316. for ( int i = imageHash.First( hash ); i != -1; i = imageHash.Next( i ) ) {
  317. idImage * image = images[i];
  318. if ( name.Icmp( image->GetName() ) == 0 ) {
  319. // the built in's, like _white and _flat always match the other options
  320. if ( name[0] == '_' ) {
  321. return image;
  322. }
  323. if ( image->cubeFiles != cubeMap ) {
  324. common->Error( "Image '%s' has been referenced with conflicting cube map states", _name );
  325. }
  326. if ( image->filter != filter || image->repeat != repeat ) {
  327. // we might want to have the system reset these parameters on every bind and
  328. // share the image data
  329. continue;
  330. }
  331. if ( image->usage != usage ) {
  332. // If an image is used differently then we need 2 copies of it because usage affects the way it's compressed and swizzled
  333. continue;
  334. }
  335. image->usage = usage;
  336. image->levelLoadReferenced = true;
  337. if ( ( !insideLevelLoad || preloadingMapImages ) && !image->IsLoaded() ) {
  338. image->referencedOutsideLevelLoad = ( !insideLevelLoad && !preloadingMapImages );
  339. image->ActuallyLoadImage( false ); // load is from front end
  340. declManager->MediaPrint( "%ix%i %s (reload for mixed referneces)\n", image->GetUploadWidth(), image->GetUploadHeight(), image->GetName() );
  341. }
  342. return image;
  343. }
  344. }
  345. //
  346. // create a new image
  347. //
  348. idImage * image = AllocImage( name );
  349. image->cubeFiles = cubeMap;
  350. image->usage = usage;
  351. image->filter = filter;
  352. image->repeat = repeat;
  353. image->levelLoadReferenced = true;
  354. // load it if we aren't in a level preload
  355. if ( !insideLevelLoad || preloadingMapImages ) {
  356. image->referencedOutsideLevelLoad = ( !insideLevelLoad && !preloadingMapImages );
  357. image->ActuallyLoadImage( false ); // load is from front end
  358. declManager->MediaPrint( "%ix%i %s\n", image->GetUploadWidth(), image->GetUploadHeight(), image->GetName() );
  359. } else {
  360. declManager->MediaPrint( "%s\n", image->GetName() );
  361. }
  362. return image;
  363. }
  364. /*
  365. ========================
  366. idImageManager::ScratchImage
  367. ========================
  368. */
  369. idImage * idImageManager::ScratchImage( const char *_name, idImageOpts *imgOpts, textureFilter_t filter, textureRepeat_t repeat, textureUsage_t usage ) {
  370. if ( !_name || !_name[0] ) {
  371. idLib::FatalError( "idImageManager::ScratchImage called with empty name" );
  372. }
  373. if ( imgOpts == NULL ) {
  374. idLib::FatalError( "idImageManager::ScratchImage called with NULL imgOpts" );
  375. }
  376. idStr name = _name;
  377. //
  378. // see if the image is already loaded, unless we
  379. // are in a reloadImages call
  380. //
  381. int hash = name.FileNameHash();
  382. for ( int i = imageHash.First( hash ); i != -1; i = imageHash.Next( i ) ) {
  383. idImage * image = images[i];
  384. if ( name.Icmp( image->GetName() ) == 0 ) {
  385. // the built in's, like _white and _flat always match the other options
  386. if ( name[0] == '_' ) {
  387. return image;
  388. }
  389. if ( image->filter != filter || image->repeat != repeat ) {
  390. // we might want to have the system reset these parameters on every bind and
  391. // share the image data
  392. continue;
  393. }
  394. if ( image->usage != usage ) {
  395. // If an image is used differently then we need 2 copies of it because usage affects the way it's compressed and swizzled
  396. continue;
  397. }
  398. image->usage = usage;
  399. image->levelLoadReferenced = true;
  400. image->referencedOutsideLevelLoad = true;
  401. return image;
  402. }
  403. }
  404. // clamp is the only repeat mode that makes sense for cube maps, but
  405. // some platforms let them stay in repeat mode and get border seam issues
  406. if ( imgOpts->textureType == TT_CUBIC && repeat != TR_CLAMP ) {
  407. repeat = TR_CLAMP;
  408. }
  409. //
  410. // create a new image
  411. //
  412. idImage* newImage = AllocImage( name );
  413. if ( newImage != NULL ) {
  414. newImage->AllocImage( *imgOpts, filter, repeat );
  415. }
  416. return newImage;
  417. }
  418. /*
  419. ===============
  420. idImageManager::GetImage
  421. ===============
  422. */
  423. idImage *idImageManager::GetImage( const char *_name ) const {
  424. if ( !_name || !_name[0] || idStr::Icmp( _name, "default" ) == 0 || idStr::Icmp( _name, "_default" ) == 0 ) {
  425. declManager->MediaPrint( "DEFAULTED\n" );
  426. return globalImages->defaultImage;
  427. }
  428. // strip any .tga file extensions from anywhere in the _name, including image program parameters
  429. idStr name = _name;
  430. name.Replace( ".tga", "" );
  431. name.BackSlashesToSlashes();
  432. //
  433. // look in loaded images
  434. //
  435. int hash = name.FileNameHash();
  436. for ( int i = imageHash.First( hash ); i != -1; i = imageHash.Next( i ) ) {
  437. idImage * image = images[i];
  438. if ( name.Icmp( image->GetName() ) == 0 ) {
  439. return image;
  440. }
  441. }
  442. return NULL;
  443. }
  444. /*
  445. ===============
  446. PurgeAllImages
  447. ===============
  448. */
  449. void idImageManager::PurgeAllImages() {
  450. int i;
  451. idImage *image;
  452. for ( i = 0; i < images.Num() ; i++ ) {
  453. image = images[i];
  454. image->PurgeImage();
  455. }
  456. }
  457. /*
  458. ===============
  459. ReloadImages
  460. ===============
  461. */
  462. void idImageManager::ReloadImages( bool all ) {
  463. for ( int i = 0 ; i < globalImages->images.Num() ; i++ ) {
  464. globalImages->images[ i ]->Reload( all );
  465. }
  466. }
  467. /*
  468. ===============
  469. R_CombineCubeImages_f
  470. Used to combine animations of six separate tga files into
  471. a serials of 6x taller tga files, for preparation to roq compress
  472. ===============
  473. */
  474. void R_CombineCubeImages_f( const idCmdArgs &args ) {
  475. if ( args.Argc() != 2 ) {
  476. common->Printf( "usage: combineCubeImages <baseName>\n" );
  477. common->Printf( " combines basename[1-6][0001-9999].tga to basenameCM[0001-9999].tga\n" );
  478. common->Printf( " 1: forward 2:right 3:back 4:left 5:up 6:down\n" );
  479. return;
  480. }
  481. idStr baseName = args.Argv( 1 );
  482. common->SetRefreshOnPrint( true );
  483. for ( int frameNum = 1 ; frameNum < 10000 ; frameNum++ ) {
  484. char filename[MAX_IMAGE_NAME];
  485. byte *pics[6];
  486. int width = 0, height = 0;
  487. int side;
  488. int orderRemap[6] = { 1,3,4,2,5,6 };
  489. for ( side = 0 ; side < 6 ; side++ ) {
  490. sprintf( filename, "%s%i%04i.tga", baseName.c_str(), orderRemap[side], frameNum );
  491. common->Printf( "reading %s\n", filename );
  492. R_LoadImage( filename, &pics[side], &width, &height, NULL, true );
  493. if ( !pics[side] ) {
  494. common->Printf( "not found.\n" );
  495. break;
  496. }
  497. // convert from "camera" images to native cube map images
  498. switch( side ) {
  499. case 0: // forward
  500. R_RotatePic( pics[side], width);
  501. break;
  502. case 1: // back
  503. R_RotatePic( pics[side], width);
  504. R_HorizontalFlip( pics[side], width, height );
  505. R_VerticalFlip( pics[side], width, height );
  506. break;
  507. case 2: // left
  508. R_VerticalFlip( pics[side], width, height );
  509. break;
  510. case 3: // right
  511. R_HorizontalFlip( pics[side], width, height );
  512. break;
  513. case 4: // up
  514. R_RotatePic( pics[side], width);
  515. break;
  516. case 5: // down
  517. R_RotatePic( pics[side], width);
  518. break;
  519. }
  520. }
  521. if ( side != 6 ) {
  522. for ( int i = 0 ; i < side ; side++ ) {
  523. Mem_Free( pics[side] );
  524. }
  525. break;
  526. }
  527. idTempArray<byte> buf( width*height*6*4 );
  528. byte *combined = (byte *)buf.Ptr();
  529. for ( side = 0 ; side < 6 ; side++ ) {
  530. memcpy( combined+width*height*4*side, pics[side], width*height*4 );
  531. Mem_Free( pics[side] );
  532. }
  533. sprintf( filename, "%sCM%04i.tga", baseName.c_str(), frameNum );
  534. common->Printf( "writing %s\n", filename );
  535. R_WriteTGA( filename, combined, width, height*6 );
  536. }
  537. common->SetRefreshOnPrint( false );
  538. }
  539. /*
  540. ===============
  541. UnbindAll
  542. ===============
  543. */
  544. void idImageManager::UnbindAll() {
  545. int oldTMU = backEnd.glState.currenttmu;
  546. for ( int i = 0; i < MAX_PROG_TEXTURE_PARMS; ++i ) {
  547. backEnd.glState.currenttmu = i;
  548. BindNull();
  549. }
  550. backEnd.glState.currenttmu = oldTMU;
  551. }
  552. /*
  553. ===============
  554. BindNull
  555. ===============
  556. */
  557. void idImageManager::BindNull() {
  558. RENDERLOG_PRINTF( "BindNull()\n" );
  559. }
  560. /*
  561. ===============
  562. Init
  563. ===============
  564. */
  565. void idImageManager::Init() {
  566. images.Resize( 1024, 1024 );
  567. imageHash.ResizeIndex( 1024 );
  568. CreateIntrinsicImages();
  569. cmdSystem->AddCommand( "reloadImages", R_ReloadImages_f, CMD_FL_RENDERER, "reloads images" );
  570. cmdSystem->AddCommand( "listImages", R_ListImages_f, CMD_FL_RENDERER, "lists images" );
  571. cmdSystem->AddCommand( "combineCubeImages", R_CombineCubeImages_f, CMD_FL_RENDERER, "combines six images for roq compression" );
  572. // should forceLoadImages be here?
  573. }
  574. /*
  575. ===============
  576. Shutdown
  577. ===============
  578. */
  579. void idImageManager::Shutdown() {
  580. images.DeleteContents( true );
  581. imageHash.Clear();
  582. }
  583. /*
  584. ====================
  585. idImageManager::BeginLevelLoad
  586. Frees all images used by the previous level
  587. ====================
  588. */
  589. void idImageManager::BeginLevelLoad() {
  590. insideLevelLoad = true;
  591. for ( int i = 0 ; i < images.Num() ; i++ ) {
  592. idImage *image = images[ i ];
  593. // generator function images are always kept around
  594. if ( image->generatorFunction ) {
  595. continue;
  596. }
  597. if ( !image->referencedOutsideLevelLoad && image->IsLoaded() ) {
  598. image->PurgeImage();
  599. //idLib::Printf( "purging %s\n", image->GetName() );
  600. } else {
  601. //idLib::Printf( "not purging %s\n", image->GetName() );
  602. }
  603. image->levelLoadReferenced = false;
  604. }
  605. }
  606. /*
  607. ====================
  608. idImageManager::ExcludePreloadImage
  609. ====================
  610. */
  611. bool idImageManager::ExcludePreloadImage( const char *name ) {
  612. idStrStatic< MAX_OSPATH > imgName = name;
  613. imgName.ToLower();
  614. if ( imgName.Find( "newfonts/", false ) >= 0 ) {
  615. return true;
  616. }
  617. if ( imgName.Find( "generated/swf/", false ) >= 0 ) {
  618. return true;
  619. }
  620. if ( imgName.Find( "/loadscreens/", false ) >= 0 ) {
  621. return true;
  622. }
  623. return false;
  624. }
  625. /*
  626. ====================
  627. idImageManager::Preload
  628. ====================
  629. */
  630. void idImageManager::Preload( const idPreloadManifest &manifest, const bool & mapPreload ) {
  631. if ( preLoad_Images.GetBool() && manifest.NumResources() > 0 ) {
  632. // preload this levels images
  633. common->Printf( "Preloading images...\n" );
  634. preloadingMapImages = mapPreload;
  635. int start = Sys_Milliseconds();
  636. int numLoaded = 0;
  637. //fileSystem->StartPreload( preloadImageFiles );
  638. for ( int i = 0; i < manifest.NumResources(); i++ ) {
  639. const preloadEntry_s & p = manifest.GetPreloadByIndex( i );
  640. if ( p.resType == PRELOAD_IMAGE && !ExcludePreloadImage( p.resourceName ) ) {
  641. globalImages->ImageFromFile( p.resourceName, ( textureFilter_t )p.imgData.filter, ( textureRepeat_t )p.imgData.repeat, ( textureUsage_t )p.imgData.usage, ( cubeFiles_t )p.imgData.cubeMap );
  642. numLoaded++;
  643. }
  644. }
  645. //fileSystem->StopPreload();
  646. int end = Sys_Milliseconds();
  647. common->Printf( "%05d images preloaded ( or were already loaded ) in %5.1f seconds\n", numLoaded, ( end - start ) * 0.001 );
  648. common->Printf( "----------------------------------------\n" );
  649. preloadingMapImages = false;
  650. }
  651. }
  652. /*
  653. ===============
  654. idImageManager::LoadLevelImages
  655. ===============
  656. */
  657. int idImageManager::LoadLevelImages( bool pacifier ) {
  658. int loadCount = 0;
  659. for ( int i = 0 ; i < images.Num() ; i++ ) {
  660. if ( pacifier ) {
  661. common->UpdateLevelLoadPacifier();
  662. }
  663. idImage *image = images[ i ];
  664. if ( image->generatorFunction ) {
  665. continue;
  666. }
  667. if ( image->levelLoadReferenced && !image->IsLoaded() ) {
  668. loadCount++;
  669. image->ActuallyLoadImage( false );
  670. }
  671. }
  672. return loadCount;
  673. }
  674. /*
  675. ===============
  676. idImageManager::EndLevelLoad
  677. ===============
  678. */
  679. void idImageManager::EndLevelLoad() {
  680. insideLevelLoad = false;
  681. common->Printf( "----- idImageManager::EndLevelLoad -----\n" );
  682. int start = Sys_Milliseconds();
  683. int loadCount = LoadLevelImages( true );
  684. int end = Sys_Milliseconds();
  685. common->Printf( "%5i images loaded in %5.1f seconds\n", loadCount, (end-start) * 0.001 );
  686. common->Printf( "----------------------------------------\n" );
  687. //R_ListImages_f( idCmdArgs( "sorted sorted", false ) );
  688. }
  689. /*
  690. ===============
  691. idImageManager::StartBuild
  692. ===============
  693. */
  694. void idImageManager::StartBuild() {
  695. }
  696. /*
  697. ===============
  698. idImageManager::FinishBuild
  699. ===============
  700. */
  701. void idImageManager::FinishBuild( bool removeDups ) {
  702. }
  703. /*
  704. ===============
  705. idImageManager::PrintMemInfo
  706. ===============
  707. */
  708. void idImageManager::PrintMemInfo( MemInfo_t *mi ) {
  709. int i, j, total = 0;
  710. int *sortIndex;
  711. idFile *f;
  712. f = fileSystem->OpenFileWrite( mi->filebase + "_images.txt" );
  713. if ( !f ) {
  714. return;
  715. }
  716. // sort first
  717. sortIndex = new (TAG_IMAGE) int[images.Num()];
  718. for ( i = 0; i < images.Num(); i++ ) {
  719. sortIndex[i] = i;
  720. }
  721. for ( i = 0; i < images.Num() - 1; i++ ) {
  722. for ( j = i + 1; j < images.Num(); j++ ) {
  723. if ( images[sortIndex[i]]->StorageSize() < images[sortIndex[j]]->StorageSize() ) {
  724. int temp = sortIndex[i];
  725. sortIndex[i] = sortIndex[j];
  726. sortIndex[j] = temp;
  727. }
  728. }
  729. }
  730. // print next
  731. for ( i = 0; i < images.Num(); i++ ) {
  732. idImage *im = images[sortIndex[i]];
  733. int size;
  734. size = im->StorageSize();
  735. total += size;
  736. f->Printf( "%s %3i %s\n", idStr::FormatNumber( size ).c_str(), im->refCount, im->GetName() );
  737. }
  738. delete [] sortIndex;
  739. mi->imageAssetsTotal = total;
  740. f->Printf( "\nTotal image bytes allocated: %s\n", idStr::FormatNumber( total ).c_str() );
  741. fileSystem->CloseFile( f );
  742. }