]> icculus.org git repositories - btb/d2x.git/blob - arch/win32/d3dframe/d3dtextr.cpp
fixed a major memory leak and removed a bit of redundancy (d1x r1.5)
[btb/d2x.git] / arch / win32 / d3dframe / d3dtextr.cpp
1 //-----------------------------------------------------------------------------
2 // File: D3DTextr.cpp
3 //
4 // Desc: This file contains the member functions for the
5 //       CD3DTextureEngine class. The class is responsible for loading and
6 //       creating textures from files, as well as retrieving the
7 //       corresponding ptrs and surfaces for the textures, given a
8 //       texture's name.
9 //
10 //
11 // Copyright (c) 1996-1998 Microsoft Corporation. All rights reserved
12 //-----------------------------------------------------------------------------
13
14 #include <tchar.h>
15 #include <stdio.h>
16 #include "D3DTextr.h"
17 #include "D3DUtil.h"
18
19
20
21 //-----------------------------------------------------------------------------
22 // Name: TextureContainer
23 // Desc: Linked list tructure to hold info per texture
24 //-----------------------------------------------------------------------------
25 struct TextureContainer
26 {
27     HBITMAP              hbmBitmap;      // Bitmap containing texture image
28     LPDIRECTDRAWSURFACE4 pddsSurface;    // Surface of the texture
29     LPDIRECT3DTEXTURE2   ptexTexture;    // Direct3D texture for the texture
30     DWORD                dwStage;        // Texture stage (for multi-textures)
31     TCHAR                strName[80];    // Filename of assoc'd bitmap
32         BOOL                 bHasAlpha;
33         DWORD                dwFlags;
34         
35         BYTE*                pSurfaceBits[10];
36         DDSURFACEDESC2       ddsd;
37     
38         TextureContainer     *pPrev, *pNext; // Ptr to next texture in linked list
39
40     ~TextureContainer();
41 };
42
43
44
45
46 //-----------------------------------------------------------------------------
47 // Macros, function prototypes and static variable
48 //-----------------------------------------------------------------------------
49 #define FOREACHTEXTURE(ptc) for( TextureContainer* ptc=g_ptcTextureList; \
50                             NULL!=ptc; ptc=ptc->pNext )
51 inline BOOL FileExists( TCHAR* n )
52 { FILE* fp=_tfopen(n,TEXT("rb")); return fp?(0==fclose(fp)):FALSE; }
53
54 static TextureContainer* g_ptcTextureList = NULL;     // Textures list
55 static TCHAR  g_strTexturePath[512] = TEXT("MEDIA\\"); // Path for files
56 static TCHAR* g_strRegValueName     = TEXT("DX6SDK Samples Path");
57
58
59
60
61 struct TEXTURESEARCHINFO
62 {
63         DWORD dwDesiredBPP; // Input for texture format search
64         BOOL  bUseAlpha;
65         BOOL  bUsePalette;
66         BOOL  bUseFourCC;
67         BOOL  bFoundGoodFormat;
68
69         DDPIXELFORMAT* pddpf; // Result of texture format search
70 };
71
72
73
74
75 //-----------------------------------------------------------------------------
76 // Name: TextureSearchCallback()
77 // Desc: Enumeration callback routine to find a best-matching texture format. 
78 //       The param data is the DDPIXELFORMAT of the best-so-far matching
79 //       texture. Note: the desired BPP is passed in the dwSize field, and the
80 //       default BPP is passed in the dwFlags field.
81 //-----------------------------------------------------------------------------
82 static HRESULT CALLBACK TextureSearchCallback( DDPIXELFORMAT* pddpf,
83                                                                                            VOID* param )
84 {
85     if( NULL==pddpf || NULL==param )
86         return DDENUMRET_OK;
87
88         TEXTURESEARCHINFO* ptsi = (TEXTURESEARCHINFO*)param;
89
90     // Skip any funky modes
91     if( pddpf->dwFlags & (DDPF_LUMINANCE|DDPF_BUMPLUMINANCE|DDPF_BUMPDUDV) )
92         return DDENUMRET_OK;
93
94         // Check for palettized formats
95         if( ptsi->bUsePalette )
96         {
97                 if( !( pddpf->dwFlags & DDPF_PALETTEINDEXED8 ) )
98                         return DDENUMRET_OK;
99
100                 // Accept the first 8-bit palettized format we get
101         memcpy( ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT) );
102                 ptsi->bFoundGoodFormat = TRUE;
103         return DDENUMRET_CANCEL;
104     }
105
106         // Else, skip any paletized formats (all modes under 16bpp)
107         if( pddpf->dwRGBBitCount < 16 )
108                 return DDENUMRET_OK;
109
110         // Check for FourCC formats
111     if( ptsi->bUseFourCC )
112         {
113                 if( pddpf->dwFourCC == 0 )
114                     return DDENUMRET_OK;
115
116                 return DDENUMRET_CANCEL;
117         }
118
119         // Else, skip any FourCC formats
120         if( pddpf->dwFourCC != 0 )
121                 return DDENUMRET_OK;
122
123         // Make sure current alpha format agrees with requested format type
124         if( (ptsi->bUseAlpha==TRUE) && !(pddpf->dwFlags&DDPF_ALPHAPIXELS) )
125                 return DDENUMRET_OK;
126         if( (ptsi->bUseAlpha==FALSE) && (pddpf->dwFlags&DDPF_ALPHAPIXELS) )
127                 return DDENUMRET_OK;
128
129     // Check if we found a good match
130     if( pddpf->dwRGBBitCount == ptsi->dwDesiredBPP )
131     {
132         memcpy( ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT) );
133                 ptsi->bFoundGoodFormat = TRUE;
134         return DDENUMRET_CANCEL;
135     }
136
137     return DDENUMRET_OK;
138 }
139
140
141
142
143 //-----------------------------------------------------------------------------
144 // Name: ~TextureContainer()
145 // Desc: Destructs the contents of the texture container
146 //-----------------------------------------------------------------------------
147 TextureContainer::~TextureContainer()
148 {
149     SAFE_DELETE( pNext );
150     SAFE_RELEASE( ptexTexture );
151     SAFE_RELEASE( pddsSurface );
152     DeleteObject( hbmBitmap );
153 }
154
155
156
157
158 //-----------------------------------------------------------------------------
159 // Name: CD3DStaticTextureEngine
160 // Desc: Class used to automatically construct and destruct the static
161 //       texture engine class.
162 //-----------------------------------------------------------------------------
163 class CD3DTextureEngine
164 {
165 public:
166     CD3DTextureEngine();
167     ~CD3DTextureEngine();
168 } g_StaticTextureEngine;
169
170
171
172
173 //-----------------------------------------------------------------------------
174 // Name: CD3DTextureEngine()
175 // Desc: Constructs the texture engine. Creates a DDraw object
176 //-----------------------------------------------------------------------------
177 CD3DTextureEngine::CD3DTextureEngine()
178 {
179 }
180
181
182
183
184 //-----------------------------------------------------------------------------
185 // Name: ~CD3DTextureEngine()
186 // Desc: Deletes the internal list of textures
187 //-----------------------------------------------------------------------------
188 CD3DTextureEngine::~CD3DTextureEngine()
189 {
190     // Delete the list of textures
191     SAFE_DELETE( g_ptcTextureList );
192 }
193
194
195
196
197 //-----------------------------------------------------------------------------
198 // Name: FindTexture()
199 // Desc: Searches the internal list of textures for a texture specified by
200 //       its name. Returns the structure associated with that texture.
201 //-----------------------------------------------------------------------------
202 static TextureContainer* FindTexture( TCHAR* strTextureName )
203 {
204     FOREACHTEXTURE( ptcTexture )
205     {
206         if( !lstrcmpi( strTextureName, ptcTexture->strName ) )
207             return ptcTexture;
208     }
209
210     return NULL;
211 }
212
213
214
215
216 //-----------------------------------------------------------------------------
217 // Name: FindTextureFile()
218 // Desc: Looks for the specified file in the current directory, in the path
219 //       specified in the environment variables, or in the path specified in
220 //       the registry. After finding it, the function returns the full path.
221 //-----------------------------------------------------------------------------
222 static HRESULT FindTextureFile( TCHAR* strFilename, TCHAR* strTexturePath,
223                          TCHAR* strFullPath )
224 {
225     // First, check the current directory
226     _tcscpy( strFullPath, strFilename );
227     if( FileExists( strFullPath ) )
228         return DD_OK;
229
230     // Next, check to see if an environment variable specifies the path
231     TCHAR* strPath = _tgetenv( TEXT("D3DPATH") );
232     if( NULL != strPath )
233     {
234         _stprintf( strFullPath, TEXT("%s\\%s"), strPath, strFilename );
235         if( FileExists( strFullPath ) )
236             return DD_OK;
237     }
238
239     // Finally, check the system registry for a path
240     HKEY key;
241     LONG result = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
242                                 TEXT("Software\\Microsoft\\DirectX"),
243                                 0, KEY_READ, &key );
244     if( ERROR_SUCCESS == result )
245     {
246         TCHAR  strPath[512];
247         DWORD type, size = 512;
248         result = RegQueryValueEx( key, g_strRegValueName, NULL, &type,
249                                   (BYTE*)strPath, &size );
250
251         RegCloseKey( key );
252
253         if( ERROR_SUCCESS == result )
254         {
255             _stprintf( strFullPath, TEXT("%s\\D3DIM\\Media\\%s"), strPath,
256                        strFilename );
257             if( FileExists( strFullPath ) )
258                 return DD_OK;
259
260             _stprintf( strFullPath, TEXT("%s\\%s%s"), strPath,
261                        strTexturePath, strFilename );
262             if( FileExists( strFullPath ) )
263                 return DD_OK;
264         }
265     }
266
267     return DDERR_NOTFOUND;
268 }
269
270
271
272
273 //-----------------------------------------------------------------------------
274 // Name: LoadTextureImage()
275 // Desc: Loads a texture map file into a BITMAP surface.
276 //-----------------------------------------------------------------------------
277 static HRESULT LoadTextureImage( TextureContainer* ptcTexture )
278 {
279     TCHAR* strFilename = ptcTexture->strName;
280     TCHAR* strExtension;
281     TCHAR  strPathname[256];
282
283     // Get the filename extension
284     if( NULL == ( strExtension = _tcsrchr( strFilename, TEXT('.') ) ) )
285         return DDERR_UNSUPPORTED;
286
287     // Check the executable's resource. If it's there, we're done!
288     if( NULL != ( ptcTexture->hbmBitmap = (HBITMAP)LoadImage(
289                                                     GetModuleHandle(NULL),
290                                             strFilename, IMAGE_BITMAP,
291                                             0, 0, LR_CREATEDIBSECTION) ) )
292         return S_OK;
293
294     // Check the current path and system registry path for the file
295     if( FAILED( FindTextureFile( strFilename, g_strTexturePath, strPathname ) ) )
296         return DDERR_NOTFOUND;
297
298     if( !lstrcmpi( strExtension, ".bmp" ) )
299     {
300         // Try to load the bitmap as a resource.
301         ptcTexture->hbmBitmap = (HBITMAP)LoadImage( GetModuleHandle(NULL),
302                                                     strPathname, IMAGE_BITMAP, 0, 0, 
303                                                                         LR_CREATEDIBSECTION );
304
305         // If the bitmap wasn't a resource, try it as a file.
306         if( NULL == ptcTexture->hbmBitmap )
307             ptcTexture->hbmBitmap = (HBITMAP)LoadImage( NULL, strPathname,
308                                                     IMAGE_BITMAP, 0, 0, 
309                                                                                 LR_LOADFROMFILE|LR_CREATEDIBSECTION );
310
311         return (ptcTexture->hbmBitmap) ? DD_OK : DDERR_NOTFOUND;
312     }
313
314         // Can check for other file formats here
315
316     return DDERR_UNSUPPORTED;
317 }
318
319
320
321
322 //-----------------------------------------------------------------------------
323 // Name: CopyBitmapToSurface()
324 // Desc: Copies the image of a bitmap into a surface
325 //-----------------------------------------------------------------------------
326 static HRESULT CopyBitmapToSurface( LPDIRECTDRAWSURFACE4 pddsTarget,
327                                     HBITMAP hbmBitmap, DWORD dwFlags )
328 {
329     // Get a DDraw object to create a temporary surface
330     LPDIRECTDRAW4 pDD;
331     pddsTarget->GetDDInterface( (VOID**)&pDD );
332     pDD->Release();
333
334     // Get the bitmap structure (to extract width, height, and bpp)
335     BITMAP bm;
336     GetObject( hbmBitmap, sizeof(BITMAP), &bm );
337
338     // Setup the new surface desc
339     DDSURFACEDESC2 ddsd;
340     D3DUtil_InitSurfaceDesc( ddsd );
341     pddsTarget->GetSurfaceDesc( &ddsd );
342     ddsd.dwFlags          = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|
343                                     DDSD_TEXTURESTAGE;
344     ddsd.ddsCaps.dwCaps   = DDSCAPS_TEXTURE|DDSCAPS_SYSTEMMEMORY;
345     ddsd.ddsCaps.dwCaps2  = 0L;
346     ddsd.dwWidth          = bm.bmWidth;
347     ddsd.dwHeight         = bm.bmHeight;
348
349     // Create a new surface for the texture
350     LPDIRECTDRAWSURFACE4 pddsTempSurface;
351         HRESULT hr;
352     if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTempSurface, NULL ) ) )
353         return NULL;
354
355     // Get a DC for the bitmap
356     HDC hdcBitmap = CreateCompatibleDC( NULL );
357     if( NULL == hdcBitmap )
358     {
359         pddsTempSurface->Release();
360         return NULL;
361     }
362     SelectObject( hdcBitmap, hbmBitmap );
363
364     // Handle palettized textures. Need to attach a palette
365     if( ddsd.ddpfPixelFormat.dwRGBBitCount == 8 )
366     {
367         // Create the color table and parse in the palette
368         DWORD pe[256];
369         WORD  wNumColors = GetDIBColorTable( hdcBitmap, 0, 256,
370                                              (RGBQUAD*)pe );
371         for( WORD i=0; i<wNumColors; i++ )
372         {
373             pe[i] = 0xff000000 + RGB( GetBValue(pe[i]), GetGValue(pe[i]),
374                                       GetRValue(pe[i]) );
375
376                         // Set alpha for transparent pixels
377                         if( dwFlags & D3DTEXTR_TRANSPARENTBLACK )
378             {
379                 if( (pe[i]&0x00ffffff) == 0x00000000 )
380                     pe[i] &= 0x00ffffff;
381             }
382             else if( dwFlags & D3DTEXTR_TRANSPARENTWHITE )
383             {
384                 if( (pe[i]&0x00ffffff) == 0x00ffffff )
385                     pe[i] &= 0x00ffffff;
386             }
387                 }
388         // Create & attach a palette with the bitmap's colors
389         LPDIRECTDRAWPALETTE  pPalette;
390                 if( dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) )
391             pDD->CreatePalette( DDPCAPS_8BIT|DDPCAPS_ALPHA, (PALETTEENTRY*)pe, &pPalette, NULL );
392         else
393             pDD->CreatePalette( DDPCAPS_8BIT, (PALETTEENTRY*)pe, &pPalette, NULL );
394         pddsTempSurface->SetPalette( pPalette );
395         pddsTarget->SetPalette( pPalette );
396         SAFE_RELEASE( pPalette );
397     }
398
399     // Copy the bitmap image to the surface.
400     HDC hdcSurface;
401     if( SUCCEEDED( pddsTempSurface->GetDC( &hdcSurface ) ) )
402     {
403         BitBlt( hdcSurface, 0, 0, bm.bmWidth, bm.bmHeight, hdcBitmap, 0, 0,
404                 SRCCOPY );
405         pddsTempSurface->ReleaseDC( hdcSurface );
406     }
407     DeleteDC( hdcBitmap );
408
409     // Copy the temp surface to the real texture surface
410     pddsTarget->Blt( NULL, pddsTempSurface, NULL, DDBLT_WAIT, NULL );
411
412     if( ddsd.ddpfPixelFormat.dwRGBBitCount == 8 )
413         {
414         LPDIRECTDRAWPALETTE  pPalette;
415                 DWORD pe[256];
416         pddsTempSurface->GetPalette( &pPalette );
417                 pPalette->GetEntries( 0, 0, 256, (PALETTEENTRY*)&pe );
418                 pPalette->Release();
419
420                 pddsTarget->GetPalette( &pPalette );
421                 pPalette->GetEntries( 0, 0, 256, (PALETTEENTRY*)&pe );
422                 pPalette->Release();
423         }
424
425     pddsTempSurface->Release();
426
427         // For textures with real alpha (not palettized), set transparent bits
428     if( ddsd.ddpfPixelFormat.dwRGBAlphaBitMask )
429         {
430                 if( dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) )
431                 {
432                         // Lock the texture surface
433                         DDSURFACEDESC2 ddsd;
434                         D3DUtil_InitSurfaceDesc( ddsd );
435                         while( pddsTarget->Lock( NULL, &ddsd, 0, NULL ) ==
436                                    DDERR_WASSTILLDRAWING );
437                          
438                     DWORD dwAlphaMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask;
439                         DWORD dwRGBMask   = ( ddsd.ddpfPixelFormat.dwRBitMask |
440                                                               ddsd.ddpfPixelFormat.dwGBitMask |
441                                                               ddsd.ddpfPixelFormat.dwBBitMask );
442                         DWORD dwColorkey  = 0x00000000; // Colorkey on black
443                         if( dwFlags & D3DTEXTR_TRANSPARENTWHITE ) 
444                                 dwColorkey = dwRGBMask;     // Colorkey on white
445
446                         // Add an opaque alpha value to each non-colorkeyed pixel
447                         for( DWORD y=0; y<ddsd.dwHeight; y++ )
448                         {
449                                 WORD*  p16 =  (WORD*)((BYTE*)ddsd.lpSurface + y*ddsd.lPitch);
450                                 DWORD* p32 = (DWORD*)((BYTE*)ddsd.lpSurface + y*ddsd.lPitch);
451         
452                                 for( DWORD x=0; x<ddsd.dwWidth; x++ )
453                                 {
454                                         if( ddsd.ddpfPixelFormat.dwRGBBitCount == 16 )
455                                         {
456                                                 if( ( *p16 &= dwRGBMask ) != dwColorkey )
457                                                         *p16 |= dwAlphaMask;
458                                                 p16++;
459                                         }
460                                         if( ddsd.ddpfPixelFormat.dwRGBBitCount == 32 )
461                                         {
462                                                 if( ( *p32 &= dwRGBMask ) != dwColorkey )
463                                                         *p32 |= dwAlphaMask;
464                                                 p32++;
465                                         }
466                                 }
467                         }
468                         pddsTarget->Unlock( NULL );
469                 }
470         }
471
472     return S_OK;;
473 }
474
475
476
477
478 //-----------------------------------------------------------------------------
479 // Name: D3DTextr_GetSurface()
480 // Desc: Returns a pointer to a d3dSurface from the name of the texture
481 //-----------------------------------------------------------------------------
482 LPDIRECTDRAWSURFACE4 D3DTextr_GetSurface( TCHAR* strName )
483 {
484     TextureContainer* ptcTexture = FindTexture( strName );
485
486     return ptcTexture ? ptcTexture->pddsSurface : NULL;
487 }
488
489
490
491
492 //-----------------------------------------------------------------------------
493 // Name: D3DTextr_GetTexture()
494 // Desc: Returns a pointer to a d3dTexture from the name of the texture
495 //-----------------------------------------------------------------------------
496 LPDIRECT3DTEXTURE2 D3DTextr_GetTexture( TCHAR* strName )
497 {
498     TextureContainer* ptcTexture = FindTexture( strName );
499
500     return ptcTexture ? ptcTexture->ptexTexture: NULL;
501 }
502
503
504
505
506 //-----------------------------------------------------------------------------
507 // Name: D3DTextr_SetTexturePath()
508 // Desc: Enumeration callback routine to find a best-matching texture format.
509 //-----------------------------------------------------------------------------
510 VOID D3DTextr_SetTexturePath( TCHAR* strTexturePath )
511 {
512     if( NULL==strTexturePath )
513         strTexturePath = TEXT("");
514     _tcscpy( g_strTexturePath, strTexturePath );
515 }
516
517
518
519
520 //-----------------------------------------------------------------------------
521 // Name: D3DTextr_CreateTexture()
522 // Desc: Is passed a filename and creates a local Bitmap from that file.
523 //       The texture can not be used until it is restored, however.
524 //-----------------------------------------------------------------------------
525 HRESULT D3DTextr_CreateTexture( TCHAR* strName, DWORD dwStage, DWORD dwFlags )
526 {
527     // Check first to see if the texture is already loaded
528     if( NULL != FindTexture( strName ) )
529         return S_OK;
530
531     // Allocate and add the texture to the linked list of textures;
532     TextureContainer* ptcTexture = new TextureContainer();
533     if( NULL == ptcTexture )
534         return E_OUTOFMEMORY;
535     ZeroMemory( ptcTexture, sizeof(TextureContainer) );
536     lstrcpy( ptcTexture->strName, strName );
537     ptcTexture->dwStage = dwStage;
538     ptcTexture->dwFlags = dwFlags;
539
540     // Create a bitmap and load the texture file into it,
541     if( FAILED( LoadTextureImage( ptcTexture ) ) )
542         {
543                 delete ptcTexture;
544         return E_FAIL;
545         }
546
547     // Add the texture to the global linked list
548     if( g_ptcTextureList )
549         g_ptcTextureList->pPrev = ptcTexture;
550     ptcTexture->pNext = g_ptcTextureList;
551     g_ptcTextureList  = ptcTexture;
552
553     return S_OK;
554 }
555
556
557
558
559 //-----------------------------------------------------------------------------
560 // Name: RestoreFromBitmap()
561 // Desc: Invalidates the current texture objects and rebuilds new ones
562 //       using the new device.
563 //-----------------------------------------------------------------------------
564 static HRESULT RestoreFromBitmap( TextureContainer* ptcTexture, 
565                                                           LPDIRECT3DDEVICE3 pd3dDevice )
566 {
567     // Get the DirectDraw interface for creating surfaces
568     LPDIRECTDRAW4 pDD;
569     if( NULL == ( pDD = D3DUtil_GetDirectDrawFromDevice( pd3dDevice ) ) )
570         return E_FAIL;
571     pDD->Release();
572
573     // Get the device caps
574     D3DDEVICEDESC ddHwDesc, ddSwDesc;
575     DWORD         dwDeviceCaps;
576     ddHwDesc.dwSize = sizeof(D3DDEVICEDESC);
577     ddSwDesc.dwSize = sizeof(D3DDEVICEDESC);
578     if( FAILED( pd3dDevice->GetCaps( &ddHwDesc, &ddSwDesc ) ) )
579         return E_FAIL;
580     if( ddHwDesc.dwFlags ) dwDeviceCaps = ddHwDesc.dpcTriCaps.dwTextureCaps;
581     else                   dwDeviceCaps = ddSwDesc.dpcTriCaps.dwTextureCaps;
582
583         // Get the bitmap structure (to extract width, height, and bpp)
584     BITMAP bm;
585     HBITMAP hbmBitmap = ptcTexture->hbmBitmap;
586     GetObject( hbmBitmap, sizeof(BITMAP), &bm );
587     DWORD dwWidth  = (DWORD)bm.bmWidth;
588     DWORD dwHeight = (DWORD)bm.bmHeight;
589
590     // Setup the new surface desc
591     DDSURFACEDESC2 ddsd;
592     D3DUtil_InitSurfaceDesc( ddsd );
593     ddsd.dwFlags         = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|
594                            DDSD_PIXELFORMAT|DDSD_TEXTURESTAGE;
595     ddsd.ddsCaps.dwCaps  = DDSCAPS_TEXTURE;
596     ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
597     ddsd.dwTextureStage  = ptcTexture->dwStage;
598     ddsd.dwWidth         = dwWidth;
599     ddsd.dwHeight        = dwHeight;
600
601     // Adjust width and height, if the driver requires it
602     if( dwDeviceCaps & D3DPTEXTURECAPS_POW2 )
603     {
604         for( ddsd.dwWidth=1;  dwWidth>ddsd.dwWidth;   ddsd.dwWidth<<=1 );
605         for( ddsd.dwHeight=1; dwHeight>ddsd.dwHeight; ddsd.dwHeight<<=1 );
606     }
607     if( dwDeviceCaps & D3DPTEXTURECAPS_SQUAREONLY )
608     {
609         if( ddsd.dwWidth > ddsd.dwHeight ) ddsd.dwHeight = ddsd.dwWidth;
610         else                               ddsd.dwWidth  = ddsd.dwHeight;
611     }
612
613         BOOL bUsePalette = ( bm.bmBitsPixel <= 8 );
614         BOOL bUseAlpha   = FALSE;
615
616         if( ptcTexture->bHasAlpha )
617                 bUseAlpha = TRUE;
618         
619         if( ptcTexture->dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) )
620         {
621                 if( bUsePalette )
622                 {
623                         if( dwDeviceCaps & D3DPTEXTURECAPS_ALPHAPALETTE )
624                         {
625                                 bUseAlpha   = TRUE;
626                                 bUsePalette = TRUE;
627                         }
628                         else
629                         {
630                                 bUseAlpha   = TRUE;
631                                 bUsePalette = FALSE;
632                         }
633                 }
634         }
635
636         // Setup the structure to be used for texture enumration.
637         TEXTURESEARCHINFO tsi;
638         tsi.pddpf            = &ddsd.ddpfPixelFormat;
639         tsi.bUseAlpha        = bUseAlpha;
640         tsi.bUsePalette      = bUsePalette;
641         tsi.bUseFourCC       = ( ddsd.ddpfPixelFormat.dwFlags & DDPF_FOURCC );
642         tsi.dwDesiredBPP     = 16;
643         tsi.bFoundGoodFormat = FALSE;
644         if( ptcTexture->dwFlags & D3DTEXTR_32BITSPERPIXEL )
645                 tsi.dwDesiredBPP = 32;
646
647         // Enumerate the texture formats, and find the closest device-supported
648         // texture pixel format
649     pd3dDevice->EnumTextureFormats( TextureSearchCallback, &tsi );
650
651         // If a palettized format was requested, but not found, default to a
652         // 16-bit texture format
653         if( FALSE == tsi.bFoundGoodFormat && bUsePalette )
654         {
655                 tsi.bUsePalette  = FALSE;
656                 tsi.dwDesiredBPP = 16;
657             pd3dDevice->EnumTextureFormats( TextureSearchCallback, &tsi );
658                 if( FALSE == tsi.bFoundGoodFormat )
659                         return E_FAIL;
660         }
661         
662     // Create a new surface for the texture
663     HRESULT hr;
664     if( FAILED( hr = pDD->CreateSurface( &ddsd, &ptcTexture->pddsSurface, NULL ) ) )
665         return E_FAIL;
666
667     // Create the texture
668     if( FAILED( ptcTexture->pddsSurface->QueryInterface( IID_IDirect3DTexture2,
669                                          (VOID**)&ptcTexture->ptexTexture ) ) )
670         return E_FAIL;
671
672
673         // Copy the bitmap to the texture surface
674     return CopyBitmapToSurface( ptcTexture->pddsSurface, hbmBitmap,
675                                         ptcTexture->dwFlags );
676
677 }
678
679
680
681
682 //-----------------------------------------------------------------------------
683 // Name: D3DTextr_Restore()
684 // Desc: Invalidates the current texture objects and rebuilds new ones
685 //       using the new device.
686 //-----------------------------------------------------------------------------
687 HRESULT D3DTextr_Restore( TCHAR* strName, LPDIRECT3DDEVICE3 pd3dDevice )
688 {
689     // Check params
690     if( NULL == pd3dDevice )
691         return DDERR_INVALIDPARAMS;
692
693     TextureContainer* ptcTexture = FindTexture( strName );
694     if( NULL == ptcTexture )
695         return DDERR_NOTFOUND;
696
697     // Release any previously created objects
698     SAFE_RELEASE( ptcTexture->ptexTexture );
699     SAFE_RELEASE( ptcTexture->pddsSurface );
700
701         // Restore the texture surface from the bitmap image. At this point, code
702         // can be added to handle other texture formats, such as those created from
703         // .dds files, .jpg files, or whatever else.
704         return RestoreFromBitmap( ptcTexture, pd3dDevice );
705 }       
706         
707
708
709
710 //-----------------------------------------------------------------------------
711 // Name: D3DTextr_RestoreAllTextures()
712 // Desc: This function is called when a mode is changed. It updates all
713 //       texture objects to be valid with the new device.
714 //-----------------------------------------------------------------------------
715 HRESULT D3DTextr_RestoreAllTextures( LPDIRECT3DDEVICE3 pd3dDevice )
716 {
717     FOREACHTEXTURE( ptcTexture )
718     {
719         D3DTextr_Restore( ptcTexture->strName, pd3dDevice );
720     }
721
722     return DD_OK;
723 }
724
725
726
727
728 //-----------------------------------------------------------------------------
729 // Name: D3DTextr_Invalidate()
730 // Desc: Used to bump a texture out of (video) memory, this function
731 //       actually destroys the d3dtexture and ddsurface of the texture
732 //-----------------------------------------------------------------------------
733 HRESULT D3DTextr_Invalidate( TCHAR* strName )
734 {
735     TextureContainer* ptcTexture = FindTexture( strName );
736     if( NULL == ptcTexture )
737         return DDERR_NOTFOUND;
738
739     SAFE_RELEASE( ptcTexture->ptexTexture );
740     SAFE_RELEASE( ptcTexture->pddsSurface );
741
742     return DD_OK;
743 }
744
745
746
747
748 //-----------------------------------------------------------------------------
749 // Name: D3DTextr_InvalidateAllTextures()
750 // Desc: This function is called when a mode is changed. It invalidates
751 //       all texture objects so their device can be safely released.
752 //-----------------------------------------------------------------------------
753 HRESULT D3DTextr_InvalidateAllTextures()
754 {
755     FOREACHTEXTURE( ptcTexture )
756     {
757         SAFE_RELEASE( ptcTexture->ptexTexture );
758         SAFE_RELEASE( ptcTexture->pddsSurface );
759     }
760
761     return DD_OK;
762 }
763
764
765
766
767 //-----------------------------------------------------------------------------
768 // Name: D3DTextr_DestroyTexture()
769 // Desc: Frees the resources for the specified texture container
770 //-----------------------------------------------------------------------------
771 HRESULT D3DTextr_DestroyTexture( TCHAR* strName )
772 {
773     TextureContainer* ptcTexture = FindTexture( strName );
774     if( NULL == ptcTexture )
775         return DDERR_NOTFOUND;
776
777     // Remove the texture container from the global list
778     if( ptcTexture->pPrev )
779         ptcTexture->pPrev->pNext = ptcTexture->pNext;
780     else
781         g_ptcTextureList = ptcTexture->pNext;
782     ptcTexture->pNext = NULL;
783
784     SAFE_DELETE( ptcTexture );
785
786     return DD_OK;
787 }
788