texfcach.cpp 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program 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. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: /Commando/Code/ww3d2/texfcach.cpp 5 8/24/01 3:23p Jani_p $ */
  19. /***********************************************************************************************
  20. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : WW3D *
  24. * *
  25. * $Archive:: /Commando/Code/ww3d2/texfcach.cpp $*
  26. * *
  27. * $Author:: Jani_p $*
  28. * *
  29. * $Modtime:: 8/24/01 11:50a $*
  30. * *
  31. * $Revision:: 5 $*
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * TextureFileCache::TextureFileCache -- Open cache. *
  36. * ~TextureFileCache::TextureFileCache -- Shut down texture cache system. *
  37. * TextureFileCache::Save_Texture -- Save the texture into the cache. *
  38. * TextureFileCache::Load_Texture -- Load texture from cache into surface. *
  39. * *TextureFileCache::_Create_File_Name -- Create a file name from prefix *
  40. * *TextureFileCache::Load_Original_Texture_Surface -- Create the initial *
  41. * *TextureFileCache::Open_Texture_Handle -- Set the TextureHandle and Header.. *
  42. * TextureFileCache::Close_Texture_Handle -- Close the current texture so we can open anoth*
  43. * TextureFileCache::Read_Texture -- Read in the texture into surface buffer. *
  44. * *TextureFileCache::Create_First_Texture_As_Surface -- Load first texture into a surface. *
  45. * *TextureFileCache::Find_Cached_Surface -- Search for a texture already cached. *
  46. * TextureFileCache::Add_Cached_Surface -- Add a new cached texture. *
  47. * *TFC::Get_Surface -- Load a texture reduced N times. *
  48. * TextureFileCache::Reset_File -- virtual function to reset file and write out file. *
  49. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  50. #ifdef WW3D_DX8
  51. #include "texfcach.h"
  52. #include "mutex.h"
  53. #include "thread.h"
  54. #include <assert.h>
  55. #include "wwdebug.h"
  56. #include "simplevec.h"
  57. #include "wwstring.h"
  58. #include "textureloader.h"
  59. #include "texture.h"
  60. #include "ffactory.h"
  61. #include <srSurfaceIOManager.hpp>
  62. #include <srExtension.hpp>
  63. #include <srCore.hpp>
  64. #include <srBinIStream.hpp>
  65. #include <srColorSurface.hpp>
  66. #include <srTextureIFace.hpp>
  67. #include <direct.h>
  68. #include <stdlib.h>
  69. #include <stdio.h>
  70. #ifdef _UNIX
  71. #include "osdep.h"
  72. #endif
  73. #define FILE_HEADER_NAME "Texture File Cache Header"
  74. char *TextureFileCache::_FileNamePtr = NULL;
  75. static int Instances=0;
  76. static CriticalSectionClass mutex(0);
  77. static SimpleVecClass<char> compression_buffer;
  78. const char BUFFER_OVERRUN_TEST_VALUE=((char)0x7d);
  79. static char* Get_Compression_Buffer(int size)
  80. {
  81. compression_buffer.Uninitialised_Grow(size+1);
  82. compression_buffer[size]=BUFFER_OVERRUN_TEST_VALUE;
  83. return &(compression_buffer[0]);
  84. }
  85. static void Verify_Compression_Buffer()
  86. {
  87. WWASSERT(compression_buffer[compression_buffer.Length()-1]==BUFFER_OVERRUN_TEST_VALUE);
  88. }
  89. class Compressor
  90. {
  91. public:
  92. static int Compress
  93. (
  94. const unsigned char * in,
  95. unsigned int in_len,
  96. unsigned char * out,
  97. unsigned int * out_len
  98. );
  99. static int Decompress
  100. (
  101. const unsigned char * in,
  102. unsigned int in_len,
  103. unsigned char * out,
  104. unsigned int * out_len
  105. );
  106. };
  107. int Compressor::Compress( const unsigned char * in, unsigned int in_len,
  108. unsigned char * out, unsigned int * out_len )
  109. {
  110. if (!in || !out || !out_len)
  111. return FALSE;
  112. if (in_len <= 0)
  113. return false;
  114. memcpy(out, in, in_len);
  115. *out_len = in_len;
  116. return TRUE;
  117. }
  118. int Compressor::Decompress( const unsigned char * in, unsigned int in_len,
  119. unsigned char * out, unsigned int * out_len )
  120. {
  121. if (!in || !out || !out_len)
  122. return FALSE;
  123. if (in_len <= 0)
  124. return false;
  125. memcpy(out, in, in_len);
  126. *out_len = in_len;
  127. return TRUE;
  128. }
  129. ////////////////////////////////////////////////////////////////////////////////////////////////
  130. ///////////////////////////////// TextureFileCache /////////////////////////////////////////////
  131. /***********************************************************************************************
  132. * TextureFileCache::TextureFileCache -- Open cache. *
  133. * *
  134. * INPUT: *
  135. * *
  136. * OUTPUT: *
  137. * *
  138. * WARNINGS: *
  139. * *
  140. * HISTORY: *
  141. * 05/07/1999 SKB : Created. *
  142. * 06/27/2000 SKB : added CachedSurfaces *
  143. * 08/14/2000 : Check for revision number. *
  144. *=============================================================================================*/
  145. TextureFileCache::TextureFileCache(const char *fileprefix):
  146. File(_Create_File_Name(fileprefix)),
  147. CurrentTexture(NULL),
  148. TextureHandle(NULL),
  149. Header(),
  150. CachedSurfaces(),
  151. Offsets(NULL),
  152. NumCachedTextures(0)
  153. {
  154. WWASSERT(!Instances);
  155. Instances++;
  156. // This was allocated by _Create_File_Name() and need to go away now.
  157. delete _FileNamePtr;
  158. _FileNamePtr = NULL;
  159. memset(CachedSurfaces, 0, sizeof(CachedSurfaces));
  160. bool reset = false;
  161. TagBlockHandle *handle = File.Open_Tag(FILE_HEADER_NAME);
  162. if (handle) {
  163. FileHeader fileheader;
  164. // Read in header for others to use.
  165. handle->Read(&fileheader, sizeof(fileheader));
  166. if (fileheader.Version != FileHeader::TCF_VERSION) {
  167. reset = true;
  168. }
  169. // Close down handle.
  170. delete handle;
  171. } else {
  172. reset = true;
  173. }
  174. if (reset) {
  175. Reset_File();
  176. }
  177. }
  178. /***********************************************************************************************
  179. * *TextureFileCache::_Create_File_Name -- Create a file name from prefix passed in. *
  180. * *
  181. * INPUT: *
  182. * *
  183. * OUTPUT: *
  184. * *
  185. * WARNINGS: *
  186. * Caller of this function must free _FileNamePtr when done with it. *
  187. * *
  188. * HISTORY: *
  189. * 05/13/1999 SKB : Created. *
  190. *=============================================================================================*/
  191. char *TextureFileCache::_Create_File_Name(const char *fileprefix)
  192. {
  193. bool addpath = (*fileprefix != '\\' && fileprefix[1] != ':');
  194. assert(!_FileNamePtr);
  195. _FileNamePtr = W3DNEWARRAY char[strlen(fileprefix) + (addpath ? 256 : 6)];
  196. char path[_MAX_PATH];
  197. if (addpath && _getcwd(path, _MAX_PATH )) {
  198. sprintf(_FileNamePtr, "%s\\%s.tfc", path, fileprefix);
  199. } else {
  200. // Create a file name.
  201. strcpy(_FileNamePtr, fileprefix);
  202. strcat(_FileNamePtr, ".tfc");
  203. *_FileNamePtr = 0;
  204. }
  205. return(_FileNamePtr);
  206. }
  207. /***********************************************************************************************
  208. * ~TextureFileCache::TextureFileCache -- Shut down texture cache system. *
  209. * *
  210. * INPUT: *
  211. * *
  212. * OUTPUT: *
  213. * *
  214. * WARNINGS: *
  215. * *
  216. * HISTORY: *
  217. * 05/07/1999 SKB : Created. *
  218. *=============================================================================================*/
  219. TextureFileCache::~TextureFileCache()
  220. {
  221. // Make sure we have shut down everything.
  222. Close_Texture_Handle();
  223. Instances--;
  224. WWASSERT(!Instances);
  225. }
  226. /**************************************************************************
  227. * TextureFileCache::Reset_File -- virtual function to reset file and wri *
  228. * *
  229. * INPUT: *
  230. * *
  231. * OUTPUT: *
  232. * *
  233. * WARNINGS: *
  234. * *
  235. * HISTORY: *
  236. * 08/14/2000 : Created. *
  237. *========================================================================*/
  238. void TextureFileCache::Reset_File()
  239. {
  240. File.Reset_File();
  241. TagBlockHandle *handle = File.Create_Tag(FILE_HEADER_NAME);
  242. if (handle) {
  243. FileHeader fileheader;
  244. fileheader.Version = FileHeader::TCF_VERSION;
  245. // Read in header for others to use.
  246. handle->Write(&fileheader, sizeof(fileheader));
  247. // Close down handle.
  248. delete handle;
  249. } else {
  250. assert(false);
  251. }
  252. }
  253. /***********************************************************************************************
  254. * TextureFileCache::Save_Texture -- Save the texture into the cache. *
  255. * *
  256. * INPUT: *
  257. * *
  258. * OUTPUT: *
  259. * *
  260. * WARNINGS: *
  261. * *
  262. * HISTORY: *
  263. * 05/12/1999 SKB : Created. *
  264. * 06/27/2000 SKB : added Header.PixelFormat *
  265. * 06/27/2000 SKB : changed cached textures to surfaces *
  266. * 08/14/2000 : save file's datatime stamp. *
  267. *=============================================================================================*/
  268. bool TextureFileCache::Save_Texture(const char *texturename, srTextureIFace::MultiRequest& mreq, srColorSurfaceIFace& origsurface)
  269. {
  270. CriticalSectionClass::LockClass m(mutex);
  271. int idx;
  272. unsigned lod;
  273. // Open up our new texture.
  274. Open_Texture_Handle(texturename);
  275. // Create a new texture now.
  276. TextureHandle = File.Create_Tag(texturename);
  277. if (!TextureHandle) {
  278. Close_Texture_Handle();
  279. return(false);
  280. }
  281. // Setup the Header.
  282. FileClass *asset=_TheFileFactory->Get_File(texturename);
  283. WWASSERT( asset );
  284. asset->Open();
  285. Header.FileTime = asset->Get_Date_Time();
  286. Header.NumMipMaps = (mreq.smallLOD - mreq.largeLOD) + 1;
  287. Header.LargestWidth = mreq.levels[mreq.largeLOD]->getWidth();
  288. Header.LargestHeight = mreq.levels[mreq.largeLOD]->getHeight();
  289. Header.SourceWidth = origsurface.getWidth();
  290. Header.SourceHeight = origsurface.getHeight();
  291. mreq.levels[mreq.largeLOD]->getPixelFormat(Header.PixelFormat);
  292. origsurface.getPixelFormat(Header.SourcePixelFormat);
  293. _TheFileFactory->Return_File(asset);
  294. asset=NULL;
  295. // Write it out.
  296. TextureHandle->Write(&Header, sizeof(Header));
  297. // Setup offset table.
  298. Offsets = W3DNEWARRAY OffsetTableType[Header.NumMipMaps + 1];
  299. // Write for now, but we will need to seek back to write final data.
  300. int tableoffset = TextureHandle->Tell();
  301. TextureHandle->Write(Offsets, sizeof(OffsetTableType) * (Header.NumMipMaps + 1));
  302. // Now write out the textures.
  303. for (idx = 0, lod = mreq.largeLOD; lod <= mreq.smallLOD; idx++, lod++) {
  304. srColorSurface *surface = mreq.levels[lod];
  305. WWASSERT(surface->getDataPtr());
  306. Offsets[idx].Offset = TextureHandle->Tell();
  307. Offsets[idx].Size = surface->getDataSize();
  308. // Save data pointers so we don't need to read them from disk next time.
  309. Add_Cached_Surface(surface);
  310. int compsize,retcode;
  311. int buf_size=surface->getDataSize();
  312. retcode = Compressor::Compress( (const unsigned char *) surface->getDataPtr(),
  313. (unsigned int) surface->getDataSize(),
  314. (unsigned char *) Get_Compression_Buffer(buf_size),
  315. (unsigned *) &compsize);
  316. // Lots-o-test to make sure that the compression did what we want.
  317. assert(retcode == TRUE);
  318. Verify_Compression_Buffer();
  319. int readin = TextureHandle->Write(Get_Compression_Buffer(compsize), compsize);
  320. assert(readin == compsize);
  321. }
  322. int pos = TextureHandle->Seek(0, SEEK_END);
  323. // Set last one so we can get a compressed size of last texture.
  324. Offsets[idx].Offset = TextureHandle->Tell();
  325. Offsets[idx].Size = 0;
  326. // Now write out header for good.
  327. TextureHandle->Seek(tableoffset, SEEK_SET);
  328. TextureHandle->Write(Offsets, sizeof(OffsetTableType) * (Header.NumMipMaps + 1));
  329. pos = TextureHandle->Seek(0, SEEK_END);
  330. // End write access so that it gets flushed out to disk.
  331. TextureHandle->End_Write_Access();
  332. return (true);
  333. }
  334. /***********************************************************************************************
  335. * *TextureFileCache::Load_Original_Texture_Surface -- Create the initial surface that would *
  336. * *
  337. * INPUT: *
  338. * *
  339. * OUTPUT: *
  340. * *
  341. * WARNINGS: *
  342. * Sureface is only needed to get default values. The texel data does not get filled in. *
  343. * *
  344. * HISTORY: *
  345. * 05/13/1999 SKB : Created. *
  346. *=============================================================================================*/
  347. srColorSurfaceIFace *TextureFileCache::Load_Original_Texture_Surface(const char *texturename)
  348. {
  349. CriticalSectionClass::LockClass m(mutex);
  350. if (Open_Texture_Handle(texturename)) {
  351. // Create surface that we wish to return.
  352. srColorSurfaceIFace *surface = W3DNEW srColorSurface(Header.SourcePixelFormat, Header.SourceWidth, Header.SourceHeight);
  353. return(surface);
  354. }
  355. return(NULL);
  356. }
  357. /***********************************************************************************************
  358. * *TFC::Get_Surface -- Load a texture reduced N times. *
  359. * *
  360. * INPUT: *
  361. * *
  362. * OUTPUT: *
  363. * *
  364. * WARNINGS: *
  365. * *
  366. * HISTORY: *
  367. * 06/26/2000 SKB : Created. *
  368. *=============================================================================================*/
  369. srColorSurfaceIFace *TextureFileCache::Get_Surface(const char *texturename, unsigned int reduce_factor)
  370. {
  371. CriticalSectionClass::LockClass m(mutex);
  372. // If we can't get a handle, then we can't load the texture.
  373. if (!Open_Texture_Handle(texturename)) {
  374. return(0);
  375. }
  376. if (reduce_factor >= (unsigned int)(Header.NumMipMaps)) {
  377. reduce_factor=Header.NumMipMaps-1;
  378. }
  379. // Figure out the width and height of texture.
  380. int width = Header.LargestWidth >> reduce_factor;
  381. int height = Header.LargestHeight >> reduce_factor;
  382. if (!width) width = 1;
  383. if (!height) height = 1;
  384. // Create surface to return.
  385. srColorSurface *surface = W3DNEW srColorSurface(Header.PixelFormat, width, height);
  386. int size = Texture_Size(reduce_factor);
  387. assert(size == surface->getDataSize());
  388. // See if this texture is already in memory.
  389. srColorSurface *cached = Find_Cached_Surface(size);
  390. if (cached) {
  391. assert(size == cached->getDataSize());
  392. memcpy(surface->getDataPtr(), cached->getDataPtr(), size);
  393. } else {
  394. // Cache pointer so if we need texture again, we will have a pointer to
  395. // valid texture data instead of reading it from the file.
  396. Add_Cached_Surface(surface);
  397. // Read texture in - note that Textures[lod] has to be set prior to this.
  398. Read_Texture(reduce_factor, surface);
  399. }
  400. return(surface);
  401. }
  402. /***********************************************************************************************
  403. * TextureFileCache::Load_Texture -- Load texture from cache into surface. *
  404. * *
  405. * INPUT: *
  406. * *
  407. * OUTPUT: *
  408. * *
  409. * WARNINGS: *
  410. * *
  411. * HISTORY: *
  412. * 05/12/1999 SKB : Created. *
  413. * 06/02/1999 SKB : deal with texture requests larger then what is in cache. *
  414. * 06/27/2000 SKB : changed cached textures to surfaces *
  415. *=============================================================================================*/
  416. bool TextureFileCache::Load_Texture(const char *texturename, srTextureIFace::MultiRequest& mreq)
  417. {
  418. CriticalSectionClass::LockClass m(mutex);
  419. // If we can't get a handle, then we can't load the texture.
  420. if (!Open_Texture_Handle(texturename)) {
  421. return(false);
  422. }
  423. // NOTE: Mip maps that are saved in the cache are the first mip maps requested and created
  424. // for a given texture name. If a user susequently requests mip maps of different
  425. // sizes that are not in the cache, they will be created by use of surface copy functions.
  426. // When this happens it is unfortunate because it indicates some sort of inefficiency.
  427. // In code below I have put in comments 'A WASTE' to indicate what part of code deels with it.
  428. int idx;
  429. unsigned lod;
  430. // Get largest size of texture in file (idx) and what is required (lod).
  431. int idxsize = Texture_Size(0);
  432. int lodsize = -1;
  433. // Now skip any mip maps that we want but are not in the cache. (A WASTE).
  434. for (lod = mreq.largeLOD; lod <= mreq.smallLOD; lod++) {
  435. lodsize = mreq.levels[lod]->getDataSize();
  436. if (lodsize <= idxsize) {
  437. break;
  438. }
  439. }
  440. // make sure largeLOD <= smallLOD.
  441. assert(lodsize != -1);
  442. // Skip past all mipmap levels that we do not want in the file.
  443. for (idx = 0; idx < Header.NumMipMaps; idx++) {
  444. idxsize = Texture_Size(idx);
  445. if (idxsize <= lodsize) {
  446. break;
  447. }
  448. }
  449. // Save off the first lod and what index it is.
  450. unsigned firstlod = lod;
  451. // Now if we have in the file something that the texture needs, load it. (This is most desired.)
  452. if (idxsize == lodsize) {
  453. // Read in textures that we have and need.
  454. while ((lod <= mreq.smallLOD) && (idx < Header.NumMipMaps)) {
  455. srColorSurface *surface = mreq.levels[lod];
  456. int size = surface->getDataSize(); assert(Texture_Size(idx) == size);
  457. // See if we can find the texture already cached.
  458. srColorSurface *cached = Find_Cached_Surface(size);
  459. // See if texture has already been read in.
  460. if (cached) {
  461. assert(size == cached->getDataSize());
  462. // Copy data over using size of dest surface incase asserts disabled and sizes are not right.
  463. memcpy(surface->getDataPtr(), cached->getDataPtr(), size);
  464. } else {
  465. // Cache pointer so if we need texture again, we will have a pointer to
  466. // valid texture data instead of reading it from the file.
  467. Add_Cached_Surface(surface);
  468. // Read texture in - note that Textures[lod] has to be set prior to this.
  469. Read_Texture(idx, surface);
  470. }
  471. idx++, lod++;
  472. }
  473. }
  474. // Save last lod.
  475. unsigned lastlod = lod - 1;
  476. // largest surface loaded.
  477. srColorSurfaceIFace *surface = NULL;
  478. if (firstlod < lastlod) {
  479. surface = mreq.levels[firstlod];
  480. surface->addReference();
  481. }
  482. // If user requested a texture larger then what we have saved, then
  483. // we will have to scale it up for him.
  484. // NOTE: This is normally not desired. It typically means the user is
  485. // creating a texture larger then the original source - a waste.
  486. if (mreq.largeLOD < firstlod) {
  487. // If there has not been a surface loaded yet, then do so now.
  488. if (!surface) {
  489. surface = Create_First_Texture_As_Surface(mreq.levels[mreq.largeLOD]);
  490. }
  491. // Now scale the largest mip map we had up to what user wants (ONCE AGAIN: A WASTE).
  492. for (lod = mreq.largeLOD; lod <= firstlod; lod++) {
  493. // Do a surface scale.
  494. surface->copy(*mreq.levels[lod]);
  495. }
  496. }
  497. // Are there more smaller lod's that are not in the cache?
  498. if (lastlod < mreq.smallLOD) {
  499. // If there has not been a surface loaded yet, then do so now.
  500. if (!surface) {
  501. surface = Create_First_Texture_As_Surface(mreq.levels[mreq.largeLOD]);
  502. }
  503. // Now scale the largest mip map we had up to what user wants (ONCE AGAIN: A WASTE).
  504. for (lod = lastlod + 1; lod <= mreq.smallLOD; lod++) {
  505. // Do a surface scale.
  506. surface->copy(*mreq.levels[lod]);
  507. }
  508. }
  509. // Done with this one.
  510. if (surface) {
  511. surface->release();
  512. }
  513. return (true);
  514. }
  515. /***********************************************************************************************
  516. * TextureFileCache::Read_Texture -- Read in the texture into surface buffer. *
  517. * *
  518. * INPUT: *
  519. * *
  520. * OUTPUT: *
  521. * *
  522. * WARNINGS: *
  523. * *
  524. * HISTORY: *
  525. * 06/01/1999 SKB : Created. *
  526. * 06/27/2000 SKB : changed cached textures to surfaces *
  527. *=============================================================================================*/
  528. void TextureFileCache::Read_Texture(int offsetidx, srColorSurface *surface)
  529. {
  530. // Seek to correct spot.
  531. TextureHandle->Seek(Offsets[offsetidx].Offset, SEEK_SET);
  532. // Figure out how much read in and make sure it is correct size.
  533. int compsize = Compressed_Texture_Size(offsetidx);
  534. // Read in texture from cache.
  535. int readin = TextureHandle->Read(Get_Compression_Buffer(compsize), compsize);
  536. assert(readin == compsize);
  537. // Set values so we can assert if overrun.
  538. Verify_Compression_Buffer();
  539. // Decompress into texture pointer.
  540. int retcode, decompsize;
  541. retcode = Compressor::Decompress( (const unsigned char*) Get_Compression_Buffer(compsize),
  542. (unsigned int) compsize,
  543. (unsigned char*) surface->getDataPtr(),
  544. (unsigned *) &decompsize);
  545. // Lots-o-test to make sure that the compression did what we want.
  546. assert(retcode == TRUE);
  547. assert(decompsize == Texture_Size(offsetidx));
  548. Verify_Compression_Buffer();
  549. }
  550. /***********************************************************************************************
  551. * *TextureFileCache::Create_First_Texture_As_Surface -- Load first texture into a surface. *
  552. * *
  553. * INPUT: *
  554. * srColorSurfaceIFace *surfacetype - only used to create surface type we want. *
  555. * *
  556. * OUTPUT: *
  557. * *
  558. * WARNINGS: *
  559. * *
  560. * HISTORY: *
  561. * 06/02/1999 SKB : Created. *
  562. *=============================================================================================*/
  563. srColorSurfaceIFace *TextureFileCache::Create_First_Texture_As_Surface(srColorSurfaceIFace *surfacetype)
  564. {
  565. srColorSurfaceIFace::PixelFormat pf;
  566. // Get our pixel format.
  567. surfacetype->getPixelFormat(pf);
  568. // Create a surface we can load the largest texture into it
  569. srColorSurface *surface = W3DNEW srColorSurface(pf, Header.LargestWidth, Header.LargestHeight);
  570. assert(Texture_Size(0) == surface->getDataSize());
  571. // Read in texture to our surface data..
  572. Read_Texture(0, surface);
  573. return(surface);
  574. }
  575. /***********************************************************************************************
  576. * *TextureFileCache::Open_Texture_Handle -- Set the TextureHandle and Header.. *
  577. * *
  578. * INPUT: *
  579. * *
  580. * OUTPUT: *
  581. * *
  582. * WARNINGS: *
  583. * *
  584. * HISTORY: *
  585. * 05/13/1999 SKB : Created. *
  586. *=============================================================================================*/
  587. bool TextureFileCache::Open_Texture_Handle(const char *fname)
  588. {
  589. if (TextureHandle) {
  590. assert(CurrentTexture);
  591. if (!strcmpi(fname, CurrentTexture)) {
  592. return(true);
  593. }
  594. // Wrong texture, close it down so we can open another.
  595. Close_Texture_Handle();
  596. }
  597. if (!CurrentTexture) {
  598. CurrentTexture = strdup(fname);
  599. }
  600. #if 0
  601. // If this is texture is newer then our texture file, reset file.
  602. // This means that next time the texture cache file gets opened, all the
  603. // previous textures will be loaded.
  604. // SKB 8/14/2000 : Removed to put in better system below..
  605. RawFileClass asset(fname);
  606. asset.Open();
  607. if (asset.Get_Date_Time() > File.Get_Date_Time()) {
  608. Reset_File();
  609. }
  610. #endif
  611. // See if we have the texture in the file cache yet.
  612. TextureHandle = File.Open_Tag(fname);
  613. if (TextureHandle) {
  614. // Read in header for others to use.
  615. TextureHandle->Read(&Header, sizeof(Header));
  616. file_auto_ptr asset(_TheFileFactory, fname);
  617. asset->Open();
  618. // Make sure it is same file.
  619. if (Header.FileTime != asset->Get_Date_Time()) {
  620. delete TextureHandle;
  621. TextureHandle = NULL;
  622. Reset_File();
  623. return(false);
  624. }
  625. // Load up the offset table.
  626. Offsets = W3DNEWARRAY OffsetTableType[Header.NumMipMaps + 1];
  627. TextureHandle->Read(Offsets, sizeof(OffsetTableType) * (Header.NumMipMaps + 1));
  628. return(true);
  629. }
  630. return(false);
  631. }
  632. /***********************************************************************************************
  633. * TextureFileCache::Close_Texture_Handle -- Close the current texture so we can open another. *
  634. * *
  635. * INPUT: *
  636. * *
  637. * OUTPUT: *
  638. * *
  639. * WARNINGS: *
  640. * *
  641. * HISTORY: *
  642. * 06/01/1999 SKB : Created. *
  643. *=============================================================================================*/
  644. void TextureFileCache::Close_Texture_Handle()
  645. {
  646. if (CurrentTexture) {
  647. free(CurrentTexture);
  648. CurrentTexture = NULL;
  649. if (TextureHandle) {
  650. delete TextureHandle;
  651. TextureHandle = NULL;
  652. }
  653. while (NumCachedTextures--) {
  654. assert(CachedSurfaces[NumCachedTextures]);
  655. CachedSurfaces[NumCachedTextures]->release();
  656. CachedSurfaces[NumCachedTextures] = 0;
  657. }
  658. NumCachedTextures = 0;
  659. if (Offsets) {
  660. delete[] Offsets;
  661. Offsets = NULL;
  662. }
  663. } else {
  664. assert(!CurrentTexture);
  665. }
  666. }
  667. /***********************************************************************************************
  668. * *TextureFileCache::Find_Cached_Surface -- Search for a texture already cached. *
  669. * *
  670. * INPUT: *
  671. * *
  672. * OUTPUT: *
  673. * *
  674. * WARNINGS: *
  675. * *
  676. * HISTORY: *
  677. * 06/02/1999 SKB : Created. *
  678. *=============================================================================================*/
  679. srColorSurface *TextureFileCache::Find_Cached_Surface(int size)
  680. {
  681. // Search through each allocated record for the right size.
  682. for (int idx = 0; idx < NumCachedTextures; idx++) {
  683. if (CachedSurfaces[idx]->getDataSize() == size) {
  684. return(CachedSurfaces[idx]);
  685. }
  686. }
  687. return(NULL);
  688. }
  689. /***********************************************************************************************
  690. * TextureFileCache::Add_Cached_Surface -- Add a new cached texture. *
  691. * *
  692. * INPUT: *
  693. * *
  694. * OUTPUT: *
  695. * *
  696. * WARNINGS: *
  697. * *
  698. * HISTORY: *
  699. * 06/02/1999 SKB : Created. *
  700. *=============================================================================================*/
  701. void TextureFileCache::Add_Cached_Surface(srColorSurface *surface)
  702. {
  703. // return;
  704. assert(!Find_Cached_Surface(surface->getDataSize()));
  705. // If are cache is full, use the smallest one's space.
  706. int surface_idx = -1;
  707. if (NumCachedTextures == MAX_CACHED_SURFACES) {
  708. // Make sure there are some cached textures.
  709. // Assume first is smallest.
  710. int smallsize = 0xfffffff;
  711. int smallidx = -1;
  712. // Look for any others that might be smaller.
  713. for (int idx = 0; idx < NumCachedTextures; idx++) {
  714. int size = CachedSurfaces[idx]->getDataSize();
  715. if (size < smallsize) {
  716. // Found one.
  717. smallsize = size;
  718. smallidx = idx;
  719. }
  720. }
  721. surface_idx = smallidx;
  722. CachedSurfaces[idx]->release();
  723. CachedSurfaces[idx] = 0;
  724. } else {
  725. // Use next slot in array.
  726. assert(NumCachedTextures < MAX_CACHED_SURFACES);
  727. surface_idx = NumCachedTextures;
  728. NumCachedTextures++;
  729. }
  730. assert(surface_idx >= 0);
  731. assert(!CachedSurfaces[surface_idx]);
  732. CachedSurfaces[surface_idx] = surface;
  733. surface->addReference();
  734. }
  735. bool TextureFileCache::Validate_Texture(const char* FileName)
  736. {
  737. // The functions used in here are all thread safe so this function doesn't have to be mutex guarded
  738. if (!Texture_Exists(FileName)) {
  739. if (!TextureLoader::Texture_File_Exists(FileName)) {
  740. return false;
  741. }
  742. // We need to load the surface from the file first to determine the real size
  743. srColorSurfaceIFace* TempSurfacePtr = ::Load_Surface(FileName);
  744. if (!TempSurfacePtr) return false;
  745. int w=TempSurfacePtr->getWidth();
  746. srColorSurfaceIFace::PixelFormat pf;
  747. TempSurfacePtr->getPixelFormat(pf);
  748. srTextureIFace::MultiRequest mr;
  749. for (int cnt=0;cnt<srTextureIFace::MAX_LOD;++cnt) mr.levels[cnt]=0;
  750. for (cnt=0;cnt<srTextureIFace::MAX_LOD;) {
  751. mr.levels[cnt]=W3DNEW srColorSurface(pf,w,w);
  752. mr.levels[cnt]->copy(*TempSurfacePtr);
  753. w>>=1;
  754. ++cnt;
  755. if (!w) break;
  756. }
  757. mr.smallLOD=cnt-1;
  758. mr.largeLOD=0;
  759. Save_Texture(FileName, mr, *TempSurfacePtr);
  760. TempSurfacePtr->release();
  761. TempSurfacePtr=0;
  762. for (cnt=0;cnt<srTextureIFace::MAX_LOD;++cnt) {
  763. if (mr.levels[cnt]) mr.levels[cnt]->release();
  764. }
  765. }
  766. return true;
  767. }
  768. int TextureFileCache::Texture_Exists(const char *fname)
  769. {
  770. CriticalSectionClass::LockClass m(mutex);
  771. return(File.Does_Tag_Exist(fname));
  772. }
  773. #endif // WW3D_DX8