Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
textureloader.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/***********************************************************************************************
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 : DX8 Texture Manager *
24 * *
25 * $Archive:: /Commando/Code/ww3d2/textureloader.h $*
26 * *
27 * Original Author:: vss_sync *
28 * *
29 * Author : Kenny Mitchell *
30 * *
31 * $Modtime:: 08/05/02 10:03a $*
32 * *
33 * $Revision:: 3 $*
34 * *
35 * 06/27/02 KM Texture class abstraction *
36 * 08/05/02 KM Texture class redesign (revisited)
37 *---------------------------------------------------------------------------------------------*
38 * Functions: *
39 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
40
41#include "textureloader.h"
42#include "mutex.h"
43#include "thread.h"
44#include "wwdebug.h"
45#include "texture.h"
46#include "ffactory.h"
47#include "wwstring.h"
48#include "bufffile.h"
49#include "ww3d.h"
50#include "texfcach.h"
51#include "assetmgr.h"
52#include "dx8wrapper.h"
53#include "dx8caps.h"
54#include "missingtexture.h"
55#include "targa.h"
56#include <D3dx8tex.h>
57#include <cstdio>
58#include "wwmemlog.h"
59#include "texture.h"
60#include "formconv.h"
61#include "texturethumbnail.h"
62#include "ddsfile.h"
63#include "bitmaphandler.h"
64#include "wwprofile.h"
65
66//#pragma optimize("", off)
67//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
68
69bool TextureLoader::TextureLoadSuspended;
70int TextureLoader::TextureInactiveOverrideTime = 0;
71
72#define USE_MANAGED_TEXTURES
73
75//
76// TextureLoadTaskListClass implementation
77//
79
81: Root()
82{
83 Root.Next = Root.Prev = &Root;
84}
85
87{
88 // task should non-null and not on any list
89 WWASSERT(task != NULL && task->Next == NULL && task->Prev == NULL);
90
91 // update inserted task to point to list
92 task->Next = Root.Next;
93 task->Prev = &Root;
94 task->List = this;
95
96 // update list to point to inserted task
97 Root.Next->Prev = task;
98 Root.Next = task;
99}
100
102{
103 // task should be non-null and not on any list
104 WWASSERT(task != NULL && task->Next == NULL && task->Prev == NULL);
105
106 // update inserted task to point to list
107 task->Next = &Root;
108 task->Prev = Root.Prev;
109 task->List = this;
110
111 // update list to point to inserted task
112 Root.Prev->Next = task;
113 Root.Prev = task;
114}
115
117{
118 // exit early if list is empty
119 if (Is_Empty()) {
120 return 0;
121 }
122
123 // otherwise, grab first task and remove it.
125 Remove(task);
126 return task;
127
128}
129
131{
132 // exit early if list is empty
133 if (Is_Empty()) {
134 return 0;
135 }
136
137 // otherwise, grab last task and remove it.
139 Remove(task);
140 return task;
141}
142
144{
145 // exit early if task is not on this list.
146 if (task->List != this) {
147 return;
148 }
149
150 // update list to skip task
151 task->Prev->Next = task->Next;
152 task->Next->Prev = task->Prev;
153
154 // update task to no longer point at list
155 task->Prev = 0;
156 task->Next = 0;
157 task->List = 0;
158}
159
160
162//
163// SynchronizedTextureLoadTaskListClass implementation
164//
166
172
178
184
186{
187 // this duplicates code inside base class, but saves us an unnecessary lock.
188 if (Is_Empty()) {
189 return 0;
190 }
191
192 FastCriticalSectionClass::LockClass lock(CriticalSection);
194
195}
196
198{
199 // this duplicates code inside base class, but saves us an unnecessary lock.
200 if (Is_Empty()) {
201 return 0;
202 }
203
204 FastCriticalSectionClass::LockClass lock(CriticalSection);
206}
207
213
214
215// Locks
216
217// To prevent deadlock, threads should acquire locks in the order in which
218// they are defined below. No ordering is necessary for the task list locks,
219// since one thread can never hold two at once.
220
221static FastCriticalSectionClass _ForegroundCriticalSection;
222static FastCriticalSectionClass _BackgroundCriticalSection;
223
224// Lists
225
226static SynchronizedTextureLoadTaskListClass _ForegroundQueue;
227static SynchronizedTextureLoadTaskListClass _BackgroundQueue;
228
229static TextureLoadTaskListClass _TexLoadFreeList;
230static TextureLoadTaskListClass _CubeTexLoadFreeList;
231static TextureLoadTaskListClass _VolTexLoadFreeList;
232
233
234// The background texture loading thread.
235static class LoaderThreadClass : public ThreadClass
236{
237public:
238#ifdef Exception_Handler
239 LoaderThreadClass(const char *thread_name = "Texture loader thread") : ThreadClass(thread_name, &Exception_Handler) {}
240#else
241 LoaderThreadClass(const char *thread_name = "Texture loader thread") : ThreadClass(thread_name) {}
242#endif
243
244 void Thread_Function();
245} _TextureLoadThread;
246
247
248// TODO: Legacy - remove this call!
249IDirect3DTexture8* Load_Compressed_Texture(
250 const StringClass& filename,
251 unsigned reduction_factor,
252 MipCountType mip_level_count,
253 WW3DFormat dest_format)
254{
255 // If DDS file isn't available, use TGA file to convert to DDS.
256
257 DDSFileClass dds_file(filename,reduction_factor);
258 if (!dds_file.Is_Available()) return NULL;
259 if (!dds_file.Load()) return NULL;
260
261 unsigned width=dds_file.Get_Width(0);
262 unsigned height=dds_file.Get_Height(0);
263 unsigned mips=dds_file.Get_Mip_Level_Count();
264
265 // If format isn't defined get the nearest valid texture format to the compressed file format
266 // Note that the nearest valid format could be anything, even uncompressed.
267 if (dest_format==WW3D_FORMAT_UNKNOWN) dest_format=Get_Valid_Texture_Format(dds_file.Get_Format(),true);
268
269 IDirect3DTexture8* d3d_texture = DX8Wrapper::_Create_DX8_Texture
270 (
271 width,
272 height,
273 dest_format,
274 (MipCountType)mips
275 );
276
277 for (unsigned level=0;level<mips;++level) {
278 IDirect3DSurface8* d3d_surface=NULL;
279 WWASSERT(d3d_texture);
280 DX8_ErrorCode(d3d_texture->GetSurfaceLevel(level/*-reduction_factor*/,&d3d_surface));
281 dds_file.Copy_Level_To_Surface(level,d3d_surface);
282 d3d_surface->Release();
283 }
284 return d3d_texture;
285}
286
287static bool Is_Format_Compressed(WW3DFormat texture_format,bool allow_compression)
288{
289 // Verify that the user isn't requesting compressed texture without hardware support
290
291 bool compressed=false;
292 if (texture_format!=WW3D_FORMAT_UNKNOWN) {
293 if (!DX8Wrapper::Get_Current_Caps()->Support_DXTC() || !allow_compression) {
294 WWASSERT(texture_format!=WW3D_FORMAT_DXT1);
295 WWASSERT(texture_format!=WW3D_FORMAT_DXT2);
296 WWASSERT(texture_format!=WW3D_FORMAT_DXT3);
297 WWASSERT(texture_format!=WW3D_FORMAT_DXT4);
298 WWASSERT(texture_format!=WW3D_FORMAT_DXT5);
299 }
300 if (texture_format==WW3D_FORMAT_DXT1 ||
301 texture_format==WW3D_FORMAT_DXT2 ||
302 texture_format==WW3D_FORMAT_DXT3 ||
303 texture_format==WW3D_FORMAT_DXT4 ||
304 texture_format==WW3D_FORMAT_DXT5) {
305 compressed=true;
306 }
307 }
308
309 // If hardware supports DXTC compression, load a compressed texture. Proceed only if the texture format hasn't been
310 // defined as non-compressed.
311 compressed|=(
312 texture_format==WW3D_FORMAT_UNKNOWN &&
314 allow_compression);
315
316 return compressed;
317}
318
319
321//
322// TextureLoader implementation
323//
325
327{
328 WWASSERT(!_TextureLoadThread.Is_Running());
329
331
332 _TextureLoadThread.Execute();
333 _TextureLoadThread.Set_Priority(-4);
334 TextureInactiveOverrideTime = 0;
335}
336
337
339{
340 FastCriticalSectionClass::LockClass lock(_BackgroundCriticalSection);
341 _TextureLoadThread.Stop();
342
345}
346
347
352
353
354// ----------------------------------------------------------------------------
355//
356// Modify given texture size to nearest valid size on current hardware.
357//
358// ----------------------------------------------------------------------------
359
361(
362 unsigned& width,
363 unsigned& height,
364 unsigned& depth
365)
366{
367 const D3DCAPS8& dx8caps=DX8Wrapper::Get_Current_Caps()->Get_DX8_Caps();
368
369 unsigned poweroftwowidth = 1;
370 while (poweroftwowidth < width)
371 {
372 poweroftwowidth <<= 1;
373 }
374
375 unsigned poweroftwoheight = 1;
376 while (poweroftwoheight < height)
377 {
378 poweroftwoheight <<= 1;
379 }
380
381 unsigned poweroftwodepth = 1;
382 while (poweroftwodepth< depth)
383 {
384 poweroftwodepth <<= 1;
385 }
386
387 if (poweroftwowidth>dx8caps.MaxTextureWidth)
388 {
389 poweroftwowidth=dx8caps.MaxTextureWidth;
390 }
391 if (poweroftwoheight>dx8caps.MaxTextureHeight)
392 {
393 poweroftwoheight=dx8caps.MaxTextureHeight;
394 }
395 if (poweroftwodepth>dx8caps.MaxVolumeExtent)
396 {
397 poweroftwodepth=dx8caps.MaxVolumeExtent;
398 }
399
400 if (poweroftwowidth>poweroftwoheight)
401 {
402 while (poweroftwowidth/poweroftwoheight>8)
403 {
404 poweroftwoheight*=2;
405 }
406 }
407 else
408 {
409 while (poweroftwoheight/poweroftwowidth>8)
410 {
411 poweroftwowidth*=2;
412 }
413 }
414
415 width=poweroftwowidth;
416 height=poweroftwoheight;
417 depth=poweroftwodepth;
418}
419
420IDirect3DTexture8* TextureLoader::Load_Thumbnail(const StringClass& filename, const Vector3& hsv_shift)//,WW3DFormat texture_format)
421{
423
424 ThumbnailClass* thumb=NULL;
426
427 // If no thumb is found return a missing texture
428 if (!thumb) {
430 }
431
433 unsigned src_pitch=thumb->Get_Width()*2; // Thumbs are always 16 bits
434 WW3DFormat dest_format;
435 WW3DFormat texture_format=WW3D_FORMAT_UNKNOWN;
436 if (texture_format==WW3D_FORMAT_UNKNOWN) {
437 dest_format=Get_Valid_Texture_Format(WW3D_FORMAT_A4R4G4B4,false); // no compressed formats please
438 }
439 else {
440 dest_format=Get_Valid_Texture_Format(texture_format,false); // no compressed formats please
441 WWASSERT(dest_format==texture_format);
442 }
443
444 IDirect3DTexture8* sysmem_texture = DX8Wrapper::_Create_DX8_Texture(
445 thumb->Get_Width(),
446 thumb->Get_Height(),
447 dest_format,
450 D3DPOOL_MANAGED);
451#else
452 D3DPOOL_SYSTEMMEM);
453#endif
454
455 unsigned level=0;
456 D3DLOCKED_RECT locked_rects[12];
457 WWASSERT(sysmem_texture->GetLevelCount()<=12);
458
459 // Lock all surfaces
460 for (level=0;level<sysmem_texture->GetLevelCount();++level) {
462 sysmem_texture->LockRect(
463 level,
464 &locked_rects[level],
465 NULL,
466 0));
467 }
468
469 unsigned char* src_surface=thumb->Peek_Bitmap();
470 WW3DFormat src_format=thumb->Get_Format();
471 unsigned width=thumb->Get_Width();
472 unsigned height=thumb->Get_Height();
473
474 Vector3 hsv=hsv_shift;
475 for (level=0;level<sysmem_texture->GetLevelCount()-1;++level) {
477 width,
478 height,
479 (unsigned char*)locked_rects[level].pBits,
480 locked_rects[level].Pitch,
481 dest_format,
482 src_surface,
483 src_pitch,
484 src_format,
485 (unsigned char*)locked_rects[level+1].pBits, // mipmap
486 locked_rects[level+1].Pitch,
487 hsv);
488 hsv=Vector3(0.0f,0.0f,0.0f); // Only do the shift for the first level, as the mipmaps are based on it.
489
490 src_format=dest_format;
491 src_surface=(unsigned char*)locked_rects[level].pBits;
492 src_pitch=locked_rects[level].Pitch;
493 width>>=1;
494 height>>=1;
495 }
496
497 // Unlock all surfaces
498 for (level=0;level<sysmem_texture->GetLevelCount();++level) {
499 DX8_ErrorCode(sysmem_texture->UnlockRect(level));
500 }
501#ifdef USE_MANAGED_TEXTURES
502 return sysmem_texture;
503#else
504 IDirect3DTexture8* d3d_texture = DX8Wrapper::_Create_DX8_Texture(
505 thumb->Get_Width(),
506 thumb->Get_Height(),
507 dest_format,
508 TextureBaseClass::MIP_LEVELS_ALL,
509 D3DPOOL_DEFAULT);
510 DX8CALL(UpdateTexture(sysmem_texture,d3d_texture));
511 sysmem_texture->Release();
512
513 WWDEBUG_SAY(("Created non-managed texture (%s)\n",filename));
514 return d3d_texture;
515#endif
516}
517
518
519// ----------------------------------------------------------------------------
520//
521// Load image to a surface. The function tries to create texture that matches
522// targa format. If suitable format is not available, it selects closest matching
523// format and performs color space conversion.
524//
525// ----------------------------------------------------------------------------
527 const StringClass& filename,
528 WW3DFormat texture_format,
529 bool allow_compression)
530{
532
533 bool compressed=Is_Format_Compressed(texture_format,allow_compression);
534
535 if (compressed) {
536 IDirect3DTexture8* comp_tex=Load_Compressed_Texture(filename,0,MIP_LEVELS_1,WW3D_FORMAT_UNKNOWN);
537 if (comp_tex) {
538 IDirect3DSurface8* d3d_surface=NULL;
539 DX8_ErrorCode(comp_tex->GetSurfaceLevel(0,&d3d_surface));
540 comp_tex->Release();
541 return d3d_surface;
542 }
543 }
544
545 // Make sure the file can be opened. If not, return missing texture.
546 Targa targa;
547 if (TARGA_ERROR_HANDLER(targa.Open(filename, TGA_READMODE),filename)) return MissingTexture::_Create_Missing_Surface();
548
549 // DX8 uses image upside down compared to TGA
550 targa.Header.ImageDescriptor ^= TGAIDF_YORIGIN;
551
552 WW3DFormat src_format,dest_format;
553 unsigned src_bpp=0;
554 Get_WW3D_Format(dest_format,src_format,src_bpp,targa);
555
556 if (texture_format!=WW3D_FORMAT_UNKNOWN) {
557 dest_format=texture_format;
558 }
559
560 // Destination size will be the next power of two square from the larger width and height...
561 unsigned width, height;
562 width=targa.Header.Width;
563 height=targa.Header.Height;
564 unsigned src_width=targa.Header.Width;
565 unsigned src_height=targa.Header.Height;
566
567 // NOTE: We load the palette but we do not yet support paletted textures!
568 char palette[256*4];
569 targa.SetPalette(palette);
570 if (TARGA_ERROR_HANDLER(targa.Load(filename, TGAF_IMAGE, false),filename)) return MissingTexture::_Create_Missing_Surface();
571
572 unsigned char* src_surface=(unsigned char*)targa.GetImage();
573
574 // No paletted destination format allowed
575 unsigned char* converted_surface=NULL;
576 if (src_format==WW3D_FORMAT_A1R5G5B5 || src_format==WW3D_FORMAT_R5G6B5 || src_format==WW3D_FORMAT_A4R4G4B4 ||
577 src_format==WW3D_FORMAT_P8 || src_format==WW3D_FORMAT_L8 || src_width!=width || src_height!=height) {
578 converted_surface=W3DNEWARRAY unsigned char[width*height*4];
581 converted_surface,
582 width,
583 height,
584 width*4,
585 WW3D_FORMAT_A8R8G8B8,//dest_format,
586 src_surface,
587 src_width,
588 src_height,
589 src_width*src_bpp,
590 src_format,
591 (unsigned char*)targa.GetPalette(),
592 targa.Header.CMapDepth>>3,
593 false);
594 src_surface=converted_surface;
595 src_format=WW3D_FORMAT_A8R8G8B8;//dest_format;
596 src_width=width;
597 src_height=height;
598 src_bpp=Get_Bytes_Per_Pixel(src_format);
599 }
600
601 unsigned src_pitch=src_width*src_bpp;
602
603 IDirect3DSurface8* d3d_surface = DX8Wrapper::_Create_DX8_Surface(width,height,dest_format);
604 WWASSERT(d3d_surface);
605 D3DLOCKED_RECT locked_rect;
607 d3d_surface->LockRect(
608 &locked_rect,
609 NULL,
610 0));
611
613 (unsigned char*)locked_rect.pBits,
614 width,
615 height,
616 locked_rect.Pitch,
617 dest_format,
618 src_surface,
619 src_width,
620 src_height,
621 src_pitch,
622 src_format,
623 (unsigned char*)targa.GetPalette(),
624 targa.Header.CMapDepth>>3,
625 false); // No mipmap
626
627 DX8_ErrorCode(d3d_surface->UnlockRect());
628
629 if (converted_surface) delete[] converted_surface;
630
631 return d3d_surface;
632}
633
634
636{
637 // Grab the foreground lock. This prevents the foreground thread
638 // from retiring any tasks related to this texture. It also
639 // serializes calls to Request_Thumbnail from multiple threads.
640 FastCriticalSectionClass::LockClass lock(_ForegroundCriticalSection);
641
642 // Has a Direct3D texture already been loaded?
643 if (tc->Peek_D3D_Base_Texture()) {
644 return;
645 }
646
647 TextureLoadTaskClass *task = tc->ThumbnailLoadTask;
648
649 if (Is_DX8_Thread()) {
650 // load the thumbnail immediately
652
653 // clear any pending thumbnail load
654 if (task) {
655 _ForegroundQueue.Remove(task);
656 task->Destroy();
657 }
658
659 } else {
660 TextureLoadTaskClass *load_task = tc->TextureLoadTask;
661
662 // if texture is not already loading a thumbnail and there is no
663 // background load near completion. (a background load waiting
664 // to be applied will be ready at the same time as a queued thumbnail.
665 // Why do the extra work?)
666 if (!task && (!load_task || load_task->Get_State() < TextureLoadTaskClass::STATE_LOAD_MIPMAP)) {
667
668 // create a thumbnail load task and add to foreground queue.
670 _ForegroundQueue.Push_Back(task);
671 }
672 }
673}
674
675
677{
678 WWPROFILE(("TextureLoader::Request_Background_Loading()"));
679 // Grab the foreground lock. This prevents the foreground thread
680 // from retiring any tasks related to this texture. It also
681 // serializes calls to Request_Background_Loading from other
682 // threads.
683 FastCriticalSectionClass::LockClass foreground_lock(_ForegroundCriticalSection);
684
685 // Has the texture already been loaded?
686 if (tc->Is_Initialized()) {
687 return;
688 }
689
690 TextureLoadTaskClass *task = tc->TextureLoadTask;
691
692 // if texture already has a load task, we don't need to create another one.
693 if (task) {
694 return;
695 }
696
698
699 if (Is_DX8_Thread()) {
700 Begin_Load_And_Queue(task);
701 } else {
702 _ForegroundQueue.Push_Back(task);
703 }
704}
705
706
708{
709 WWPROFILE(("TextureLoader::Request_Foreground_Loading()"));
710 // Grab the foreground lock. This prevents the foreground thread
711 // from retiring the load tasks for this texture. It also
712 // serializes calls to Request_Foreground_Loading from other
713 // threads.
714 FastCriticalSectionClass::LockClass foreground_lock(_ForegroundCriticalSection);
715
716 // Has the texture already been loaded?
717 if (tc->Is_Initialized()) {
718 return;
719 }
720
721 TextureLoadTaskClass *task = tc->TextureLoadTask;
722 TextureLoadTaskClass *task_thumb = tc->ThumbnailLoadTask;
723
724 if (Is_DX8_Thread()) {
725
726 // since we're in the DX8 thread, we can load the entire
727 // texture right now.
728
729 // if we have a thumbnail task waiting, kill it.
730 if (task_thumb) {
731 _ForegroundQueue.Remove(task_thumb);
732 task_thumb->Destroy();
733 }
734
735 if (task) {
736 // we need to remove the task from any queue, since we're going
737 // to finish it up right now.
738
739 // halt background thread. After we're holding this lock,
740 // we know the background thread cannot begin loading
741 // mipmap levels for this texture.
742 FastCriticalSectionClass::LockClass background_lock(_BackgroundCriticalSection);
743 _ForegroundQueue.Remove(task);
744 _BackgroundQueue.Remove(task);
745 } else {
746 // Since the task manages all the state associated with loading
747 // a texture, we temporarily create one.
749 }
750
751 // finish loading the task and destroy it.
752 task->Finish_Load();
753 task->Destroy();
754
755 } else {
756 // we are not in the DX8 thread. We need to add a high-priority loading
757 // task to the foreground queue.
758
759 // Grab the background lock. After we're holding this lock, we
760 // know the background thread cannot begin loading mipmap levels
761 // for this texture.
762 FastCriticalSectionClass::LockClass background_lock(_BackgroundCriticalSection);
763
764 // if we have a thumbnail task, we should cancel it. Since we are not
765 // the foreground thread, we are not allowed to call Destroy(). Instead,
766 // leave it queued in the completed state so it will be destroyed by Update().
767 if (task_thumb) {
769 }
770
771 if (task) {
772 // if a load task is waiting on the background queue, we need to
773 // move it to the foreground queue.
774 if (task->Get_List() == &_BackgroundQueue) {
775
776 // remove task from list
777 _BackgroundQueue.Remove(task);
778
779 // add to foreground queue.
780 _ForegroundQueue.Push_Back(task);
781 }
782
783 // upgrade the task priority
785
786 } else {
787 // allocate high priority load task
789
790 // add to back of foreground queue.
791 _ForegroundQueue.Push_Back(task);
792 }
793 }
794}
795
796
798{
799 // This function can only be called from the main thread.
800 // (Only the main thread can make the DX8 calls necessary
801 // to complete texture loading. If we wanted to flush
802 // the pending tasks from another thread, we'd probably
803 // want to set a bool that is checked by Update().
805
806 for (;;) {
807 bool done = false;
808
809 {
810 // we have no pending load tasks when both queues are empty
811 // and the background thread is not processing a texture.
812
813 // Grab the background lock. Once we're holding it, we
814 // know that the background thread is not processing any
815 // textures.
816
817 // NOTE: It's important that we do only hold on to the background
818 // lock while we check for completion. Otherwise, we will either
819 // violate the lock order when we call Update() (which grabs
820 // the foreground lock) or never give the background thread
821 // a chance to empty its queue.
822 FastCriticalSectionClass::LockClass background_lock(_BackgroundCriticalSection);
823 done = _BackgroundQueue.Is_Empty() && _ForegroundQueue.Is_Empty();
824 }
825
826 // exit loop if no entries in list
827 if (done) {
828 break;
829 }
830
831 Update();
833 }
834}
835
836
837// Nework update macro for texture loader.
838#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union
839#include <mmsystem.h>
840#define UPDATE_NETWORK \
841 if (network_callback) { \
842 unsigned long time2 = timeGetTime(); \
843 if (time2 - time > 20) { \
844 network_callback(); \
845 time = time2; \
846 } \
847 } \
848
849
850void TextureLoader::Update(void (*network_callback)(void))
851{
852 WWASSERT_PRINT(Is_DX8_Thread(), "TextureLoader::Update must be called from the main thread!");
853
854 if (TextureLoadSuspended) {
855 return;
856 }
857
858 // grab foreground lock to prevent any other thread from
859 // modifying texture tasks.
860 FastCriticalSectionClass::LockClass lock(_ForegroundCriticalSection);
861
862 unsigned long time = timeGetTime();
863
864 // while we have tasks on the foreground queue
865 while (TextureLoadTaskClass *task = _ForegroundQueue.Pop_Front()) {
867 // dispatch to proper task handler
868 switch (task->Get_Type()) {
870 Process_Foreground_Thumbnail(task);
871 break;
872
874 Process_Foreground_Load(task);
875 break;
876 }
877 }
878
879 TextureBaseClass::Invalidate_Old_Unused_Textures(TextureInactiveOverrideTime);
880}
881
883{
884 WWASSERT_PRINT(Is_DX8_Thread(),"TextureLoader::Suspend_Texture_Load must be called from the main thread!");
885 TextureLoadSuspended=true;
886}
887
889{
890 WWASSERT_PRINT(Is_DX8_Thread(),"TextureLoader::Continue_Texture_Load must be called from the main thread!");
891 TextureLoadSuspended=false;
892}
893
894void TextureLoader::Process_Foreground_Thumbnail(TextureLoadTaskClass *task)
895{
896 switch (task->Get_State()) {
899 // NOTE: fall-through is intentional
900
902 task->Destroy();
903 break;
904 }
905}
906
907
908void TextureLoader::Process_Foreground_Load(TextureLoadTaskClass *task)
909{
910 // Is high-priority task?
912 task->Finish_Load();
913 task->Destroy();
914 return;
915 }
916
917 // otherwise, must be a low-priority task.
918
919 switch (task->Get_State()) {
921 Begin_Load_And_Queue(task);
922 break;
923
925 task->End_Load();
926 task->Destroy();
927 break;
928 }
929}
930
931
932void TextureLoader::Begin_Load_And_Queue(TextureLoadTaskClass *task)
933{
934 // should only be called from the DX8 thread.
936
937 if (task->Begin_Load()) {
938 // add to front of background queue. This means the
939 // background load thread will service tasks in LIFO
940 // (last in, first out) order.
941
942 // NOTE: this was how the old code did it, with a
943 // comment that mentioned good reasons for doing so,
944 // without actually listing the reasons. I suspect
945 // it has something to do with visually important textures,
946 // like those in the foreground, starting their load last.
947 _BackgroundQueue.Push_Front(task);
948 } else {
949 // unable to load.
950 task->Apply_Missing_Texture();
951 task->Destroy();
952 }
953}
954
955
957{
958 // All D3D operations must run from main thread
960
961 // load thumbnail texture
962 IDirect3DTexture8 *d3d_texture = Load_Thumbnail(tc->Get_Full_Path(),tc->Get_HSV_Shift());
963
964 // apply thumbnail to texture
966 {
967 tc->Apply_New_Surface(d3d_texture, false);
968 }
969
970 // release our reference to thumbnail texture
971 d3d_texture->Release();
972 d3d_texture = 0;
973}
974
975
976void LoaderThreadClass::Thread_Function(void)
977{
978 while (running) {
979 // if there are no tasks on the background queue, no need to grab background lock.
980 if (!_BackgroundQueue.Is_Empty()) {
981 // Grab background load so other threads know we could be
982 // loading a texture.
983 FastCriticalSectionClass::LockClass lock(_BackgroundCriticalSection);
984
985 // try to remove a task from the background queue. This could fail
986 // if another thread modified the queue between our test above and
987 // grabbing the lock.
988 TextureLoadTaskClass* task = _BackgroundQueue.Pop_Front();
989 if (task) {
990 // verify task is in proper state for background processing.
993
994 // load mip map levels and return to foreground queue for final step.
995 task->Load();
996 _ForegroundQueue.Push_Back(task);
997 }
998 }
999
1000 Switch_Thread();
1001 }
1002}
1003
1004
1006//
1007// TextureLoaderTaskClass implementation
1008//
1010
1012: Texture (0),
1013 D3DTexture (0),
1015 Width (0),
1016 Height (0),
1017 MipLevelCount (0),
1018 Reduction (0),
1019 Type (TASK_NONE),
1021 State (STATE_NONE),
1022 HSVShift (0.0f,0.0f,0.0f)
1023{
1024 // because texture load tasks are pooled, the constructor and destructor
1025 // don't need to do much. The work of attaching a task to a texture is
1026 // is done by Init() and Deinit().
1027
1028 for (int i = 0; i < MIP_LEVELS_MAX; ++i) {
1030 LockedSurfacePitch[i] = 0;
1031 }
1032}
1033
1034
1039
1040
1042{
1043 // recycle or create a new texture load task with the given type
1044 // and priority, then associate the texture with the task.
1045
1046 // pull a load task from front of free list
1047 TextureLoadTaskClass *task = NULL;
1048 switch (tc->Get_Asset_Type())
1049 {
1050 case TextureBaseClass::TEX_REGULAR : task=_TexLoadFreeList.Pop_Front(); break;
1051 case TextureBaseClass::TEX_CUBEMAP : task=_CubeTexLoadFreeList.Pop_Front(); break;
1052 case TextureBaseClass::TEX_VOLUME : task=_VolTexLoadFreeList.Pop_Front(); break;
1053 default : WWASSERT(0);
1054 };
1055
1056 // if no tasks on free list, allocate a new task
1057 if (!task)
1058 {
1059 switch (tc->Get_Asset_Type())
1060 {
1064 default : WWASSERT(0);
1065 }
1066 }
1067 task->Init(tc, type, priority);
1068 return task;
1069}
1070
1071
1073{
1074 // detach the task from its texture, and return to free pool.
1075 Deinit();
1076 _TexLoadFreeList.Push_Front(this);
1077}
1078
1079
1081{
1082 // (gth) We should probably just MEMPool these task objects...
1083 while (TextureLoadTaskClass *task = _TexLoadFreeList.Pop_Front()) {
1084 delete task;
1085 }
1086 while (TextureLoadTaskClass *task = _CubeTexLoadFreeList.Pop_Front()) {
1087 delete task;
1088 }
1089 while (TextureLoadTaskClass *task = _VolTexLoadFreeList.Pop_Front()) {
1090 delete task;
1091 }
1092}
1093
1094
1096{
1097 WWASSERT(tc);
1098
1099 // NOTE: we must be in the main thread to avoid corrupting the texture's refcount.
1101 REF_PTR_SET(Texture, tc);
1102
1103 // Make sure texture has a filename.
1104 WWASSERT(Texture->Get_Full_Path() != "");
1105
1106 Type = type;
1107 Priority = priority;
1108 State = STATE_NONE;
1109
1110 D3DTexture = 0;
1111
1112 TextureClass* tex=Texture->As_TextureClass();
1113
1114 if (tex)
1115 {
1116 Format = tex->Get_Texture_Format(); // don't assume format yet KM
1117 }
1118 else
1119 {
1121 }
1122
1123 Width = 0;
1124 Height = 0;
1125 MipLevelCount = Texture->MipLevelCount;
1126 Reduction = Texture->Get_Reduction();
1127 HSVShift = Texture->Get_HSV_Shift();
1128
1129
1130 for (int i = 0; i < MIP_LEVELS_MAX; ++i)
1131 {
1133 LockedSurfacePitch[i] = 0;
1134 }
1135
1136 switch (Type)
1137 {
1138 case TASK_THUMBNAIL:
1139 WWASSERT(Texture->ThumbnailLoadTask == NULL);
1140 Texture->ThumbnailLoadTask = this;
1141 break;
1142
1143 case TASK_LOAD:
1144 WWASSERT(Texture->TextureLoadTask == NULL);
1145 Texture->TextureLoadTask = this;
1146 break;
1147 }
1148}
1149
1150
1152{
1153 // task should not be on any list when it is being detached from texture.
1154 WWASSERT(Next == NULL);
1155 WWASSERT(Prev == NULL);
1156
1158
1159 for (int i = 0; i < MIP_LEVELS_MAX; ++i) {
1161 }
1162
1163 if (Texture) {
1164 switch (Type) {
1165 case TASK_THUMBNAIL:
1166 WWASSERT(Texture->ThumbnailLoadTask == this);
1167 Texture->ThumbnailLoadTask = NULL;
1168 break;
1169
1170 case TASK_LOAD:
1171 WWASSERT(Texture->TextureLoadTask == this);
1172 Texture->TextureLoadTask = NULL;
1173 break;
1174 }
1175
1176 // NOTE: we must be in main thread to avoid corrupting Texture's refcount.
1179 }
1180}
1181
1182
1184{
1186
1187 bool loaded = false;
1188
1189 // if allowed, begin a compressed load
1190 if (Texture->Is_Compression_Allowed()) {
1191 loaded = Begin_Compressed_Load();
1192 }
1193
1194 // otherwise, begin an uncompressed load
1195 if (!loaded) {
1196 loaded = Begin_Uncompressed_Load();
1197 }
1198
1199 // if not loaded, abort.
1200 if (!loaded) {
1201 return false;
1202 }
1203
1204 // lock surfaces in preparation for copy
1205 Lock_Surfaces();
1206
1208
1209 return true;
1210}
1211
1212
1213// ----------------------------------------------------------------------------
1214//
1215// Load mipmap levels to a pre-generated and locked texture object based on
1216// information in load task object. Try loading from a DDS file first and if
1217// that fails try a TGA.
1218//
1219// ----------------------------------------------------------------------------
1221{
1224
1225 bool loaded = false;
1226
1227 // if allowed, try to load compressed mipmaps
1228 if (Texture->Is_Compression_Allowed()) {
1229 loaded = Load_Compressed_Mipmap();
1230 }
1231
1232 // otherwise, load uncompressed mipmaps
1233 if (!loaded) {
1234 loaded = Load_Uncompressed_Mipmap();
1235 }
1236
1238
1239 return loaded;
1240}
1241
1242
1244{
1246
1248 Apply(true);
1249
1251}
1252
1253
1255{
1256 switch (State) {
1257 // NOTE: fall-through below is intentional.
1258
1259 case STATE_NONE:
1260 if (!Begin_Load()) {
1262 break;
1263 }
1264
1265 case STATE_LOAD_BEGUN:
1266 Load();
1267
1268 case STATE_LOAD_MIPMAP:
1269 End_Load();
1270
1271 default:
1272 break;
1273 }
1274}
1275
1276
1285
1286
1287void TextureLoadTaskClass::Apply(bool initialize)
1288{
1290
1291 // Verify that none of the mip levels are locked
1292 for (unsigned i=0;i<MipLevelCount;++i) {
1294 }
1295
1296 Texture->Apply_New_Surface(D3DTexture, initialize);
1297
1298 D3DTexture->Release();
1299 D3DTexture = NULL;
1300}
1301
1302static bool Get_Texture_Information
1303(
1304 const char* filename,
1305 unsigned& reduction,
1306 unsigned& w,
1307 unsigned& h,
1308 unsigned& d,
1309 WW3DFormat& format,
1310 unsigned& mip_count,
1311 bool compressed
1312)
1313{
1315
1316 if (!thumb)
1317 {
1318 if (compressed)
1319 {
1320 DDSFileClass dds_file(filename, 0);
1321 if (!dds_file.Is_Available()) return false;
1322
1323 // Destination size will be the next power of two square from the larger width and height...
1324 w = dds_file.Get_Width(0);
1325 h = dds_file.Get_Height(0);
1326 d = dds_file.Get_Depth(0);
1327 format = dds_file.Get_Format();
1328 mip_count = dds_file.Get_Mip_Level_Count();
1329 //Figure out correct reduction
1330 int reqReduction=WW3D::Get_Texture_Reduction(); //requested reduction
1331
1332 if (reqReduction >= mip_count)
1333 reqReduction=mip_count-1; //leave only the lowest level
1334
1335 //Clamp reduction
1336 int curReduction=0;
1337 int curWidth=w;
1338 int curHeight=h;
1340
1341 while (curReduction < reqReduction && curWidth > minDim && curHeight > minDim)
1342 { curWidth >>=1; //keep dividing
1343 curHeight >>=1;
1344 curReduction++;
1345 }
1346 reduction=curReduction;
1347 return true;
1348 }
1349
1350 Targa targa;
1351 if (TARGA_ERROR_HANDLER(targa.Open(filename, TGA_READMODE), filename))
1352 {
1353 return false;
1354 }
1355
1356 unsigned int bpp;
1357 WW3DFormat dest_format;
1358 Get_WW3D_Format(dest_format,format,bpp,targa);
1359
1360 mip_count = 0;
1361
1362 //Figure out how many mip levels this texture will occupy
1363 for (int i=targa.Header.Width, j=targa.Header.Height; i > 0 && j > 0; i>>=1, j>>=1)
1364 mip_count++;
1365
1366 //Figure out correct reduction
1367 int reqReduction=WW3D::Get_Texture_Reduction(); //requested reduction
1368
1369 if (reqReduction >= mip_count)
1370 reqReduction=mip_count-1; //leave only the lowest level
1371
1372 //Clamp reduction
1373 int curReduction=0;
1374 int curWidth=targa.Header.Width;
1375 int curHeight=targa.Header.Height;
1377
1378 while (curReduction < reqReduction && curWidth > minDim && curHeight > minDim)
1379 { curWidth >>=1; //keep dividing
1380 curHeight >>=1;
1381 curReduction++;
1382 }
1383 reduction=curReduction;
1384
1385 // Destination size will be the next power of two square from the larger width and height...
1386 w = targa.Header.Width;
1387 h = targa.Header.Height;
1388 d = 1;
1389 return true;
1390 }
1391
1392 if (compressed &&
1398 return false;
1399 }
1400
1401 w=thumb->Get_Original_Texture_Width() >> reduction;
1402 h=thumb->Get_Original_Texture_Height() >> reduction;
1403 //d=thumb->Get_Original_Texture_Depth() >> reduction; // need to a volume texture support to thumbnails...maybe
1404 mip_count=thumb->Get_Original_Texture_Mip_Level_Count();
1405 format=thumb->Get_Original_Texture_Format();
1406 return true;
1407}
1408
1409
1411{
1412 unsigned orig_w,orig_h,orig_d,orig_mip_count,reduction;
1413 WW3DFormat orig_format;
1414 if (!Get_Texture_Information
1415 (
1416 Texture->Get_Full_Path(),
1417 reduction,
1418 orig_w,
1419 orig_h,
1420 orig_d,
1421 orig_format,
1422 orig_mip_count,
1423 true
1424 )
1425 )
1426 {
1427 return false;
1428 }
1429
1430 // Destination size will be the next power of two square from the larger width and height...
1431 unsigned int width = orig_w;
1432 unsigned int height = orig_h;
1433 TextureLoader::Validate_Texture_Size(width, height,orig_d);
1434
1435 // If the size doesn't match, try and see if texture reduction would help... (mainly for
1436 // cases where loaded texture is larger than hardware limit)
1437 if (width != orig_w || height != orig_h)
1438 {
1439 for (unsigned int i = 1; i < orig_mip_count; ++i)
1440 {
1441 unsigned w=orig_w>>i;
1442 if (w<4) w=4;
1443 unsigned h=orig_h>>i;
1444 if (h<4) h=4;
1445 unsigned tmp_w=w;
1446 unsigned tmp_h=h;
1447
1449
1450 if (w == tmp_w && h == tmp_h)
1451 {
1452 Reduction += i;
1453 width = w;
1454 height = h;
1455 break;
1456 }
1457 }
1458 }
1459
1460 Width = width;
1461 Height = height;
1462 Format = Get_Valid_Texture_Format(orig_format, Texture->Is_Compression_Allowed());
1463 Reduction = reduction;
1464
1465
1466 if (!Texture->Is_Reducible() || Texture->MipLevelCount == MIP_LEVELS_1)
1467 Reduction = 0; //app doesn't want this texture to ever be reduced.
1468 else
1469 //Make sure we don't reduce below the level requested by the app
1470 if (Texture->MipLevelCount != MIP_LEVELS_ALL && (Texture->MipLevelCount - Reduction) < 1)
1471 Reduction = Texture->MipLevelCount - 1;
1472
1473 //Another sanity check
1474 if (Reduction >= orig_mip_count)
1475 Reduction = 0; //should not be possible to get here, but check just in case.
1476
1477 unsigned int mip_level_count = Get_Mip_Level_Count();
1478 int reducedWidth=Width;
1479 int reducedHeight=Height;
1480
1481 // If texture wants all mip levels, take as many as the file contains (not necessarily all)
1482 // Otherwise take as many mip levels as the texture wants, not to exceed the count in file...
1483 if (!mip_level_count)
1484 {
1485 reducedWidth >>= Reduction;
1486 reducedHeight >>= Reduction;
1487 mip_level_count = orig_mip_count-Reduction;//dds_file.Get_Mip_Level_Count();
1488 if (mip_level_count < 1)
1489 mip_level_count = 1; //sanity check to make sure something gets loaded.
1490 }
1491 else
1492 {
1493 if (mip_level_count > orig_mip_count)
1494 { //dds_file.Get_Mip_Level_Count()) {
1495 mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count();
1496 }
1497
1498 if (Reduction)
1499 { reducedWidth >>= Reduction;
1500 reducedHeight >>= Reduction;
1501 mip_level_count -= Reduction; //reduced requested number by those removed.
1502 }
1503 }
1504
1505 // Once more, verify that the mip level count is correct (in case it was changed here it might not
1506 // match the size...well actually it doesn't have to match but it can't be bigger than the size)
1507 unsigned int max_mip_level_count = 1;
1508 unsigned int w = 4;
1509 unsigned int h = 4;
1510
1511 while (w < Width && h < Height)
1512 {
1513 w += w;
1514 h += h;
1515 max_mip_level_count++;
1516 }
1517
1518 if (mip_level_count > max_mip_level_count)
1519 {
1520 mip_level_count = max_mip_level_count;
1521 }
1522
1524 (
1525 reducedWidth,
1526 reducedHeight,
1527 Format,
1528 (MipCountType)mip_level_count,
1530 D3DPOOL_MANAGED
1531#else
1532 D3DPOOL_SYSTEMMEM
1533#endif
1534 );
1535
1536 MipLevelCount = mip_level_count;
1537
1538 return true;
1539}
1540
1542{
1543 unsigned width,height,depth,orig_mip_count,reduction;
1544 WW3DFormat orig_format;
1545 if (!Get_Texture_Information
1546 (
1547 Texture->Get_Full_Path(),
1548 reduction,
1549 width,
1550 height,
1551 depth,
1552 orig_format,
1553 orig_mip_count,
1554 false
1555 )
1556 )
1557 {
1558 return false;
1559 }
1560
1561 WW3DFormat src_format=orig_format;
1562 WW3DFormat dest_format=src_format;
1563 dest_format=Get_Valid_Texture_Format(dest_format,false); // No compressed destination format if reading from targa...
1564
1565 if ( src_format != WW3D_FORMAT_A8R8G8B8
1566 && src_format != WW3D_FORMAT_R8G8B8
1567 && src_format != WW3D_FORMAT_X8R8G8B8 )
1568 {
1569 WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!\n", Texture->Get_Full_Path()));
1570 }
1571
1572 // Destination size will be the next power of two square from the larger width and height...
1573 unsigned ow = width;
1574 unsigned oh = height;
1575 TextureLoader::Validate_Texture_Size(width, height,depth);
1576 if (width != ow || height != oh)
1577 {
1578 WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d\n", Texture->Get_Full_Path(), ow, oh, width, height));
1579 }
1580
1581 Width = width;
1582 Height = height;
1583 Reduction = reduction;
1584
1585 if (!Texture->Is_Reducible() || Texture->MipLevelCount == MIP_LEVELS_1)
1586 Reduction = 0; //app doesn't want this texture to ever be reduced.
1587 else
1588 //Make sure we don't reduce below the level requested by the app
1589 if (Texture->MipLevelCount != MIP_LEVELS_ALL && (Texture->MipLevelCount - Reduction) < 1)
1590 Reduction = Texture->MipLevelCount - 1;
1591
1592 //Another sanity check
1593 if (Reduction >= orig_mip_count)
1594 Reduction = 0; //should not be possible to get here, but check just in case.
1595
1597 {
1598 Format=dest_format;
1599 // Format = Get_Valid_Texture_Format(dest_format, false); validated above
1600 }
1601 else
1602 {
1604 }
1605
1606 int reducedWidth=Width;
1607 int reducedHeight=Height;
1608 int reducedMipCount=Texture->MipLevelCount;
1609
1610 if (Reduction)
1611 { //we don't care about specific levels so reduce them if needed.
1612 reducedWidth >>= Reduction;
1613 reducedHeight >>= Reduction;
1614 if (reducedMipCount != MIP_LEVELS_ALL)
1615 reducedMipCount -= Reduction;
1616 }
1617
1619 (
1620 reducedWidth,
1621 reducedHeight,
1622 Format,
1623 (MipCountType)reducedMipCount,
1625 D3DPOOL_MANAGED
1626#else
1627 D3DPOOL_SYSTEMMEM
1628#endif
1629 );
1630
1631 return true;
1632}
1633
1634/*
1635bool TextureLoadTaskClass::Begin_Compressed_Load(void)
1636{
1637 DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction());
1638 if (!dds_file.Is_Available()) {
1639 return false;
1640 }
1641
1642 // Destination size will be the next power of two square from the larger width and height...
1643 unsigned int width = dds_file.Get_Width(0);
1644 unsigned int height = dds_file.Get_Height(0);
1645 TextureLoader::Validate_Texture_Size(width, height);
1646
1647 // If the size doesn't match, try and see if texture reduction would help... (mainly for
1648 // cases where loaded texture is larger than hardware limit)
1649 if (width != dds_file.Get_Width(0) || height != dds_file.Get_Height(0)) {
1650 for (unsigned int i = 1; i < dds_file.Get_Mip_Level_Count(); ++i) {
1651 unsigned int w = dds_file.Get_Width(i);
1652 unsigned int h = dds_file.Get_Height(i);
1653 TextureLoader::Validate_Texture_Size(w,h);
1654
1655 if (w == dds_file.Get_Width(i) && h == dds_file.Get_Height(i)) {
1656 Reduction += i;
1657 width = w;
1658 height = h;
1659 break;
1660 }
1661 }
1662 }
1663
1664 Width = width;
1665 Height = height;
1666 Format = Get_Valid_Texture_Format(dds_file.Get_Format(), Texture->Is_Compression_Allowed());
1667
1668 unsigned int mip_level_count = Get_Mip_Level_Count();
1669
1670 // If texture wants all mip levels, take as many as the file contains (not necessarily all)
1671 // Otherwise take as many mip levels as the texture wants, not to exceed the count in file...
1672 if (!mip_level_count) {
1673 mip_level_count = dds_file.Get_Mip_Level_Count();
1674 } else if (mip_level_count > dds_file.Get_Mip_Level_Count()) {
1675 mip_level_count = dds_file.Get_Mip_Level_Count();
1676 }
1677
1678 // Once more, verify that the mip level count is correct (in case it was changed here it might not
1679 // match the size...well actually it doesn't have to match but it can't be bigger than the size)
1680 unsigned int max_mip_level_count = 1;
1681 unsigned int w = 4;
1682 unsigned int h = 4;
1683
1684 while (w < Width && h < Height) {
1685 w += w;
1686 h += h;
1687 max_mip_level_count++;
1688 }
1689
1690 if (mip_level_count > max_mip_level_count) {
1691 mip_level_count = max_mip_level_count;
1692 }
1693
1694 D3DTexture = DX8Wrapper::_Create_DX8_Texture(
1695 Width,
1696 Height,
1697 Format,
1698 (TextureBaseClass::MipCountType)mip_level_count,
1699#ifdef USE_MANAGED_TEXTURES
1700 D3DPOOL_MANAGED);
1701#else
1702 D3DPOOL_SYSTEMMEM);
1703#endif
1704 MipLevelCount = mip_level_count;
1705 return true;
1706}
1707
1708
1709bool TextureLoadTaskClass::Begin_Uncompressed_Load(void)
1710{
1711 Targa targa;
1712 if (TARGA_ERROR_HANDLER(targa.Open(Texture->Get_Full_Path(), TGA_READMODE), Texture->Get_Full_Path())) {
1713 return false;
1714 }
1715
1716 unsigned int bpp;
1717 WW3DFormat src_format, dest_format;
1718 Get_WW3D_Format(dest_format,src_format,bpp,targa);
1719
1720 if ( src_format != WW3D_FORMAT_A8R8G8B8
1721 && src_format != WW3D_FORMAT_R8G8B8
1722 && src_format != WW3D_FORMAT_X8R8G8B8) {
1723 WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!\n", Texture->Get_Full_Path()));
1724 }
1725
1726 // Destination size will be the next power of two square from the larger width and height...
1727 unsigned width=targa.Header.Width, height=targa.Header.Height;
1728 int ReductionFactor=Get_Reduction();
1729 int MipLevels=0;
1730
1731 //Figure out how many mip levels this texture will occupy
1732 for (int i=width, j=height; i > 0 && j > 0; i>>=1, j>>=1)
1733 MipLevels++;
1734
1735 //Adjust the reduction factor to keep textures above some minimum dimensions
1736 if (MipLevels <= WW3D::Get_Texture_Min_Mip_Levels())
1737 ReductionFactor=0;
1738 else
1739 { int mipToDrop=MipLevels-WW3D::Get_Texture_Min_Mip_Levels();
1740 if (ReductionFactor >= mipToDrop)
1741 ReductionFactor=mipToDrop;
1742 }
1743
1744 width=targa.Header.Width>>ReductionFactor;
1745 height=targa.Header.Height>>ReductionFactor;
1746 unsigned ow = width;
1747 unsigned oh = height;
1748 TextureLoader::Validate_Texture_Size(width, height);
1749 if (width != ow || height != oh) {
1750 WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d\n", Texture->Get_Full_Path(), ow, oh, width, height));
1751 }
1752
1753 Width = width;
1754 Height = height;
1755
1756 // changed because format was being read from previous loading task?! KJM
1757 Format=dest_format;
1758 //if (Format == WW3D_FORMAT_UNKNOWN) {
1759 // Format = Get_Valid_Texture_Format(dest_format, false);
1760 //} else {
1761 // Format = Get_Valid_Texture_Format(Format, false);
1762 //}
1763
1764 D3DTexture = DX8Wrapper::_Create_DX8_Texture
1765 (
1766 Width,
1767 Height,
1768 Format,
1769 Texture->MipLevelCount,
1770#ifdef USE_MANAGED_TEXTURES
1771 D3DPOOL_MANAGED);
1772#else
1773 D3DPOOL_SYSTEMMEM);
1774#endif
1775 return true;
1776}
1777*/
1778
1780{
1781 MipLevelCount = D3DTexture->GetLevelCount();
1782
1783 for (unsigned int i = 0; i < MipLevelCount; ++i)
1784 {
1785 D3DLOCKED_RECT locked_rect;
1787 (
1788 Peek_D3D_Texture()->LockRect
1789 (
1790 i,
1791 &locked_rect,
1792 NULL,
1793 0
1794 )
1795 );
1796 LockedSurfacePtr[i] = (unsigned char *)locked_rect.pBits;
1797 LockedSurfacePitch[i] = locked_rect.Pitch;
1798 }
1799}
1800
1801
1803{
1804 for (unsigned int i = 0; i < MipLevelCount; ++i)
1805 {
1806 if (LockedSurfacePtr[i])
1807 {
1809 DX8_ErrorCode(Peek_D3D_Texture()->UnlockRect(i));
1810 }
1812 }
1813
1814#ifndef USE_MANAGED_TEXTURES
1815 IDirect3DTexture8* tex = DX8Wrapper::_Create_DX8_Texture(Width, Height, Format, Texture->MipLevelCount,D3DPOOL_DEFAULT);
1816 DX8CALL(UpdateTexture(Peek_D3D_Texture(),tex));
1817 Peek_D3D_Texture()->Release();
1818 D3DTexture=tex;
1819 WWDEBUG_SAY(("Created non-managed texture (%s)\n",Texture->Get_Full_Path()));
1820#endif
1821
1822}
1823
1824
1826{
1827 DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction());
1828
1829 // if we can't load from file, indicate rror.
1830 if (!dds_file.Is_Available() || !dds_file.Load())
1831 {
1832 return false;
1833 }
1834
1835 // regular 2d texture
1836 unsigned int width = Get_Width();
1837 unsigned int height = Get_Height();
1838
1839 if (Reduction)
1840 { for (unsigned int level = 0; level < Reduction; ++level) {
1841 width >>= 1;
1842 height >>= 1;
1843 }
1844 }
1845
1846 for (unsigned int level = 0; level < Get_Mip_Level_Count(); ++level)
1847 {
1848 WWASSERT(width && height);
1849 dds_file.Copy_Level_To_Surface
1850 (
1851 level,
1852 Get_Format(),
1853 width,
1854 height,
1857 HSVShift
1858 );
1859
1860 width >>= 1;
1861 height >>= 1;
1862 }
1863
1864 return true;
1865}
1866
1867
1869{
1870 if (!Get_Mip_Level_Count())
1871 {
1872 return false;
1873 }
1874
1875 Targa targa;
1876 if (TARGA_ERROR_HANDLER(targa.Open(Texture->Get_Full_Path(), TGA_READMODE), Texture->Get_Full_Path())) {
1877 return false;
1878 }
1879
1880 // DX8 uses image upside down compared to TGA
1881 targa.Header.ImageDescriptor ^= TGAIDF_YORIGIN;
1882
1883 WW3DFormat src_format;
1884 WW3DFormat dest_format;
1885 unsigned int src_bpp = 0;
1886 Get_WW3D_Format(dest_format,src_format,src_bpp,targa);
1887 if (src_format==WW3D_FORMAT_UNKNOWN) return false;
1888
1889 dest_format = Get_Format(); // Texture can be requested in different format than the most obvious from the TGA
1890
1891 char palette[256*4];
1892 targa.SetPalette(palette);
1893
1894 unsigned int src_width = targa.Header.Width;
1895 unsigned int src_height = targa.Header.Height;
1896 unsigned int width = Get_Width();
1897 unsigned int height = Get_Height();
1898
1899 // NOTE: We load the palette but we do not yet support paletted textures!
1900 if (TARGA_ERROR_HANDLER(targa.Load(Texture->Get_Full_Path(), TGAF_IMAGE, false), Texture->Get_Full_Path())) {
1901 return false;
1902 }
1903
1904 unsigned char * src_surface = (unsigned char*)targa.GetImage();
1905 unsigned char * converted_surface = NULL;
1906
1907 // No paletted format allowed when generating mipmaps
1908 Vector3 hsv_shift=HSVShift;
1909 if ( src_format == WW3D_FORMAT_A1R5G5B5
1910 || src_format == WW3D_FORMAT_R5G6B5
1911 || src_format == WW3D_FORMAT_A4R4G4B4
1912 || src_format == WW3D_FORMAT_P8
1913 || src_format == WW3D_FORMAT_L8
1914 || src_width != width
1915 || src_height != height) {
1916
1917 converted_surface = new unsigned char[width*height*4];
1918 dest_format = Get_Valid_Texture_Format(WW3D_FORMAT_A8R8G8B8, false);
1919
1921 converted_surface,
1922 width,
1923 height,
1924 width*4,
1925 WW3D_FORMAT_A8R8G8B8, //dest_format,
1926 src_surface,
1927 src_width,
1928 src_height,
1929 src_width*src_bpp,
1930 src_format,
1931 (unsigned char*)targa.GetPalette(),
1932 targa.Header.CMapDepth>>3,
1933 false,
1934 hsv_shift);
1935 hsv_shift=Vector3(0.0f,0.0f,0.0f);
1936
1937 src_surface = converted_surface;
1938 src_format = WW3D_FORMAT_A8R8G8B8; //dest_format;
1939 src_width = width;
1940 src_height = height;
1941 src_bpp = Get_Bytes_Per_Pixel(src_format);
1942 }
1943
1944 unsigned src_pitch = src_width * src_bpp;
1945
1946 if (Reduction)
1947 { //texture needs to be reduced so allocate storage for full-sized version.
1948 unsigned char * destination_surface = new unsigned char[width*height*4];
1949 //generate upper mip-levels that will be dropped in final texture
1950 for (unsigned int level = 0; level < Reduction; ++level) {
1952 (unsigned char *)destination_surface,
1953 width,
1954 height,
1955 src_pitch,
1956 Get_Format(),
1957 src_surface,
1958 src_width,
1959 src_height,
1960 src_pitch,
1961 src_format,
1962 NULL,
1963 0,
1964 true,
1965 hsv_shift);
1966
1967 width >>= 1;
1968 height >>= 1;
1969 src_width >>= 1;
1970 src_height >>= 1;
1971 }
1972 delete [] destination_surface;
1973 }
1974
1975 for (unsigned int level = 0; level < Get_Mip_Level_Count(); ++level) {
1979 width,
1980 height,
1982 Get_Format(),
1983 src_surface,
1984 src_width,
1985 src_height,
1986 src_pitch,
1987 src_format,
1988 NULL,
1989 0,
1990 true,
1991 hsv_shift);
1992 hsv_shift=Vector3(0.0f,0.0f,0.0f);
1993
1994 width >>= 1;
1995 height >>= 1;
1996 src_width >>= 1;
1997 src_height >>= 1;
1998
1999 if (!width || !height || !src_width || !src_height) {
2000 break;
2001 }
2002 }
2003
2004 if (converted_surface) {
2005 delete[] converted_surface;
2006 }
2007
2008 return true;
2009}
2010
2011
2012unsigned char * TextureLoadTaskClass::Get_Locked_Surface_Ptr(unsigned int level)
2013{
2014 WWASSERT(level<MipLevelCount);
2015 WWASSERT(LockedSurfacePtr[level]);
2016 return LockedSurfacePtr[level];
2017}
2018
2019// ----------------------------------------------------------------------------
2020//
2021// Return locked surface pitch (in bytes) at a specific level. The call will
2022// assert if level is greater or equal to the number of mip levels or if the
2023// requested level has not been locked.
2024//
2025// ----------------------------------------------------------------------------
2026
2027unsigned int TextureLoadTaskClass::Get_Locked_Surface_Pitch(unsigned int level) const
2028{
2029 WWASSERT(level<MipLevelCount);
2030 WWASSERT(LockedSurfacePtr[level]);
2031 return LockedSurfacePitch[level];
2032}
2033
2034
2035
2036
2037
2038// CubeTextureLoadTaskClass
2041{
2042 // because texture load tasks are pooled, the constructor and destructor
2043 // don't need to do much. The work of attaching a task to a texture is
2044 // is done by Init() and Deinit().
2045
2046 for (int f=0;f<6;f++)
2047 {
2048 for (int i = 0; i < MIP_LEVELS_MAX; ++i)
2049 {
2050 LockedCubeSurfacePtr[f][i] = NULL;
2051 LockedCubeSurfacePitch[f][i] = 0;
2052 }
2053 }
2054}
2055
2057{
2058 // detach the task from its texture, and return to free pool.
2059 Deinit();
2060 _CubeTexLoadFreeList.Push_Front(this);
2061}
2062
2063
2065{
2066 WWASSERT(tc);
2067
2068 // NOTE: we must be in the main thread to avoid corrupting the texture's refcount.
2070 REF_PTR_SET(Texture, tc);
2071
2072 // Make sure texture has a filename.
2073 WWASSERT(Texture->Get_Full_Path() != "");
2074
2075 Type = type;
2076 Priority = priority;
2077 State = STATE_NONE;
2078
2079 D3DTexture = 0;
2080
2081 CubeTextureClass* tex=Texture->As_CubeTextureClass();
2082
2083 if (tex)
2084 {
2085 Format = tex->Get_Texture_Format(); // don't assume format yet KM
2086 }
2087 else
2088 {
2090 }
2091
2092 Width = 0;
2093 Height = 0;
2094 MipLevelCount = Texture->MipLevelCount;
2095 Reduction = Texture->Get_Reduction();
2096 HSVShift = Texture->Get_HSV_Shift();
2097
2098
2099 for (int f=0; f<6; f++)
2100 {
2101 for (int i = 0; i < MIP_LEVELS_MAX; ++i)
2102 {
2103 LockedCubeSurfacePtr[f][i] = NULL;
2104 LockedCubeSurfacePitch[f][i] = 0;
2105 }
2106 }
2107
2108 switch (Type)
2109 {
2110 case TASK_THUMBNAIL:
2111 WWASSERT(Texture->ThumbnailLoadTask == NULL);
2112 Texture->ThumbnailLoadTask = this;
2113 break;
2114
2115 case TASK_LOAD:
2116 WWASSERT(Texture->TextureLoadTask == NULL);
2117 Texture->TextureLoadTask = this;
2118 break;
2119 }
2120}
2121
2122
2124{
2125 // task should not be on any list when it is being detached from texture.
2126 WWASSERT(Next == NULL);
2127 WWASSERT(Prev == NULL);
2128
2130
2131 for (int f=0; f<6; f++)
2132 {
2133 for (int i = 0; i < MIP_LEVELS_MAX; ++i)
2134 {
2135 WWASSERT(LockedCubeSurfacePtr[f][i] == NULL);
2136 }
2137 }
2138
2139 if (Texture)
2140 {
2141 switch (Type)
2142 {
2143 case TASK_THUMBNAIL:
2144 WWASSERT(Texture->ThumbnailLoadTask == this);
2145 Texture->ThumbnailLoadTask = NULL;
2146 break;
2147
2148 case TASK_LOAD:
2149 WWASSERT(Texture->TextureLoadTask == this);
2150 Texture->TextureLoadTask = NULL;
2151 break;
2152 }
2153
2154 // NOTE: we must be in main thread to avoid corrupting Texture's refcount.
2157 }
2158}
2159
2161{
2162 for (unsigned int f=0; f<6; f++)
2163 {
2164 for (unsigned int i=0; i<MipLevelCount; i++)
2165 {
2166 D3DLOCKED_RECT locked_rect;
2168 (
2169 Peek_D3D_Cube_Texture()->LockRect
2170 (
2171 (D3DCUBEMAP_FACES)f,
2172 i,
2173 &locked_rect,
2174 NULL,
2175 0
2176 )
2177 );
2178 LockedCubeSurfacePtr[f][i] = (unsigned char *)locked_rect.pBits;
2179 LockedCubeSurfacePitch[f][i]= locked_rect.Pitch;
2180 }
2181 }
2182}
2183
2185{
2186 for (unsigned int f=0; f<6; f++)
2187 {
2188 for (unsigned int i = 0; i < MipLevelCount; ++i)
2189 {
2190 if (LockedCubeSurfacePtr[f][i])
2191 {
2194 (
2195 Peek_D3D_Cube_Texture()->UnlockRect((D3DCUBEMAP_FACES)f,i)
2196 );
2197 }
2198 LockedCubeSurfacePtr[f][i] = NULL;
2199 }
2200 }
2201
2202#ifndef USE_MANAGED_TEXTURES
2203 IDirect3DCubeTexture8* tex = DX8Wrapper::_Create_DX8_Cube_Texture
2204 (
2205 Width,
2206 Height,
2207 Format,
2208 Texture->MipLevelCount,
2209 D3DPOOL_DEFAULT
2210 );
2211 DX8CALL(UpdateTexture(Peek_D3D_Volume_Texture(),tex));
2212 Peek_D3D_Volume_Texture()->Release();
2213 D3DTexture=tex;
2214 WWDEBUG_SAY(("Created non-managed texture (%s)\n",Texture->Get_Full_Path()));
2215#endif
2216
2217}
2218
2219
2220
2222{
2223 unsigned orig_w,orig_h,orig_d,orig_mip_count,reduction;
2224 WW3DFormat orig_format;
2225 if (!Get_Texture_Information
2226 (
2227 Texture->Get_Full_Path(),
2228 reduction,
2229 orig_w,
2230 orig_h,
2231 orig_d,
2232 orig_format,
2233 orig_mip_count,
2234 true
2235 )
2236 )
2237 {
2238 return false;
2239 }
2240
2241 // Destination size will be the next power of two square from the larger width and height...
2242 unsigned int width = orig_w;
2243 unsigned int height = orig_h;
2244 TextureLoader::Validate_Texture_Size(width, height,orig_d);
2245
2246 // If the size doesn't match, try and see if texture reduction would help... (mainly for
2247 // cases where loaded texture is larger than hardware limit)
2248 if (width != orig_w || height != orig_h)
2249 {
2250 for (unsigned int i = 1; i < orig_mip_count; ++i)
2251 {
2252 unsigned w=orig_w>>i;
2253 if (w<4) w=4;
2254 unsigned h=orig_h>>i;
2255 if (h<4) h=4;
2256 unsigned tmp_w=w;
2257 unsigned tmp_h=h;
2258
2260
2261 if (w == tmp_w && h == tmp_h)
2262 {
2263 Reduction += i;
2264 width = w;
2265 height = h;
2266 break;
2267 }
2268 }
2269 }
2270
2271 Width = width;
2272 Height = height;
2273 Format = Get_Valid_Texture_Format(orig_format, Texture->Is_Compression_Allowed());
2274
2275 unsigned int mip_level_count = Get_Mip_Level_Count();
2276
2277 // If texture wants all mip levels, take as many as the file contains (not necessarily all)
2278 // Otherwise take as many mip levels as the texture wants, not to exceed the count in file...
2279 if (!mip_level_count)
2280 {
2281 mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count();
2282 }
2283 else if (mip_level_count > orig_mip_count)
2284 {//dds_file.Get_Mip_Level_Count()) {
2285 mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count();
2286 }
2287
2288 // Once more, verify that the mip level count is correct (in case it was changed here it might not
2289 // match the size...well actually it doesn't have to match but it can't be bigger than the size)
2290 unsigned int max_mip_level_count = 1;
2291 unsigned int w = 4;
2292 unsigned int h = 4;
2293
2294 while (w < Width && h < Height)
2295 {
2296 w += w;
2297 h += h;
2298 max_mip_level_count++;
2299 }
2300
2301 if (mip_level_count > max_mip_level_count)
2302 {
2303 mip_level_count = max_mip_level_count;
2304 }
2305
2307 (
2308 Width,
2309 Height,
2310 Format,
2311 (MipCountType)mip_level_count,
2313 D3DPOOL_MANAGED
2314#else
2315 D3DPOOL_SYSTEMMEM
2316#endif
2317 );
2318
2319 MipLevelCount = mip_level_count;
2320 return true;
2321}
2322
2324{
2325 unsigned width,height,depth,orig_mip_count,reduction;
2326 WW3DFormat orig_format;
2327 if (!Get_Texture_Information
2328 (
2329 Texture->Get_Full_Path(),
2330 reduction,
2331 width,
2332 height,
2333 depth,
2334 orig_format,
2335 orig_mip_count,
2336 false
2337 )
2338 )
2339 {
2340 return false;
2341 }
2342
2343 WW3DFormat src_format=orig_format;
2344 WW3DFormat dest_format=src_format;
2345 dest_format=Get_Valid_Texture_Format(dest_format,false); // No compressed destination format if reading from targa...
2346
2347 if ( src_format != WW3D_FORMAT_A8R8G8B8
2348 && src_format != WW3D_FORMAT_R8G8B8
2349 && src_format != WW3D_FORMAT_X8R8G8B8 )
2350 {
2351 WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!\n", Texture->Get_Full_Path()));
2352 }
2353
2354 // Destination size will be the next power of two square from the larger width and height...
2355 unsigned ow = width;
2356 unsigned oh = height;
2357 TextureLoader::Validate_Texture_Size(width, height,depth);
2358 if (width != ow || height != oh)
2359 {
2360 WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d\n", Texture->Get_Full_Path(), ow, oh, width, height));
2361 }
2362
2363 Width = width;
2364 Height = height;
2365
2367 {
2368 Format=dest_format;
2369 }
2370 else
2371 {
2373 }
2374
2376 (
2377 Width,
2378 Height,
2379 Format,
2380 Texture->MipLevelCount,
2382 D3DPOOL_MANAGED
2383#else
2384 D3DPOOL_SYSTEMMEM
2385#endif
2386 );
2387
2388 return true;
2389}
2390
2392{
2393 DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction());
2394
2395 // if we can't load from file, indicate rror.
2396 if (!dds_file.Is_Available() || !dds_file.Load())
2397 {
2398 return false;
2399 }
2400
2401 // load cube map faces
2402 for (unsigned int face=0; face<6; face++)
2403 {
2404 unsigned int width = Get_Width();
2405 unsigned int height = Get_Height();
2406
2407 for (unsigned int level=0; level<Get_Mip_Level_Count(); level++)
2408 {
2409 WWASSERT(width && height);
2410
2411 // get cube map surface
2413 (
2414 face,
2415 level,
2416 Get_Format(),
2417 width,
2418 height,
2419 Get_Locked_CubeMap_Surface_Pointer(face,level),
2420 Get_Locked_CubeMap_Surface_Pitch(face,level),
2421 HSVShift
2422 );
2423
2424 width>>=1;
2425 height>>=1;
2426 }
2427 }
2428
2429 return true;
2430}
2431
2432unsigned char* CubeTextureLoadTaskClass::Get_Locked_CubeMap_Surface_Pointer(unsigned int face, unsigned int level)
2433{
2434 WWASSERT(face<6 && level<MipLevelCount);
2435 WWASSERT(LockedCubeSurfacePtr[face][level]);
2436 return LockedCubeSurfacePtr[face][level];
2437}
2438
2439unsigned int CubeTextureLoadTaskClass::Get_Locked_CubeMap_Surface_Pitch(unsigned int face, unsigned int level) const
2440{
2441 WWASSERT(face<6 && level<MipLevelCount);
2442 WWASSERT(LockedCubeSurfacePitch[face][level]);
2443 return LockedCubeSurfacePitch[face][level];
2444}
2445
2446
2447
2448
2449
2450
2451
2452// VolumeTextureLoadTaskClass
2455{
2456 // because texture load tasks are pooled, the constructor and destructor
2457 // don't need to do much. The work of attaching a task to a texture is
2458 // is done by Init() and Deinit().
2459
2460 for (int i = 0; i < MIP_LEVELS_MAX; ++i)
2461 {
2463 LockedSurfacePitch[i] = 0;
2464 LockedSurfaceSlicePitch[i] = 0;
2465 }
2466}
2467
2469{
2470 // detach the task from its texture, and return to free pool.
2471 Deinit();
2472 _VolTexLoadFreeList.Push_Front(this);
2473}
2474
2476{
2477 WWASSERT(tc);
2478
2479 // NOTE: we must be in the main thread to avoid corrupting the texture's refcount.
2481 REF_PTR_SET(Texture, tc);
2482
2483 // Make sure texture has a filename.
2484 WWASSERT(Texture->Get_Full_Path() != "");
2485
2486 Type = type;
2487 Priority = priority;
2488 State = STATE_NONE;
2489
2490 D3DTexture = 0;
2491
2492 VolumeTextureClass* tex=Texture->As_VolumeTextureClass();
2493
2494 if (tex)
2495 {
2496 Format = tex->Get_Texture_Format(); // don't assume format yet KM
2497 }
2498 else
2499 {
2501 }
2502
2503 Width = 0;
2504 Height = 0;
2505 Depth = 0;
2506 MipLevelCount = Texture->MipLevelCount;
2507 Reduction = Texture->Get_Reduction();
2508 HSVShift = Texture->Get_HSV_Shift();
2509
2510
2511 for (int i = 0; i < MIP_LEVELS_MAX; ++i)
2512 {
2514 LockedSurfacePitch[i] = 0;
2515 LockedSurfaceSlicePitch[i] = 0;
2516 }
2517
2518 switch (Type)
2519 {
2520 case TASK_THUMBNAIL:
2521 WWASSERT(Texture->ThumbnailLoadTask == NULL);
2522 Texture->ThumbnailLoadTask = this;
2523 break;
2524
2525 case TASK_LOAD:
2526 WWASSERT(Texture->TextureLoadTask == NULL);
2527 Texture->TextureLoadTask = this;
2528 break;
2529 }
2530}
2531
2533{
2534 for (unsigned int i=0; i<MipLevelCount; i++)
2535 {
2536 D3DLOCKED_BOX locked_box;
2538 (
2539 Peek_D3D_Volume_Texture()->LockBox
2540 (
2541 i,
2542 &locked_box,
2543 NULL,
2544 0
2545 )
2546 );
2547 LockedSurfacePtr[i] = (unsigned char *)locked_box.pBits;
2548 LockedSurfacePitch[i] = locked_box.RowPitch;
2549 LockedSurfaceSlicePitch[i] = locked_box.SlicePitch;
2550 }
2551}
2552
2553
2555{
2556 for (unsigned int i = 0; i < MipLevelCount; ++i)
2557 {
2558 if (LockedSurfacePtr[i])
2559 {
2562 (
2563 Peek_D3D_Volume_Texture()->UnlockBox(i)
2564 );
2565 }
2567 }
2568
2569#ifndef USE_MANAGED_TEXTURES
2570 IDirect3DTexture8* tex = DX8Wrapper::_Create_DX8_Volume_Texture(Width, Height, Depth, Format, Texture->MipLevelCount,D3DPOOL_DEFAULT);
2571 DX8CALL(UpdateTexture(Peek_D3D_Volume_Texture(),tex));
2572 Peek_D3D_Volume_Texture()->Release();
2573 D3DTexture=tex;
2574 WWDEBUG_SAY(("Created non-managed texture (%s)\n",Texture->Get_Full_Path()));
2575#endif
2576
2577}
2578
2579
2580
2582{
2583 unsigned orig_w,orig_h,orig_d,orig_mip_count,reduction;
2584 WW3DFormat orig_format;
2585 if (!Get_Texture_Information
2586 (
2587 Texture->Get_Full_Path(),
2588 reduction,
2589 orig_w,
2590 orig_h,
2591 orig_d,
2592 orig_format,
2593 orig_mip_count,
2594 true
2595 )
2596 )
2597 {
2598 return false;
2599 }
2600
2601 // Destination size will be the next power of two square from the larger width and height...
2602 unsigned int width = orig_w;
2603 unsigned int height = orig_h;
2604 unsigned int depth = orig_d;
2605 TextureLoader::Validate_Texture_Size(width, height, depth);
2606
2607 // If the size doesn't match, try and see if texture reduction would help... (mainly for
2608 // cases where loaded texture is larger than hardware limit)
2609 if (width != orig_w || height != orig_h || depth != orig_d)
2610 {
2611 for (unsigned int i = 1; i < orig_mip_count; ++i)
2612 {
2613 unsigned w=orig_w>>i;
2614 if (w<4) w=4;
2615 unsigned h=orig_h>>i;
2616 if (h<4) h=4;
2617 unsigned d=orig_d>>i;
2618 if (d<1) d=1;
2619 unsigned tmp_w=w;
2620 unsigned tmp_h=h;
2621 unsigned tmp_d=d;
2622
2624
2625 if (w == tmp_w && h == tmp_h && d== tmp_d)
2626 {
2627 Reduction += i;
2628 width = w;
2629 height = h;
2630 depth = d;
2631 break;
2632 }
2633 }
2634 }
2635
2636 Width = width;
2637 Height = height;
2638 Depth = depth;
2639 Format = Get_Valid_Texture_Format(orig_format, Texture->Is_Compression_Allowed());
2640
2641 unsigned int mip_level_count = Get_Mip_Level_Count();
2642
2643 // If texture wants all mip levels, take as many as the file contains (not necessarily all)
2644 // Otherwise take as many mip levels as the texture wants, not to exceed the count in file...
2645 if (!mip_level_count)
2646 {
2647 mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count();
2648 }
2649 else if (mip_level_count > orig_mip_count)
2650 {//dds_file.Get_Mip_Level_Count()) {
2651 mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count();
2652 }
2653
2654 // Once more, verify that the mip level count is correct (in case it was changed here it might not
2655 // match the size...well actually it doesn't have to match but it can't be bigger than the size)
2656 unsigned int max_mip_level_count = 1;
2657 unsigned int w = 4;
2658 unsigned int h = 4;
2659
2660 while (w < Width && h < Height)
2661 {
2662 w += w;
2663 h += h;
2664 max_mip_level_count++;
2665 }
2666 if (mip_level_count > max_mip_level_count)
2667 {
2668 mip_level_count = max_mip_level_count;
2669 }
2670
2672 (
2673 Width,
2674 Height,
2675 Depth,
2676 Format,
2677 (MipCountType)mip_level_count,
2679 D3DPOOL_MANAGED
2680#else
2681 D3DPOOL_SYSTEMMEM
2682#endif
2683 );
2684
2685 MipLevelCount = mip_level_count;
2686 return true;
2687}
2688
2690{
2691 unsigned width,height,depth,orig_mip_count,reduction;
2692 WW3DFormat orig_format;
2693 if (!Get_Texture_Information
2694 (
2695 Texture->Get_Full_Path(),
2696 reduction,
2697 width,
2698 height,
2699 depth,
2700 orig_format,
2701 orig_mip_count,
2702 false
2703 )
2704 )
2705 {
2706 return false;
2707 }
2708
2709 WW3DFormat src_format=orig_format;
2710 WW3DFormat dest_format=src_format;
2711 dest_format=Get_Valid_Texture_Format(dest_format,false); // No compressed destination format if reading from targa...
2712
2713 if ( src_format != WW3D_FORMAT_A8R8G8B8
2714 && src_format != WW3D_FORMAT_R8G8B8
2715 && src_format != WW3D_FORMAT_X8R8G8B8 )
2716 {
2717 WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!\n", Texture->Get_Full_Path()));
2718 }
2719
2720 // Destination size will be the next power of two square from the larger width and height...
2721 unsigned ow = width;
2722 unsigned oh = height;
2723 unsigned od = depth;
2724 TextureLoader::Validate_Texture_Size(width, height, depth);
2725 if (width != ow || height != oh || depth != od)
2726 {
2727 WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d\n", Texture->Get_Full_Path(), ow, oh, width, height));
2728 }
2729
2730 Width = width;
2731 Height = height;
2732 Depth = depth;
2733
2735 {
2736 Format=dest_format;
2737 }
2738 else
2739 {
2741 }
2742
2744 (
2745 Width,
2746 Height,
2747 Depth,
2748 Format,
2749 Texture->MipLevelCount,
2751 D3DPOOL_MANAGED
2752#else
2753 D3DPOOL_SYSTEMMEM
2754#endif
2755 );
2756
2757 return true;
2758}
2759
2761{
2762 DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction());
2763
2764 // if we can't load from file, indicate rror.
2765 if (!dds_file.Is_Available() || !dds_file.Load())
2766 {
2767 return false;
2768 }
2769
2770 // load volume
2771 unsigned int depth=dds_file.Get_Depth(0);
2772 unsigned int width=Get_Width();
2773 unsigned int height=Get_Height();
2774
2775 WWASSERT(width && height && depth);
2776
2777 for (unsigned int level=0; level<Get_Mip_Level_Count(); level++)
2778 {
2779 if (width<1) width=1;
2780 if (height<1) height=1;
2781 if (depth<1) depth=1;
2782
2783 // get volume
2785 (
2786 level,
2787 depth,
2788 Get_Format(),
2789 width,
2790 height,
2791 Get_Locked_Volume_Pointer(level),
2792 Get_Locked_Volume_Row_Pitch(level),
2793 Get_Locked_Volume_Slice_Pitch(level),
2794 HSVShift
2795 );
2796
2797 width>>=1;
2798 height>>=1;
2799 depth>>=1;
2800 }
2801
2802 return true;
2803}
2804
2805unsigned char* VolumeTextureLoadTaskClass::Get_Locked_Volume_Pointer(unsigned int level)
2806{
2807 WWASSERT(level<MipLevelCount);
2808 WWASSERT(LockedSurfacePtr[level]);
2809 return LockedSurfacePtr[level];
2810}
2811
2812unsigned int VolumeTextureLoadTaskClass::Get_Locked_Volume_Row_Pitch(unsigned int level)
2813{
2814 WWASSERT(level<MipLevelCount);
2815 WWASSERT(LockedSurfacePtr[level]);
2816 return LockedSurfacePitch[level];
2817}
2818
2819unsigned int VolumeTextureLoadTaskClass::Get_Locked_Volume_Slice_Pitch(unsigned int level)
2820{
2821 WWASSERT(level<MipLevelCount);
2822 WWASSERT(LockedSurfacePtr[level]);
2823 return LockedSurfaceSlicePitch[level];
2824}
#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
static void Copy_Image_Generate_Mipmap(unsigned width, unsigned height, unsigned char *dest_surface, unsigned dest_pitch, WW3DFormat dest_format, unsigned char *src_surface, unsigned src_pitch, WW3DFormat src_format, unsigned char *mip_surface, unsigned mip_pitch, const Vector3 &hsv_shift=Vector3(0.0f, 0.0f, 0.0f))
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))
virtual void Unlock_Surfaces(void)
virtual bool Load_Compressed_Mipmap(void)
virtual void Deinit(void)
virtual bool Begin_Uncompressed_Load(void)
virtual void Destroy(void)
virtual void Init(TextureBaseClass *tc, TaskType type, PriorityType priority)
virtual bool Begin_Compressed_Load(void)
virtual void Lock_Surfaces(void)
WW3DFormat Get_Format() const
Definition ddsfile.h:218
bool Is_Available() const
Definition ddsfile.h:278
unsigned Get_Height(unsigned level) const
Definition ddsfile.cpp:203
unsigned Get_Mip_Level_Count() const
Definition ddsfile.h:215
bool Load()
Definition ddsfile.cpp:258
unsigned Get_Width(unsigned level) const
Definition ddsfile.cpp:195
unsigned Get_Depth(unsigned level) const
Definition ddsfile.cpp:211
void Copy_Level_To_Surface(unsigned level, IDirect3DSurface8 *d3d_surface, const Vector3 &hsv_shift=Vector3(0.0f, 0.0f, 0.0f))
Definition ddsfile.cpp:343
void Copy_CubeMap_Level_To_Surface(unsigned face, unsigned level, WW3DFormat dest_format, unsigned width, unsigned height, unsigned char *surf, unsigned pitch, const Vector3 &hsv_shift=Vector3(0.0f, 0.0f, 0.0f))
Definition ddsfile.cpp:528
void Copy_Volume_Level_To_Surface(unsigned level, unsigned depth, WW3DFormat dest_format, unsigned width, unsigned height, unsigned char *vol, unsigned row_pitch, unsigned slice_pitch, const Vector3 &hsv_shift=Vector3(0.0f, 0.0f, 0.0f))
Definition ddsfile.cpp:697
D3DCAPS8 const & Get_DX8_Caps() const
Definition dx8caps.h:251
bool Support_DXTC() const
Definition dx8caps.h:216
static IDirect3DTexture8 * _Create_DX8_Texture(unsigned int width, unsigned int height, WW3DFormat format, MipCountType mip_level_count, D3DPOOL pool=D3DPOOL_MANAGED, bool rendertarget=false)
static const DX8Caps * Get_Current_Caps()
Definition dx8wrapper.h:536
static IDirect3DCubeTexture8 * _Create_DX8_Cube_Texture(unsigned int width, unsigned int height, WW3DFormat format, MipCountType mip_level_count, D3DPOOL pool=D3DPOOL_MANAGED, bool rendertarget=false)
static unsigned _Get_Main_Thread_ID()
Definition dx8wrapper.h:427
static IDirect3DSurface8 * _Create_DX8_Surface(unsigned int width, unsigned int height, WW3DFormat format)
static IDirect3DVolumeTexture8 * _Create_DX8_Volume_Texture(unsigned int width, unsigned int height, unsigned int depth, WW3DFormat format, MipCountType mip_level_count, D3DPOOL pool=D3DPOOL_MANAGED)
friend class LockClass
Definition mutex.h:174
static IDirect3DSurface8 * _Create_Missing_Surface()
static IDirect3DTexture8 * _Get_Missing_Texture()
void Push_Front(TextureLoadTaskClass *task)
void Remove(TextureLoadTaskClass *task)
TextureLoadTaskClass * Pop_Front(void)
TextureLoadTaskClass * Pop_Back(void)
void Push_Back(TextureLoadTaskClass *task)
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
IDirect3DBaseTexture8 * Peek_D3D_Base_Texture() const
Returns a pointer to the d3d texture.
Definition texture.cpp:258
virtual TexAssetType Get_Asset_Type() const =0
static void Invalidate_Old_Unused_Textures(unsigned inactive_time_override)
Invalidate old unused textures.
Definition texture.cpp:142
const StringClass & Get_Full_Path(void) const
Definition texture.h:113
const Vector3 & Get_HSV_Shift()
Definition texture.h:178
bool Is_Initialized() const
Definition texture.h:145
virtual void Apply_New_Surface(IDirect3DBaseTexture8 *tex, bool initialized, bool disable_auto_invalidation=false)=0
WW3DFormat Get_Texture_Format() const
Definition texture.h:338
IDirect3DTexture8 * Peek_D3D_Texture(void)
unsigned int Get_Reduction(void) const
TextureBaseClass * Texture
WW3DFormat Get_Format(void) const
virtual void Deinit(void)
unsigned int Get_Height(void) const
virtual bool Load_Uncompressed_Mipmap(void)
virtual bool Load_Compressed_Mipmap(void)
unsigned int Get_Locked_Surface_Pitch(unsigned int level) const
unsigned int LockedSurfacePitch[MIP_LEVELS_MAX]
static TextureLoadTaskClass * Create(TextureBaseClass *tc, TaskType type, PriorityType priority)
virtual void Init(TextureBaseClass *tc, TaskType type, PriorityType priority)
virtual bool Begin_Compressed_Load(void)
virtual void Destroy(void)
unsigned char * LockedSurfacePtr[MIP_LEVELS_MAX]
StateType Get_State(void) const
TaskType Get_Type(void) const
virtual bool Begin_Uncompressed_Load(void)
virtual void Lock_Surfaces(void)
static void Delete_Free_Pool(void)
unsigned int MipLevelCount
PriorityType Get_Priority(void) const
void Apply(bool initialize)
unsigned int Get_Mip_Level_Count(void) const
unsigned char * Get_Locked_Surface_Ptr(unsigned int level)
virtual void Unlock_Surfaces(void)
unsigned int Get_Width(void) const
TextureBaseClass * Peek_Texture(void)
void Set_State(StateType s)
IDirect3DBaseTexture8 * D3DTexture
void Set_Priority(PriorityType p)
TextureLoadTaskClass * Pop_Back(void)
bool Is_Empty(void) const
void Push_Back(TextureLoadTaskClass *task)
void Push_Front(TextureLoadTaskClass *task)
TextureLoadTaskClass * Pop_Front(void)
void Remove(TextureLoadTaskClass *task)
TextureLoadTaskListClass * Get_List(void)
TextureLoadTaskListNodeClass * Prev
TextureLoadTaskListClass * List
TextureLoadTaskListNodeClass * Next
static void Continue_Texture_Load()
static void Validate_Texture_Size(unsigned &width, unsigned &height, unsigned &depth)
static void Request_Background_Loading(TextureBaseClass *tc)
static void Flush_Pending_Load_Tasks(void)
static void Init(void)
static void Suspend_Texture_Load()
static void Request_Thumbnail(TextureBaseClass *tc)
static void Update(void(*network_callback)(void)=NULL)
static IDirect3DTexture8 * Load_Thumbnail(const StringClass &filename, const Vector3 &hsv_shift)
static bool Is_DX8_Thread(void)
static void Deinit(void)
static void Request_Foreground_Loading(TextureBaseClass *tc)
static IDirect3DSurface8 * Load_Surface_Immediate(const StringClass &filename, WW3DFormat surface_format, bool allow_compression)
ThreadClass(const char *name=NULL, ExceptionHandlerType exception_handler=NULL)
Definition thread.cpp:32
static void Switch_Thread()
Definition thread.cpp:130
static unsigned _Get_Current_Thread_ID()
Definition thread.cpp:142
volatile bool running
Definition thread.h:89
WW3DFormat Get_Original_Texture_Format() const
WW3DFormat Get_Format()
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
static ThumbnailClass * Peek_Thumbnail_Instance_From_Any_Manager(const StringClass &name)
virtual void Unlock_Surfaces(void)
virtual bool Load_Compressed_Mipmap(void)
virtual void Lock_Surfaces(void)
virtual void Init(TextureBaseClass *tc, TaskType type, PriorityType priority)
virtual bool Begin_Compressed_Load(void)
virtual bool Begin_Uncompressed_Load(void)
static int Get_Texture_Reduction(void)
Definition ww3d.cpp:1794
static int Get_Texture_Min_Dimension(void)
Definition ww3d.cpp:1811
#define DX8CALL(x)
Definition dx8wrapper.h:138
WWINLINE void DX8_ErrorCode(unsigned res)
Definition dx8wrapper.h:125
#define REF_PTR_RELEASE(x)
Definition refcount.h:80
#define REF_PTR_SET(dst, src)
Definition refcount.h:79
MipCountType
@ MIP_LEVELS_ALL
@ MIP_LEVELS_MAX
@ MIP_LEVELS_1
#define UPDATE_NETWORK
#define USE_MANAGED_TEXTURES
IDirect3DTexture8 * Load_Compressed_Texture(const StringClass &filename, unsigned reduction_factor, MipCountType mip_level_count, WW3DFormat dest_format)
struct Update Update
Definition wolapi.h:617
unsigned Get_Bytes_Per_Pixel(WW3DFormat format)
WW3DFormat Get_Valid_Texture_Format(WW3DFormat format, bool is_compression_allowed)
void Get_WW3D_Format(WW3DFormat &dest_format, WW3DFormat &src_format, unsigned &src_bpp, const Targa &targa)
WW3DFormat
Definition ww3dformat.h:75
@ WW3D_FORMAT_R5G6B5
Definition ww3dformat.h:80
@ WW3D_FORMAT_DXT3
Definition ww3dformat.h:98
@ WW3D_FORMAT_L8
Definition ww3dformat.h:90
@ WW3D_FORMAT_DXT2
Definition ww3dformat.h:97
@ WW3D_FORMAT_P8
Definition ww3dformat.h:89
@ WW3D_FORMAT_X8R8G8B8
Definition ww3dformat.h:79
@ WW3D_FORMAT_DXT5
Definition ww3dformat.h:100
@ WW3D_FORMAT_UNKNOWN
Definition ww3dformat.h:76
@ WW3D_FORMAT_DXT4
Definition ww3dformat.h:99
@ WW3D_FORMAT_R8G8B8
Definition ww3dformat.h:77
@ WW3D_FORMAT_DXT1
Definition ww3dformat.h:96
@ WW3D_FORMAT_A4R4G4B4
Definition ww3dformat.h:83
@ WW3D_FORMAT_A8R8G8B8
Definition ww3dformat.h:78
@ WW3D_FORMAT_A1R5G5B5
Definition ww3dformat.h:82
#define WWASSERT_PRINT(expr, string)
Definition wwdebug.h:135
#define WWDEBUG_SAY(x)
Definition wwdebug.h:114
@ MEM_TEXTURE
Definition wwmemlog.h:61
#define WWMEMLOG(category)
Definition wwmemlog.h:183
#define WWPROFILE(name)
Definition wwprofile.h:270