Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
texturethumbnail.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#include "texturethumbnail.h"
20#include "hashtemplate.h"
21#include "missingtexture.h"
22#include "targa.h"
23#include "ww3dformat.h"
24#include "ddsfile.h"
25#include "textureloader.h"
26#include "bitmaphandler.h"
27#include "ffactory.h"
28#include "rawfile.h"
29#include "mixfile.h"
30#include "wwprofile.h"
31#include <windows.h>
32
33static DLListClass<ThumbnailManagerClass> ThumbnailManagerList;
34static ThumbnailManagerClass* GlobalThumbnailManager;
35static bool message_box_displayed=false;
36bool ThumbnailManagerClass::CreateThumbnailIfNotFound=false;
37
38const char* ThumbFileHeader="THU6";
39
40static void Create_Hash_Name(StringClass& name, const StringClass& thumb_name)
41{
42 name=thumb_name;
43 int len=name.Get_Length();
44 WWASSERT(!stricmp(&name[len-4],".tga") || !stricmp(&name[len-4],".dds"));
45 name[len-4]='\0';
46 _strlwr(name.Peek_Buffer());
47}
48
49 /* file_auto_ptr my_tga_file(_TheFileFactory,filename);
50 if (my_tga_file->Is_Available()) {
51 my_tga_file->Open();
52 unsigned size=my_tga_file->Size();
53 char* tga_memory=new char[size];
54 my_tga_file->Read(tga_memory,size);
55 my_tga_file->Close();
56
57 StringClass pth("data\\");
58 pth+=filename;
59 RawFileClass tmp_tga_file(pth);
60 tmp_tga_file.Create();
61 tmp_tga_file.Write(tga_memory,size);
62 tmp_tga_file.Close();
63 delete[] tga_memory;
64
65 }
66*/
67
68
69ThumbnailClass::ThumbnailClass(
70 ThumbnailManagerClass* manager,
71 const char* name,
72 unsigned char* bitmap,
73 unsigned w,
74 unsigned h,
75 unsigned original_w,
76 unsigned original_h,
77 unsigned original_mip_level_count,
78 WW3DFormat original_format,
79 bool allocated,
80 unsigned long date_time)
81 :
82 Manager(manager),
83 Name(name),
84 Bitmap(bitmap),
85 Allocated(allocated),
86 Width(w),
87 Height(h),
88 OriginalTextureWidth(original_w),
89 OriginalTextureHeight(original_h),
90 OriginalTextureMipLevelCount(original_mip_level_count),
91 OriginalTextureFormat(original_format),
92 DateTime(date_time)
93{
94 Manager->Insert_To_Hash(this);
95}
96
97// ----------------------------------------------------------------------------
98//
99// Load texture and generate mipmap levels if requested. The function tries
100// to create texture that matches targa format. If suitable format is not
101// available, it selects closest matching format and performs color space
102// conversion.
103//
104// ----------------------------------------------------------------------------
105
106ThumbnailClass::ThumbnailClass(ThumbnailManagerClass* manager, const StringClass& filename)
107 :
108 Manager(manager),
109 Bitmap(0),
110 Name(filename),
111 Allocated(false),
112 Width(0),
113 Height(0),
114 OriginalTextureWidth(0),
115 OriginalTextureHeight(0),
116 OriginalTextureMipLevelCount(0),
117 OriginalTextureFormat(WW3D_FORMAT_UNKNOWN),
118 DateTime(0)
119{
120 WWPROFILE(("ThumbnailClass::ThumbnailClass"));
121 unsigned reduction_factor=3;
122
123 // First, try loading image from a DDS file
124 DDSFileClass dds_file(filename,reduction_factor);
125 if (dds_file.Is_Available() && dds_file.Load()) {
126 DateTime=dds_file.Get_Date_Time();
127
128 int len=Name.Get_Length();
129 WWASSERT(len>4);
130 Name[len-3]='d';
131 Name[len-2]='d';
132 Name[len-1]='s';
133
134 unsigned level=0;
135 while (dds_file.Get_Width(level)>32 || dds_file.Get_Height(level)>32) {
136 if (level>=dds_file.Get_Mip_Level_Count()) break;
137 level++;
138 }
139
140 OriginalTextureWidth=dds_file.Get_Full_Width();
141 OriginalTextureHeight=dds_file.Get_Full_Height();
142 OriginalTextureFormat=dds_file.Get_Format();
143 OriginalTextureMipLevelCount=dds_file.Get_Mip_Level_Count();
144 Width=dds_file.Get_Width(0);
145 Height=dds_file.Get_Height(0);
146 Bitmap=W3DNEWARRAY unsigned char[Width*Height*2];
147 Allocated=true;
148 dds_file.Copy_Level_To_Surface(
149 0, // Level
151 Width,
152 Height,
153 Bitmap,
154 Width*2,
155 Vector3(0.0f,0.0f,0.0f));// We don't want to HSV-shift here
156 }
157 // If DDS file can't be used try loading from TGA
158 else {
159 // Make sure the file can be opened. If not, return missing texture.
160 Targa targa;
161 if (TARGA_ERROR_HANDLER(targa.Open(filename,TGA_READMODE),filename)) return;
162
163 // DX8 uses image upside down compared to TGA
164 targa.Header.ImageDescriptor ^= TGAIDF_YORIGIN;
165
166 WW3DFormat src_format,dest_format;
167 unsigned src_bpp=0;
168 Get_WW3D_Format(src_format,src_bpp,targa);
169 if (src_format==WW3D_FORMAT_UNKNOWN) {
170 WWDEBUG_SAY(("Unknown texture format for %s\n",filename));
171 return;
172 }
173
174 // Destination size will be the next power of two square from the larger width and height...
175 OriginalTextureWidth=targa.Header.Width;
176 OriginalTextureHeight=targa.Header.Height;
177 OriginalTextureFormat=src_format;
178 Width=targa.Header.Width>>reduction_factor;
179 Height=targa.Header.Height>>reduction_factor;
180 OriginalTextureMipLevelCount=1;
181 unsigned iw=1;
182 unsigned ih=1;
183 while (iw<OriginalTextureWidth && ih<OriginalTextureHeight) {
184 iw+=iw;
185 ih+=ih;
186 OriginalTextureMipLevelCount++;
187 }
188
189 while (Width>32 || Height>32) {
190 reduction_factor++;
191 Width>>=2;
192 Height>>=2;
193 }
194
195 unsigned poweroftwowidth = 1;
196 while (poweroftwowidth < Width) {
197 poweroftwowidth <<= 1;
198 }
199
200 unsigned poweroftwoheight = 1;
201 while (poweroftwoheight < Height) {
202 poweroftwoheight <<= 1;
203 }
204
205 Width=poweroftwowidth;
206 Height=poweroftwoheight;
207
208 unsigned src_width=targa.Header.Width;
209 unsigned src_height=targa.Header.Height;
210
211 // NOTE: We load the palette but we do not yet support paletted textures!
212 char palette[256*4];
213 targa.SetPalette(palette);
214 if (TARGA_ERROR_HANDLER(targa.Load(filename, TGAF_IMAGE, false),filename)) return;
215
216 // Get time stamp from the tga file
217 {
218 file_auto_ptr my_tga_file(_TheFileFactory,filename);
219 WWASSERT(my_tga_file->Is_Available());
220 my_tga_file->Open();
221 DateTime=my_tga_file->Get_Date_Time();
222 my_tga_file->Close();
223 }
224
225 unsigned char* src_surface=(unsigned char*)targa.GetImage();
226
227 int len=Name.Get_Length();
228 WWASSERT(len>4);
229 Name[len-3]='t';
230 Name[len-2]='g';
231 Name[len-1]='a';
232
233 Bitmap=W3DNEWARRAY unsigned char[Width*Height*2];
234 Allocated=true;
235
236 dest_format=WW3D_FORMAT_A8R8G8B8;
238 Bitmap,
239 Width,
240 Height,
241 Width*2,
243 src_surface,
244 src_width,
245 src_height,
246 src_width*src_bpp,
247 src_format,
248 (unsigned char*)targa.GetPalette(),
249 targa.Header.CMapDepth>>3,
250 false);
251 }
252
253 Manager->Insert_To_Hash(this);
254}
255
256ThumbnailClass::~ThumbnailClass()
257{
258 if (Allocated) delete[] Bitmap;
259 Manager->Remove_From_Hash(this);
260}
261
262void ThumbnailManagerClass::Create_Thumbnails()
263{
264 SimpleFileFactoryClass ff;
265// ff.Set_Sub_Directory("Data\\");
266 ff.Set_Sub_Directory("..\\data\\client\\mixfiles\\");
267
268 MixFileFactoryClass mix(MixFileName, &ff);
269 FileFactoryClass* old_file_factory=_TheFileFactory;
270 _TheFileFactory=&mix;
271 if (mix.Is_Valid()) {
272 DynamicVectorClass<StringClass> list;
273 list.Set_Growth_Step (1000);
274 mix.Build_Filename_List(list);
275 for (int i=0;i<list.Count();++i) {
276 int len=list[i].Get_Length();
277 if (!stricmp(&list[i][len-4],".tga") || !stricmp(&list[i][len-4],".dds")) {
278 StringClass tex_name(list[i]);
279 if (!Peek_Thumbnail_Instance(tex_name)) {
280 new ThumbnailClass(this,tex_name);
281 }
282 // Remove from Global manager if texture exists in it
283 if (GlobalThumbnailManager) {
284 ThumbnailClass* g_thumb=GlobalThumbnailManager->Peek_Thumbnail_Instance(tex_name);
285 if (g_thumb) {
286 delete g_thumb;
287 }
288 }
289 }
290 }
291 }
292 _TheFileFactory=old_file_factory;
293}
294
295void ThumbnailManagerClass::Load()
296{
297 WWASSERT(!ThumbnailMemory);
298
299 // If the thumbnail hash table file is available, init hash table
300#if 0 // don't do thumbnail file.
301 DateTime=0;
302 SimpleFileFactoryClass ff;
303 ff.Set_Sub_Directory("..\\data\\client\\mixfiles\\");
304 FileClass* thumb_file=ff.Get_File(ThumbnailFileName);
305
306 if (thumb_file->Is_Available()) {
307 thumb_file->Open(FileClass::READ);
308
309 DateTime=thumb_file->Get_Date_Time();
310
311 char tmp[4];
312 thumb_file->Read(tmp,4);
313 if (tmp[0]==ThumbFileHeader[0] &&
314 tmp[1]==ThumbFileHeader[1] &&
315 tmp[2]==ThumbFileHeader[2] &&
316 tmp[3]==ThumbFileHeader[3]) {
317
318 int total_thumb_count;
319 int total_header_length;
320 int total_data_length;
321 thumb_file->Read(&total_thumb_count,sizeof(int));
322 thumb_file->Read(&total_header_length,sizeof(int));
323 thumb_file->Read(&total_data_length,sizeof(int));
324 if (total_thumb_count) {
325 WWASSERT(total_data_length && total_header_length);
326 ThumbnailMemory=W3DNEWARRAY unsigned char[total_data_length];
327 // Load thumbs
328 for (int i=0;i<total_thumb_count;++i) {
329 char name[256];
330 int offset;
331 int width;
332 int height;
333 int original_width;
334 int original_height;
335 int original_mip_level_count;
336 WW3DFormat original_format;
337 int name_len;
338 unsigned long date_time;
339 thumb_file->Read(&date_time,sizeof(unsigned long));
340 thumb_file->Read(&offset,sizeof(int));
341 thumb_file->Read(&width,sizeof(int));
342 thumb_file->Read(&height,sizeof(int));
343 thumb_file->Read(&original_width,sizeof(int));
344 thumb_file->Read(&original_height,sizeof(int));
345 thumb_file->Read(&original_mip_level_count,sizeof(int));
346 thumb_file->Read(&original_format,sizeof(int));
347 thumb_file->Read(&name_len,sizeof(int));
348 WWASSERT(name_len<255);
349 thumb_file->Read(name,name_len);
350 name[name_len]='\0';
351
352 // If per-texture time stamp test is enabled, thumbnail is only used if its time stamp
353 // matches the texture's time stamp.
354 bool valid=true;
356 file_auto_ptr texture_file(_TheFileFactory, name);
357 if (texture_file->Is_Available()) {
358 texture_file->Open();
359 if (texture_file->Get_Date_Time()!=date_time) {
360 valid=false;
361 }
362 texture_file->Close();
363 }
364 else {
365 valid=false;
366 }
367 }
368
369 if (valid) {
370 W3DNEW ThumbnailClass(
371 this,
372 name,
373 ThumbnailMemory+offset-total_header_length,
374 width,
375 height,
376 original_width,
377 original_height,
378 original_mip_level_count,
379 original_format,
380 false,
381 date_time);
382 }
383 }
384 thumb_file->Read(ThumbnailMemory,total_data_length);
385 }
386 }
387 thumb_file->Close();
388 }
389 Changed=false;
390 ff.Return_File(thumb_file);
391#endif
392}
393
394void ThumbnailManagerClass::Save(bool force)
395{
396 // Save only if changed
397 if (!Changed && !force) return;
398 Changed=false;
399
400 // If the thumbnail hash table was modified, save it to disk
401#if 0 // don't write thumbnails. jba.
402
403 HashTemplateIterator<StringClass,ThumbnailClass*> ite(ThumbnailHash);
404 int total_header_length=0;
405 int total_data_length=0;
406 int total_thumb_count=0;
407 total_header_length+=4; // header
408 total_header_length+=4; // thumb count
409 total_header_length+=4; // header size
410 total_header_length+=4; // data length
411
412 for (ite.First();!ite.Is_Done();ite.Next()) {
413 ThumbnailClass* thumb=ite.Peek_Value();
414 total_header_length+=4; // per-thumb date-time
415 total_header_length+=4; // int bitmap offset
416 total_header_length+=4; // int bitmap width
417 total_header_length+=4; // int bitmap height
418 total_header_length+=4; // int original bitmap width
419 total_header_length+=4; // int original bitmap height
420 total_header_length+=4; // int original mip level count
421 total_header_length+=4; // int original format
422 total_header_length+=4; // int name string length
423
424 total_header_length+=strlen(thumb->Get_Name());
425 total_data_length+=thumb->Get_Width()*thumb->Get_Height()*2;
426 total_thumb_count++;
427 }
428 int offset=total_header_length;
429
430 SimpleFileFactoryClass ff;
431 ff.Set_Sub_Directory("..\\data\\client\\mixfiles\\");
432 FileClass* thumb_file=ff.Get_File(ThumbnailFileName);
433// file_auto_ptr thumb_file(_TheWritingFileFactory, ThumbnailFileName);
434
435 if (thumb_file->Is_Available()) {
436 thumb_file->Delete();
437 }
438 thumb_file->Create();
439 thumb_file->Open(FileClass::WRITE);
440
441 thumb_file->Write(ThumbFileHeader,4);
442 thumb_file->Write(&total_thumb_count,sizeof(int));
443 thumb_file->Write(&total_header_length,sizeof(int));
444 thumb_file->Write(&total_data_length,sizeof(int));
445
446 // Save names and offsets
447 for (ite.First();!ite.Is_Done();ite.Next()) {
448 ThumbnailClass* thumb=ite.Peek_Value();
449 const char* name=thumb->Get_Name();
450 int name_len=strlen(name);
451 int width=thumb->Get_Width();
452 int height=thumb->Get_Height();
453 int original_width=thumb->Get_Original_Texture_Width();
454 int original_height=thumb->Get_Original_Texture_Height();
455 int original_mip_level_count=thumb->Get_Original_Texture_Mip_Level_Count();
456 WW3DFormat original_format=thumb->Get_Original_Texture_Format();
457 unsigned long date_time=thumb->Get_Date_Time();
458
459 thumb_file->Write(&date_time,sizeof(unsigned long));
460 thumb_file->Write(&offset,sizeof(int));
461 thumb_file->Write(&width,sizeof(int));
462 thumb_file->Write(&height,sizeof(int));
463 thumb_file->Write(&original_width,sizeof(int));
464 thumb_file->Write(&original_height,sizeof(int));
465 thumb_file->Write(&original_mip_level_count,sizeof(int));
466 thumb_file->Write(&original_format,sizeof(int));
467 thumb_file->Write(&name_len,sizeof(int));
468 thumb_file->Write(name,name_len);
469 offset+=width*height*2;
470 }
471
472 // Save bitmaps
473 offset=total_header_length;
474 for (ite.First();!ite.Is_Done();ite.Next()) {
475 ThumbnailClass* thumb=ite.Peek_Value();
476 int width=thumb->Get_Width();
477 int height=thumb->Get_Height();
478 thumb_file->Write(thumb->Peek_Bitmap(),width*height*2);
479 }
480 if (DateTime) thumb_file->Set_Date_Time(DateTime);
481 thumb_file->Close();
482 ff.Return_File(thumb_file);
483#endif
484}
485
486
487// ----------------------------------------------------------------------------
488ThumbnailManagerClass::ThumbnailManagerClass(const char* thumbnail_filename, const char* mix_filename)
489 :
490 ThumbnailMemory(NULL),
491 ThumbnailFileName(thumbnail_filename),
492 MixFileName(mix_filename),
493 PerTextureTimeStampUsed(false),
494 Changed(false),
495 DateTime(0)
496{
497 Load();
498}
499
500// ----------------------------------------------------------------------------
501ThumbnailManagerClass::~ThumbnailManagerClass()
502{
503 Save();
504 HashTemplateIterator<StringClass,ThumbnailClass*> ite(ThumbnailHash);
505 ite.First();
506 while (!ite.Is_Done()) {
507 ThumbnailClass* thumb=ite.Peek_Value();
508 delete thumb;
509 ite.First();
510 }
511
512 if (ThumbnailMemory) delete[] ThumbnailMemory;
513 ThumbnailMemory=NULL;
514}
515
516// ----------------------------------------------------------------------------
517ThumbnailManagerClass* ThumbnailManagerClass::Peek_Thumbnail_Manager(const char* thumbnail_filename)
518{
519 ThumbnailManagerClass* man=ThumbnailManagerList.Head();
520 while (man) {
521 if (man->ThumbnailFileName==thumbnail_filename) return man;
522 man=man->Succ();
523 }
524 if (GlobalThumbnailManager &&
525 GlobalThumbnailManager->ThumbnailFileName==thumbnail_filename) return GlobalThumbnailManager;
526 return NULL;
527}
528
529// ----------------------------------------------------------------------------
530void ThumbnailManagerClass::Add_Thumbnail_Manager(const char* thumbnail_filename, const char* mix_filename)
531{
532 // First loop over all thumbnail managers to see if we already have this one created. This isn't
533 // supposed to be called often at all and there are usually just couple managers alive,
534 // so we'll do pure string compares here...
535
536 // Must NOT add global manager with this function
537 WWASSERT(stricmp(thumbnail_filename,GLOBAL_THUMBNAIL_MANAGER_FILENAME));
538
539 ThumbnailManagerClass* man=Peek_Thumbnail_Manager(thumbnail_filename);
540 if (man) return;
541
542 // Always update thumbnail files when they're out of date
543 Update_Thumbnail_File(mix_filename,false);
544
545 // Not found, create and add to the list.
546 man=new ThumbnailManagerClass(thumbnail_filename,mix_filename);
547 ThumbnailManagerList.Add_Tail(man);
548}
549// ----------------------------------------------------------------------------
550void ThumbnailManagerClass::Remove_Thumbnail_Manager(const char* thumbnail_filename)
551{
552 ThumbnailManagerClass* man=ThumbnailManagerList.Head();
553 while (man) {
554 if (man->ThumbnailFileName==thumbnail_filename) {
555 delete man;
556 return;
557 }
558 man=man->Succ();
559 }
560 if (GlobalThumbnailManager &&
561 GlobalThumbnailManager->ThumbnailFileName==thumbnail_filename) {
562 delete GlobalThumbnailManager;
563 GlobalThumbnailManager=NULL;
564 }
565}
566// ----------------------------------------------------------------------------
568{
569
570 return Get_From_Hash(name);
571}
572
574{
575 WWPROFILE(("Peek_Thumbnail_Instance_From_Any_Manager"));
576 ThumbnailManagerClass* thumb_man=ThumbnailManagerList.Head();
577 while (thumb_man) {
578 ThumbnailClass* thumb=thumb_man->Peek_Thumbnail_Instance(filename);
579 if (thumb) return thumb;
580 thumb_man=thumb_man->Succ();
581 }
582
583 if (GlobalThumbnailManager) {
584 ThumbnailClass* thumb=GlobalThumbnailManager->Peek_Thumbnail_Instance(filename);
585 if (thumb) return thumb;
586 }
587
588// If thumbnail is not found, see if we can find a texture. It is possible that the texture is outside of
589// a mix file and didn't get included in any thumbnail database based on a mixfile. If so, we'll add it to
590// our global thumbnail database.
592 if (GlobalThumbnailManager) {
593 ThumbnailClass* thumb=new ThumbnailClass(GlobalThumbnailManager,filename);
594 if (!thumb->Peek_Bitmap()) {
595 delete thumb;
596 thumb=NULL;
597 }
598 return thumb;
599 }
600 }
601
602 return NULL;
603}
604
605
606void ThumbnailManagerClass::Insert_To_Hash(ThumbnailClass* thumb)
607{
608 Changed=true;
609 StringClass hash_name(0,true);
610 Create_Hash_Name(hash_name,thumb->Get_Name());
611 ThumbnailHash.Insert(hash_name,thumb);
612}
613
614ThumbnailClass* ThumbnailManagerClass::Get_From_Hash(const StringClass& name)
615{
616 StringClass hash_name(0,true);
617 Create_Hash_Name(hash_name,name);
618 return ThumbnailHash.Get(hash_name);
619}
620
621void ThumbnailManagerClass::Remove_From_Hash(ThumbnailClass* thumb)
622{
623 Changed=true;
624 StringClass hash_name(0,true);
625 Create_Hash_Name(hash_name,thumb->Get_Name());
626 ThumbnailHash.Remove(hash_name);
627}
628
629void ThumbnailManagerClass::Update_Thumbnail_File(const char* mix_file_name,bool display_message_box)
630{
631 if (!mix_file_name) return;
632
633 SimpleFileFactoryClass ff;
634 ff.Set_Sub_Directory("..\\data\\client\\mixfiles\\");
635
636 StringClass thumb_file_name(mix_file_name,true);
637 int len=thumb_file_name.Get_Length();
638 WWASSERT(len>4);
639 thumb_file_name[len-3]='t';
640 thumb_file_name[len-2]='h';
641 thumb_file_name[len-1]='6';
642 FileClass* mix_file=ff.Get_File(mix_file_name);
643 FileClass* thumb_file=ff.Get_File(thumb_file_name);
644
645 WWASSERT(mix_file && thumb_file);
646
647 // If mix file isn't found but thumb file is, delete the obsolete thumb file
648 mix_file->Open(FileClass::READ);
649 thumb_file->Open(FileClass::READ); //|FileClass::WRITE); Changed this to READ only since we never use the handle for writing and it may cause contention amongst slave servers ST - 12/14/2001 8:26PM
650 if (!mix_file->Is_Available()) {
651 if (thumb_file->Is_Available()) {
652 thumb_file->Delete();
653 }
654 mix_file->Close();
655 thumb_file->Close();
656 ff.Return_File(mix_file);
657 ff.Return_File(thumb_file);
658 return;
659 }
660
661 unsigned long mix_date_time=mix_file->Get_Date_Time();
662 if (thumb_file->Is_Available()) {
663 unsigned long thumb_date_time=thumb_file->Get_Date_Time();
664 if (mix_date_time!=thumb_date_time) {
665 thumb_file->Delete();
666 }
667 // Read header to make sure the thumb file is of correct version.
668 char tmp[4];
669 thumb_file->Read(tmp,4);
670 if (tmp[0]!=ThumbFileHeader[0] ||
671 tmp[1]!=ThumbFileHeader[1] ||
672 tmp[2]!=ThumbFileHeader[2] ||
673 tmp[3]!=ThumbFileHeader[3]) {
674 thumb_file->Delete();
675 }
676 }
677
678 if (thumb_file->Is_Available()) {
679 mix_file->Close();
680 thumb_file->Close();
681 ff.Return_File(mix_file);
682 ff.Return_File(thumb_file);
683 return;
684 }
685
686 if (display_message_box && !message_box_displayed) {
687 message_box_displayed=true;
688 ::MessageBox(NULL,
689 "Some or all texture thumbnails need to be updated.\n"
690 "This will take a while. The update will only be done once\n"
691 "each time a mix file changes and thumb database hasn't been\n"
692 "updated.",
693 "Updating texture thumbnails",
694 MB_OK);
695 }
696
697 // we don't currently have a thumbnail file (either we just deleted it or it never existed, we don't care)
698 // so we must create one now.
699 ThumbnailManagerClass* manager=new ThumbnailManagerClass(thumb_file_name, mix_file_name);
700 manager->DateTime=mix_date_time; // Set the datetime to mixfile's datetime.
701 manager->Create_Thumbnails();
702 manager->Save(true);
703 delete manager;
704
705 // close files and return pointers
706 mix_file->Close();
707 thumb_file->Close();
708 ff.Return_File(mix_file);
709 ff.Return_File(thumb_file);
710}
711
712// Verify that up-to-date thumbnails exist for all textures
713void ThumbnailManagerClass::Pre_Init(bool display_message_box)
714{
715 WWASSERT(!ThumbnailManagerList.Head());
716
717 // Collect all mix file names
719
720 char cur_dir[256];
721 GetCurrentDirectory(sizeof(cur_dir),cur_dir);
722 StringClass new_dir(cur_dir,true);
723 new_dir+="\\Data";
724 SetCurrentDirectory(new_dir);
725
726 WIN32_FIND_DATA find_data;
727 HANDLE handle=FindFirstFile("*.mix",&find_data);
728 if (handle!=INVALID_HANDLE_VALUE) {
729 for (;;) {
730 if (!(find_data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)) {
731 mix_names.Add(find_data.cFileName);
732 }
733 if (!FindNextFile(handle,&find_data)) {
734 FindClose(handle);
735 break;
736 }
737 }
738 }
739 SetCurrentDirectory(cur_dir);
740
741 // First generate thumbnails for always.dat
742 Update_Thumbnail_File("always.dat",display_message_box);
743
744 // Then loop over all .mix files
745 for (int i=0;i<mix_names.Count();++i) {
746 Update_Thumbnail_File(mix_names[i],display_message_box);
747 }
748}
749
751{
752 WWASSERT(GlobalThumbnailManager == NULL);
753 GlobalThumbnailManager=new ThumbnailManagerClass(GLOBAL_THUMBNAIL_MANAGER_FILENAME,NULL);
754 GlobalThumbnailManager->Enable_Per_Texture_Time_Stamp(true);
755}
756
758{
759 while (ThumbnailManagerClass* man=ThumbnailManagerList.Head()) {
760 delete man;
761 }
762 if (GlobalThumbnailManager) {
763 delete GlobalThumbnailManager;
764 GlobalThumbnailManager=NULL;
765 }
766}
#define NULL
Definition BaseType.h:92
#define WWASSERT
#define TGAF_IMAGE
Definition TARGA.H:112
#define TARGA_ERROR_HANDLER(call, filename)
Definition TARGA.H:47
#define TGA_READMODE
Definition TARGA.H:99
#define TGAIDF_YORIGIN
Definition TARGA.H:96
#define W3DNEWARRAY
Definition always.h:110
#define W3DNEW
Definition always.h:109
@ false
Definition bool.h:59
static void Copy_Image(unsigned char *dest_surface, unsigned dest_surface_width, unsigned dest_surface_height, unsigned dest_surface_pitch, WW3DFormat dest_surface_format, unsigned char *src_surface, unsigned src_surface_width, unsigned src_surface_height, unsigned src_surface_pitch, WW3DFormat src_surface_format, const unsigned char *src_palette, unsigned src_palette_bpp, bool generate_mip_level, const Vector3 &hsv_shift=Vector3(0.0f, 0.0f, 0.0f))
T * Succ()
Definition dllist.h:146
int Count(void) const
Definition Vector.H:507
bool Add(T const &object)
Definition Vector.H:671
virtual int Create(void)=0
virtual unsigned long Get_Date_Time(void)
Definition WWFILE.H:91
virtual bool Set_Date_Time(unsigned long)
Definition WWFILE.H:92
virtual bool Is_Available(int forced=false)=0
virtual int Delete(void)=0
virtual int Read(void *buffer, int size)=0
virtual void Close(void)=0
virtual int Open(char const *filename, int rights=READ)=0
virtual int Write(void const *buffer, int size)=0
@ WRITE
Definition WWFILE.H:72
void Insert(const KeyType &s, const ValueType &d)
virtual void Return_File(FileClass *file)
Definition ffactory.cpp:307
virtual FileClass * Get_File(char const *filename)
Definition ffactory.cpp:235
void Set_Sub_Directory(const char *sub_directory)
Definition ffactory.cpp:124
int Get_Length(void) const
Definition wwstring.h:664
TCHAR * Peek_Buffer(void)
Definition wwstring.h:560
Definition TARGA.H:260
char * SetPalette(char *buffer)
Definition TARGA.CPP:973
char * GetPalette(void) const
Definition TARGA.H:281
TGAHeader Header
Definition TARGA.H:287
long Load(const char *name, char *palette, char *image, bool invert_image=true)
Definition TARGA.CPP:354
char * GetImage(void) const
Definition TARGA.H:278
long Open(const char *name, long mode)
Definition TARGA.CPP:171
WW3DFormat Get_Original_Texture_Format() const
unsigned long Get_Date_Time() const
unsigned Get_Width() const
unsigned Get_Height() const
unsigned Get_Original_Texture_Mip_Level_Count() const
unsigned Get_Original_Texture_Height() const
unsigned char * Peek_Bitmap()
unsigned Get_Original_Texture_Width() const
const StringClass & Get_Name() const
static bool Is_Thumbnail_Created_If_Not_Found()
ThumbnailClass * Peek_Thumbnail_Instance(const StringClass &name)
bool Is_Per_Texture_Time_Stamp_Used() const
static void Pre_Init(bool display_message_box)
static ThumbnailClass * Peek_Thumbnail_Instance_From_Any_Manager(const StringClass &name)
static void Add_Thumbnail_Manager(const char *thumbnail_filename, const char *mix_file_name)
static ThumbnailManagerClass * Peek_Thumbnail_Manager(const char *thumbnail_filename)
static void Remove_Thumbnail_Manager(const char *thumbnail_filename)
FileFactoryClass * _TheFileFactory
Definition ffactory.cpp:51
const char * ThumbFileHeader
#define GLOBAL_THUMBNAIL_MANAGER_FILENAME
void Get_WW3D_Format(WW3DFormat &dest_format, WW3DFormat &src_format, unsigned &src_bpp, const Targa &targa)
WW3DFormat
Definition ww3dformat.h:75
@ WW3D_FORMAT_UNKNOWN
Definition ww3dformat.h:76
@ WW3D_FORMAT_A4R4G4B4
Definition ww3dformat.h:83
@ WW3D_FORMAT_A8R8G8B8
Definition ww3dformat.h:78
#define WWDEBUG_SAY(x)
Definition wwdebug.h:114
#define WWPROFILE(name)
Definition wwprofile.h:270