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