texfcach.cpp 38 KB

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