d3dtextr.cpp
上传用户:cydong117
上传日期:2009-11-10
资源大小:638k
文件大小:33k
源码类别:

模拟服务器

开发平台:

Visual C++

  1. //-----------------------------------------------------------------------------
  2. // File: D3DTextr.cpp
  3. //
  4. // Desc: Functions to manage textures, including creating (loading from a
  5. //       file), restoring lost surfaces, invalidating, and destroying.
  6. //
  7. //       Note: the implementation of these fucntions maintain an internal list
  8. //       of loaded textures. After creation, individual textures are referenced
  9. //       via their ASCII names.
  10. //
  11. // Copyright (c) 1996-1999 Microsoft Corporation. All rights reserved
  12. //-----------------------------------------------------------------------------
  13. //#define STRICT
  14. #include "StdAfx.h"
  15. //#include <tchar.h>
  16. //#include <stdio.h>
  17. //#include "D3DTextr.h"
  18. //#include "D3DUtil.h"
  19. //-----------------------------------------------------------------------------
  20. // Macros, function prototypes and static variable
  21. //-----------------------------------------------------------------------------
  22. static TCHAR  g_strTexturePath[512] = _T(""); // Path for files
  23. //-----------------------------------------------------------------------------
  24. // Name: TextureContainer
  25. // Desc: Linked list structure to hold info per texture
  26. //-----------------------------------------------------------------------------
  27. struct TextureContainer
  28. {
  29.     TextureContainer* m_pNext; // Linked list ptr
  30.     TCHAR   m_strName[80];     // Name of texture (doubles as image filename)
  31.     DWORD   m_dwWidth;
  32.     DWORD   m_dwHeight;
  33.     DWORD   m_dwStage;         // Texture stage (for multitexture devices)
  34.     DWORD   m_dwBPP;
  35.     DWORD   m_dwFlags;
  36.     BOOL    m_bHasAlpha;
  37.     LPDIRECTDRAWSURFACE7 m_pddsSurface; // Surface of the texture
  38.     HBITMAP m_hbmBitmap;       // Bitmap containing texture image
  39.     DWORD*  m_pRGBAData;
  40. public:
  41.     HRESULT LoadImageData();
  42.     HRESULT LoadBitmapFile( TCHAR* strPathname );
  43.     HRESULT LoadTargaFile( TCHAR* strPathname );
  44.     HRESULT Restore( LPDIRECT3DDEVICE7 pd3dDevice );
  45.     HRESULT CopyBitmapToSurface();
  46.     HRESULT CopyRGBADataToSurface();
  47.     TextureContainer( TCHAR* strName, DWORD dwStage, DWORD dwFlags );
  48.     ~TextureContainer();
  49. };
  50. // Local list of textures
  51. static TextureContainer* g_ptcTextureList = NULL;
  52. //-----------------------------------------------------------------------------
  53. // Name: CD3DTextureManager
  54. // Desc: Class used to automatically construct and destruct the static
  55. //       texture engine class.
  56. //-----------------------------------------------------------------------------
  57. class CD3DTextureManager
  58. {
  59. public:
  60.     CD3DTextureManager() {}
  61.     ~CD3DTextureManager() { if( g_ptcTextureList ) delete g_ptcTextureList; }
  62. };
  63. // Global instance
  64. CD3DTextureManager g_StaticTextureEngine;
  65. //-----------------------------------------------------------------------------
  66. // Name: struct TEXTURESEARCHINFO
  67. // Desc: Structure used to search for texture formats
  68. //-----------------------------------------------------------------------------
  69. struct TEXTURESEARCHINFO
  70. {
  71.     DWORD dwDesiredBPP;   // Input for texture format search
  72.     BOOL  bUseAlpha;
  73.     BOOL  bUsePalette;
  74.     BOOL  bFoundGoodFormat;
  75.     DDPIXELFORMAT* pddpf; // Output of texture format search
  76. };
  77. //-----------------------------------------------------------------------------
  78. // Name: TextureSearchCallback()
  79. // Desc: Enumeration callback routine to find a best-matching texture format.
  80. //       The param data is the DDPIXELFORMAT of the best-so-far matching
  81. //       texture. Note: the desired BPP is passed in the dwSize field, and the
  82. //       default BPP is passed in the dwFlags field.
  83. //-----------------------------------------------------------------------------
  84. static HRESULT CALLBACK TextureSearchCallback( DDPIXELFORMAT* pddpf,
  85.                                                VOID* param )
  86. {
  87.     if( NULL==pddpf || NULL==param )
  88.         return DDENUMRET_OK;
  89.     TEXTURESEARCHINFO* ptsi = (TEXTURESEARCHINFO*)param;
  90.     // Skip any funky modes
  91.     if( pddpf->dwFlags & (DDPF_LUMINANCE|DDPF_BUMPLUMINANCE|DDPF_BUMPDUDV) )
  92.         return DDENUMRET_OK;
  93.     // Check for palettized formats
  94.     if( ptsi->bUsePalette )
  95.     {
  96.         if( !( pddpf->dwFlags & DDPF_PALETTEINDEXED8 ) )
  97.             return DDENUMRET_OK;
  98.         // Accept the first 8-bit palettized format we get
  99.         memcpy( ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT) );
  100.         ptsi->bFoundGoodFormat = TRUE;
  101.         return DDENUMRET_CANCEL;
  102.     }
  103.     // Else, skip any paletized formats (all modes under 16bpp)
  104.     if( pddpf->dwRGBBitCount < 16 )
  105.         return DDENUMRET_OK;
  106.     // Skip any FourCC formats
  107.     if( pddpf->dwFourCC != 0 )
  108.         return DDENUMRET_OK;
  109.     // Skip any ARGB 4444 formats (which are best used for pre-authored
  110.     // content designed speciafically for an ARGB 4444 format).
  111.     if( pddpf->dwRGBAlphaBitMask == 0x0000f000 )
  112.         return DDENUMRET_OK;
  113.     // Make sure current alpha format agrees with requested format type
  114.     if( (ptsi->bUseAlpha==TRUE) && !(pddpf->dwFlags&DDPF_ALPHAPIXELS) )
  115.         return DDENUMRET_OK;
  116.     if( (ptsi->bUseAlpha==FALSE) && (pddpf->dwFlags&DDPF_ALPHAPIXELS) )
  117.         return DDENUMRET_OK;
  118.     // Check if we found a good match
  119.     if( pddpf->dwRGBBitCount == ptsi->dwDesiredBPP )
  120.     {
  121.         memcpy( ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT) );
  122.         ptsi->bFoundGoodFormat = TRUE;
  123.         return DDENUMRET_CANCEL;
  124.     }
  125.     return DDENUMRET_OK;
  126. }
  127. //-----------------------------------------------------------------------------
  128. // Name: FindTexture()
  129. // Desc: Searches the internal list of textures for a texture specified by
  130. //       its name. Returns the structure associated with that texture.
  131. //-----------------------------------------------------------------------------
  132. static TextureContainer* FindTexture( TCHAR* strTextureName )
  133. {
  134.     TextureContainer* ptcTexture = g_ptcTextureList;
  135.     while( ptcTexture )
  136.     {
  137.         if( !lstrcmpi( strTextureName, ptcTexture->m_strName ) )
  138.             return ptcTexture;
  139.         ptcTexture = ptcTexture->m_pNext;
  140.     }
  141.     return NULL;
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Name: TextureContainer()
  145. // Desc: Constructor for a texture object
  146. //-----------------------------------------------------------------------------
  147. TextureContainer::TextureContainer( TCHAR* strName, DWORD dwStage,
  148.                                     DWORD dwFlags )
  149. {
  150.     lstrcpy( m_strName, strName );
  151.     m_dwWidth     = 0;
  152.     m_dwHeight    = 0;
  153.     m_dwStage     = dwStage;
  154.     m_dwBPP       = 0;
  155.     m_dwFlags     = dwFlags;
  156.     m_bHasAlpha   = 0;
  157.     m_pddsSurface = NULL;
  158.     m_hbmBitmap   = NULL;
  159.     m_pRGBAData   = NULL;
  160.     // Add the texture to the head of the global texture list
  161.     m_pNext = g_ptcTextureList;
  162.     g_ptcTextureList = this;
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Name: ~TextureContainer()
  166. // Desc: Destructs the contents of the texture container
  167. //-----------------------------------------------------------------------------
  168. TextureContainer::~TextureContainer()
  169. {
  170.     SAFE_RELEASE( m_pddsSurface );
  171.     SAFE_DELETE(  m_pRGBAData );
  172.     DeleteObject( m_hbmBitmap );
  173.     // Remove the texture container from the global list
  174.     if( g_ptcTextureList == this )
  175.         g_ptcTextureList = m_pNext;
  176.     else
  177.     {
  178.         for( TextureContainer* ptc=g_ptcTextureList; ptc; ptc=ptc->m_pNext )
  179.             if( ptc->m_pNext == this )
  180.                 ptc->m_pNext = m_pNext;
  181.     }
  182. }
  183. //-----------------------------------------------------------------------------
  184. // Name: LoadImageData()
  185. // Desc: Loads the texture map's image data
  186. //-----------------------------------------------------------------------------
  187. HRESULT TextureContainer::LoadImageData()
  188. {
  189.     TCHAR* strExtension;
  190.     TCHAR  strPathname[256];
  191.     FILE*  file;
  192.     // Check the executable's resource. If it's there, we're done!
  193.     m_hbmBitmap = (HBITMAP)LoadImage( GetModuleHandle(NULL), m_strName,
  194.                                       IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION );
  195.     if( m_hbmBitmap )
  196.         return S_OK;
  197.     // First check if the file exists in the global texture path
  198.     lstrcpy( strPathname, g_strTexturePath );
  199.     lstrcat( strPathname, m_strName );
  200.     if( NULL == ( file = fopen( strPathname, "rb" ) ) )
  201.     {
  202.         // Then check if the file exists in the DirectX SDK media path
  203.         lstrcpy( strPathname, D3DUtil_GetDXSDKMediaPath() );
  204.         lstrcat( strPathname, m_strName );
  205.         if( NULL == ( file = fopen( strPathname, "rb" ) ) )
  206.             return DDERR_NOTFOUND;
  207.     }
  208.     fclose( file );
  209.     // Get the filename extension
  210.     if( NULL == ( strExtension = _tcsrchr( m_strName, _T('.') ) ) )
  211.         return DDERR_UNSUPPORTED;
  212.     // Load bitmap files
  213.     if( !lstrcmpi( strExtension, _T(".bmp") ) )
  214.         return LoadBitmapFile( strPathname );
  215.     // Load targa files
  216.     if( !lstrcmpi( strExtension, _T(".tga") ) )
  217.         return LoadTargaFile( strPathname );
  218.     // Can add code here to check for other file formats before failing
  219.     return DDERR_UNSUPPORTED;
  220. }
  221. //-----------------------------------------------------------------------------
  222. // Name: LoadBitmapFile()
  223. // Desc: Loads data from a .bmp file, and stores it in a bitmap structure.
  224. //-----------------------------------------------------------------------------
  225. HRESULT TextureContainer::LoadBitmapFile( TCHAR* strPathname )
  226. {
  227.     // Try to load the bitmap as a file
  228.     m_hbmBitmap = (HBITMAP)LoadImage( NULL, strPathname, IMAGE_BITMAP, 0, 0,
  229.                                       LR_LOADFROMFILE|LR_CREATEDIBSECTION );
  230.     if( m_hbmBitmap )
  231.         return S_OK;
  232.     
  233.     return DDERR_NOTFOUND;
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Name: LoadTargaFile()
  237. // Desc: Loads RGBA data from a .tga file, and stores it in allocated memory
  238. //       for the specified texture container
  239. //-----------------------------------------------------------------------------
  240. HRESULT TextureContainer::LoadTargaFile( TCHAR* strPathname )
  241. {
  242.     FILE* file = fopen( strPathname, "rb" );
  243.     if( NULL == file )
  244.         return E_FAIL;
  245.     struct TargaHeader
  246.     {
  247.         BYTE IDLength;
  248.         BYTE ColormapType;
  249.         BYTE ImageType;
  250.         BYTE ColormapSpecification[5];
  251.         WORD XOrigin;
  252.         WORD YOrigin;
  253.         WORD ImageWidth;
  254.         WORD ImageHeight;
  255.         BYTE PixelDepth;
  256.         BYTE ImageDescriptor;
  257.     } tga;
  258.     fread( &tga, sizeof(TargaHeader), 1, file );
  259.     // Only true color, non-mapped images are supported
  260.     if( ( 0 != tga.ColormapType ) || 
  261.         ( tga.ImageType != 10 && tga.ImageType != 2 ) )
  262.     {
  263.         fclose( file );
  264.         return E_FAIL;
  265.     }
  266.     // Skip the ID field. The first byte of the header is the length of this field
  267.     if( tga.IDLength )
  268.         fseek( file, tga.IDLength, SEEK_CUR );
  269.     m_dwWidth   = tga.ImageWidth;
  270.     m_dwHeight  = tga.ImageHeight;
  271.     m_dwBPP     = tga.PixelDepth;
  272.     m_pRGBAData = new DWORD[m_dwWidth*m_dwHeight];
  273.     if( m_pRGBAData == NULL )
  274.     {
  275.         fclose(file);
  276.         return E_FAIL;
  277.     }
  278.     for( DWORD y=0; y<m_dwHeight; y++ )
  279.     {
  280.         DWORD dwOffset = y*m_dwWidth;
  281.         if( 0 == ( tga.ImageDescriptor & 0x0010 ) )
  282.             dwOffset = (m_dwHeight-y-1)*m_dwWidth;
  283.         for( DWORD x=0; x<m_dwWidth; x )
  284.         {
  285.             if( tga.ImageType == 10 )
  286.             {
  287.                 BYTE PacketInfo = getc( file );
  288.                 WORD PacketType = 0x80 & PacketInfo;
  289.                 WORD PixelCount = ( 0x007f & PacketInfo ) + 1;
  290.                 if( PacketType )
  291.                 {
  292.                     DWORD b = getc( file );
  293.                     DWORD g = getc( file );
  294.                     DWORD r = getc( file );
  295.                     DWORD a = 0xff;
  296.                     if( m_dwBPP == 32 )
  297.                         a = getc( file );
  298.                     while( PixelCount-- )
  299.                     {
  300.                         m_pRGBAData[dwOffset+x] = (r<<24L)+(g<<16L)+(b<<8L)+(a);
  301.                         x++;
  302.                     }
  303.                 }
  304.                 else
  305.                 {
  306.                     while( PixelCount-- )
  307.                     {
  308.                         BYTE b = getc( file );
  309.                         BYTE g = getc( file );
  310.                         BYTE r = getc( file );
  311.                         BYTE a = 0xff;
  312.                         if( m_dwBPP == 32 )
  313.                             a = getc( file );
  314.                         m_pRGBAData[dwOffset+x] = (r<<24L)+(g<<16L)+(b<<8L)+(a);
  315.                         x++;
  316.                     }
  317.                 }
  318.             }
  319.             else
  320.             {
  321.                 BYTE b = getc( file );
  322.                 BYTE g = getc( file );
  323.                 BYTE r = getc( file );
  324.                 BYTE a = 0xff;
  325.                 if( m_dwBPP == 32 )
  326.                     a = getc( file );
  327.                 m_pRGBAData[dwOffset+x] = (r<<24L)+(g<<16L)+(b<<8L)+(a);
  328.                 x++;
  329.             }
  330.         }
  331.     }
  332.     fclose( file );
  333.     // Check for alpha content
  334.     for( DWORD i=0; i<(m_dwWidth*m_dwHeight); i++ )
  335.     {
  336.         if( m_pRGBAData[i] & 0x000000ff != 0xff )
  337.         {
  338.             m_bHasAlpha = TRUE;
  339.             break;
  340.         }
  341.     }
  342.     
  343.     return S_OK;
  344. }
  345. //-----------------------------------------------------------------------------
  346. // Name: Restore()
  347. // Desc: Rebuilds the texture surface using the new device.
  348. //-----------------------------------------------------------------------------
  349. HRESULT TextureContainer::Restore( LPDIRECT3DDEVICE7 pd3dDevice )
  350. {
  351.     // Release any previously created objects
  352.     SAFE_RELEASE( m_pddsSurface );
  353.     // Check params
  354.     if( NULL == pd3dDevice )
  355.         return DDERR_INVALIDPARAMS;
  356.     // Get the device caps
  357.     D3DDEVICEDESC7 ddDesc;
  358.     if( FAILED( pd3dDevice->GetCaps( &ddDesc) ) )
  359.         return E_FAIL;
  360.     // Setup the new surface desc
  361.     DDSURFACEDESC2 ddsd;
  362.     D3DUtil_InitSurfaceDesc( ddsd );
  363.     ddsd.dwFlags         = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|
  364.                            DDSD_PIXELFORMAT|DDSD_TEXTURESTAGE;
  365.     ddsd.ddsCaps.dwCaps  = DDSCAPS_TEXTURE;
  366.     ddsd.dwTextureStage  = m_dwStage;
  367.     ddsd.dwWidth         = m_dwWidth;
  368.     ddsd.dwHeight        = m_dwHeight;
  369.     // Turn on texture management for hardware devices
  370.     if( ddDesc.deviceGUID == IID_IDirect3DHALDevice )
  371.         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
  372.     else if( ddDesc.deviceGUID == IID_IDirect3DTnLHalDevice )
  373.         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
  374.     else
  375.         ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  376.     // Adjust width and height to be powers of 2, if the device requires it
  377.     if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2 )
  378.     {
  379.         for( ddsd.dwWidth=1;  m_dwWidth>ddsd.dwWidth;   ddsd.dwWidth<<=1 );
  380.         for( ddsd.dwHeight=1; m_dwHeight>ddsd.dwHeight; ddsd.dwHeight<<=1 );
  381.     }
  382.     // Limit max texture sizes, if the driver can't handle large textures
  383.     DWORD dwMaxWidth  = ddDesc.dwMaxTextureWidth;
  384.     DWORD dwMaxHeight = ddDesc.dwMaxTextureHeight;
  385.     ddsd.dwWidth  = min( ddsd.dwWidth,  ( dwMaxWidth  ? dwMaxWidth  : 256 ) );
  386.     ddsd.dwHeight = min( ddsd.dwHeight, ( dwMaxHeight ? dwMaxHeight : 256 ) );
  387.     // Make the texture square, if the driver requires it
  388.     if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY )
  389.     {
  390.         if( ddsd.dwWidth > ddsd.dwHeight ) ddsd.dwHeight = ddsd.dwWidth;
  391.         else                               ddsd.dwWidth  = ddsd.dwHeight;
  392.     }
  393.     // Setup the structure to be used for texture enumration.
  394.     TEXTURESEARCHINFO tsi;
  395.     tsi.bFoundGoodFormat = FALSE;
  396.     tsi.pddpf            = &ddsd.ddpfPixelFormat;
  397.     tsi.dwDesiredBPP     = m_dwBPP;
  398.     tsi.bUsePalette      = ( m_dwBPP <= 8 );
  399.     tsi.bUseAlpha        = m_bHasAlpha;
  400.     if( m_dwFlags & D3DTEXTR_16BITSPERPIXEL )
  401.         tsi.dwDesiredBPP = 16;
  402.     else if( m_dwFlags & D3DTEXTR_32BITSPERPIXEL )
  403.         tsi.dwDesiredBPP = 32;
  404.     if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) )
  405.     {
  406.         if( tsi.bUsePalette )
  407.         {
  408.             if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_ALPHAPALETTE )
  409.             {
  410.                 tsi.bUseAlpha   = TRUE;
  411.                 tsi.bUsePalette = TRUE;
  412.             }
  413.             else
  414.             {
  415.                 tsi.bUseAlpha   = TRUE;
  416.                 tsi.bUsePalette = FALSE;
  417.             }
  418.         }
  419.     }
  420.     // Enumerate the texture formats, and find the closest device-supported
  421.     // texture pixel format
  422.     pd3dDevice->EnumTextureFormats( TextureSearchCallback, &tsi );
  423.     // If we couldn't find a format, let's try a default format
  424.     if( FALSE == tsi.bFoundGoodFormat )
  425.     {
  426.         tsi.bUsePalette  = FALSE;
  427.         tsi.dwDesiredBPP = 16;
  428.         pd3dDevice->EnumTextureFormats( TextureSearchCallback, &tsi );
  429.         // If we still fail, we cannot create this texture
  430.         if( FALSE == tsi.bFoundGoodFormat )
  431.             return E_FAIL;
  432.     }
  433.     // Get the DirectDraw interface for creating surfaces
  434.     LPDIRECTDRAW7        pDD;
  435.     LPDIRECTDRAWSURFACE7 pddsRender;
  436.     pd3dDevice->GetRenderTarget( &pddsRender );
  437.     pddsRender->GetDDInterface( (VOID**)&pDD );
  438.     pddsRender->Release();
  439.     // Create a new surface for the texture
  440.     HRESULT hr = pDD->CreateSurface( &ddsd, &m_pddsSurface, NULL );
  441.     // Done with DDraw
  442.     pDD->Release();
  443.     if( FAILED(hr) )
  444.         return hr;
  445.     // For bitmap-based textures, copy the bitmap image.
  446.     if( m_hbmBitmap )
  447.         return CopyBitmapToSurface();
  448.     if( m_pRGBAData )
  449.         return CopyRGBADataToSurface();
  450.     // At this point, code can be added to handle other file formats (such as
  451.     // .dds files, .jpg files, etc.).
  452.     return S_OK;
  453. }
  454. //-----------------------------------------------------------------------------
  455. // Name: CopyBitmapToSurface()
  456. // Desc: Copies the image of a bitmap into a surface
  457. //-----------------------------------------------------------------------------
  458. HRESULT TextureContainer::CopyBitmapToSurface()
  459. {
  460.     // Get a DDraw object to create a temporary surface
  461.     LPDIRECTDRAW7 pDD;
  462.     m_pddsSurface->GetDDInterface( (VOID**)&pDD );
  463.     // Get the bitmap structure (to extract width, height, and bpp)
  464.     BITMAP bm;
  465.     GetObject( m_hbmBitmap, sizeof(BITMAP), &bm );
  466.     // Setup the new surface desc
  467.     DDSURFACEDESC2 ddsd;
  468.     ddsd.dwSize = sizeof(ddsd);
  469.     m_pddsSurface->GetSurfaceDesc( &ddsd );
  470.     ddsd.dwFlags          = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|
  471.                             DDSD_TEXTURESTAGE;
  472.     ddsd.ddsCaps.dwCaps   = DDSCAPS_TEXTURE|DDSCAPS_SYSTEMMEMORY;
  473.     ddsd.ddsCaps.dwCaps2  = 0L;
  474.     ddsd.dwWidth          = bm.bmWidth;
  475.     ddsd.dwHeight         = bm.bmHeight;
  476.     // Create a new surface for the texture
  477.     LPDIRECTDRAWSURFACE7 pddsTempSurface;
  478.     HRESULT hr;
  479.     if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTempSurface, NULL ) ) )
  480.     {
  481.         pDD->Release();
  482.         return hr;
  483.     }
  484.     // Get a DC for the bitmap
  485.     HDC hdcBitmap = CreateCompatibleDC( NULL );
  486.     if( NULL == hdcBitmap )
  487.     {
  488.         pddsTempSurface->Release();
  489.         pDD->Release();
  490.         return hr;
  491.     }
  492.     SelectObject( hdcBitmap, m_hbmBitmap );
  493.     // Handle palettized textures. Need to attach a palette
  494.     if( ddsd.ddpfPixelFormat.dwRGBBitCount == 8 )
  495.     {
  496.         LPDIRECTDRAWPALETTE  pPalette;
  497.         DWORD dwPaletteFlags = DDPCAPS_8BIT|DDPCAPS_ALLOW256;
  498.         DWORD pe[256];
  499.         WORD  wNumColors     = GetDIBColorTable( hdcBitmap, 0, 256, (RGBQUAD*)pe );
  500.         // Create the color table
  501.         for( WORD i=0; i<wNumColors; i++ )
  502.         {
  503.             pe[i] = RGB( GetBValue(pe[i]), GetGValue(pe[i]), GetRValue(pe[i]) );
  504.             // Handle textures with transparent pixels
  505.             if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) )
  506.             {
  507.                 // Set alpha for opaque pixels
  508.                 if( m_dwFlags & D3DTEXTR_TRANSPARENTBLACK )
  509.                 {
  510.                     if( pe[i] != 0x00000000 )
  511.                         pe[i] |= 0xff000000;
  512.                 }
  513.                 else if( m_dwFlags & D3DTEXTR_TRANSPARENTWHITE )
  514.                 {
  515.                     if( pe[i] != 0x00ffffff )
  516.                         pe[i] |= 0xff000000;
  517.                 }
  518.             }
  519.         }
  520.         // Add DDPCAPS_ALPHA flag for textures with transparent pixels
  521.         if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) )
  522.             dwPaletteFlags |= DDPCAPS_ALPHA;
  523.         // Create & attach a palette
  524.         pDD->CreatePalette( dwPaletteFlags, (PALETTEENTRY*)pe, &pPalette, NULL );
  525.         pddsTempSurface->SetPalette( pPalette );
  526.         m_pddsSurface->SetPalette( pPalette );
  527.         SAFE_RELEASE( pPalette );
  528.     }
  529.     // Copy the bitmap image to the surface.
  530.     HDC hdcSurface;
  531.     if( SUCCEEDED( pddsTempSurface->GetDC( &hdcSurface ) ) )
  532.     {
  533.         BitBlt( hdcSurface, 0, 0, bm.bmWidth, bm.bmHeight, hdcBitmap, 0, 0,
  534.                 SRCCOPY );
  535.         pddsTempSurface->ReleaseDC( hdcSurface );
  536.     }
  537.     DeleteDC( hdcBitmap );
  538.     // Copy the temp surface to the real texture surface
  539.     m_pddsSurface->Blt( NULL, pddsTempSurface, NULL, DDBLT_WAIT, NULL );
  540.     // Done with the temp surface
  541.     pddsTempSurface->Release();
  542.     // For textures with real alpha (not palettized), set transparent bits
  543.     if( ddsd.ddpfPixelFormat.dwRGBAlphaBitMask )
  544.     {
  545.         if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) )
  546.         {
  547.             // Lock the texture surface
  548.             DDSURFACEDESC2 ddsd;
  549.             ddsd.dwSize = sizeof(ddsd);
  550.             while( m_pddsSurface->Lock( NULL, &ddsd, 0, NULL ) ==
  551.                    DDERR_WASSTILLDRAWING );
  552.             DWORD dwAlphaMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask;
  553.             DWORD dwRGBMask   = ( ddsd.ddpfPixelFormat.dwRBitMask |
  554.                                   ddsd.ddpfPixelFormat.dwGBitMask |
  555.                                   ddsd.ddpfPixelFormat.dwBBitMask );
  556.             DWORD dwColorkey  = 0x00000000; // Colorkey on black
  557.             if( m_dwFlags & D3DTEXTR_TRANSPARENTWHITE )
  558.                 dwColorkey = dwRGBMask;     // Colorkey on white
  559.             // Add an opaque alpha value to each non-colorkeyed pixel
  560.             for( DWORD y=0; y<ddsd.dwHeight; y++ )
  561.             {
  562.                 WORD*  p16 =  (WORD*)((BYTE*)ddsd.lpSurface + y*ddsd.lPitch);
  563.                 DWORD* p32 = (DWORD*)((BYTE*)ddsd.lpSurface + y*ddsd.lPitch);
  564.                 for( DWORD x=0; x<ddsd.dwWidth; x++ )
  565.                 {
  566.                     if( ddsd.ddpfPixelFormat.dwRGBBitCount == 16 )
  567.                     {
  568.                         if( ( *p16 &= dwRGBMask ) != dwColorkey )
  569.                             *p16 |= dwAlphaMask;
  570.                         p16++;
  571.                     }
  572.                     if( ddsd.ddpfPixelFormat.dwRGBBitCount == 32 )
  573.                     {
  574.                         if( ( *p32 &= dwRGBMask ) != dwColorkey )
  575.                             *p32 |= dwAlphaMask;
  576.                         p32++;
  577.                     }
  578.                 }
  579.             }
  580.             m_pddsSurface->Unlock( NULL );
  581.         }
  582.     }
  583.     pDD->Release();
  584.     return S_OK;;
  585. }
  586. //-----------------------------------------------------------------------------
  587. // Name: CopyRGBADataToSurface()
  588. // Desc: Invalidates the current texture objects and rebuilds new ones
  589. //       using the new device.
  590. //-----------------------------------------------------------------------------
  591. HRESULT TextureContainer::CopyRGBADataToSurface()
  592. {
  593.     // Get a DDraw object to create a temporary surface
  594.     LPDIRECTDRAW7 pDD;
  595.     m_pddsSurface->GetDDInterface( (VOID**)&pDD );
  596.     // Setup the new surface desc
  597.     DDSURFACEDESC2 ddsd;
  598.     ddsd.dwSize = sizeof(ddsd);
  599.     m_pddsSurface->GetSurfaceDesc( &ddsd );
  600.     ddsd.dwFlags         = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|
  601.                            DDSD_TEXTURESTAGE;
  602.     ddsd.ddsCaps.dwCaps  = DDSCAPS_TEXTURE|DDSCAPS_SYSTEMMEMORY;
  603.     ddsd.ddsCaps.dwCaps2 = 0L;
  604.     ddsd.dwWidth         = m_dwWidth;
  605.     ddsd.dwHeight        = m_dwHeight;
  606.     // Create a new surface for the texture
  607.     LPDIRECTDRAWSURFACE7 pddsTempSurface;
  608.     HRESULT hr;
  609.     if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTempSurface, NULL ) ) )
  610.     {
  611.         pDD->Release();
  612.         return NULL;
  613.     }
  614.     while( pddsTempSurface->Lock( NULL, &ddsd, 0, 0 ) == DDERR_WASSTILLDRAWING );
  615.     DWORD lPitch = ddsd.lPitch;
  616.     BYTE* pBytes = (BYTE*)ddsd.lpSurface;
  617.     DWORD dwRMask = ddsd.ddpfPixelFormat.dwRBitMask;
  618.     DWORD dwGMask = ddsd.ddpfPixelFormat.dwGBitMask;
  619.     DWORD dwBMask = ddsd.ddpfPixelFormat.dwBBitMask;
  620.     DWORD dwAMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask;
  621.     DWORD dwRShiftL = 8, dwRShiftR = 0;
  622.     DWORD dwGShiftL = 8, dwGShiftR = 0;
  623.     DWORD dwBShiftL = 8, dwBShiftR = 0;
  624.     DWORD dwAShiftL = 8, dwAShiftR = 0;
  625.     DWORD dwMask;
  626.     for( dwMask=dwRMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwRShiftR++;
  627.     for( ; dwMask; dwMask>>=1 ) dwRShiftL--;
  628.     for( dwMask=dwGMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwGShiftR++;
  629.     for( ; dwMask; dwMask>>=1 ) dwGShiftL--;
  630.     for( dwMask=dwBMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwBShiftR++;
  631.     for( ; dwMask; dwMask>>=1 ) dwBShiftL--;
  632.     for( dwMask=dwAMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwAShiftR++;
  633.     for( ; dwMask; dwMask>>=1 ) dwAShiftL--;
  634.     for( DWORD y=0; y<ddsd.dwHeight; y++ )
  635.     {
  636.         DWORD* pDstData32 = (DWORD*)pBytes;
  637.         WORD*  pDstData16 = (WORD*)pBytes;
  638.         for( DWORD x=0; x<ddsd.dwWidth; x++ )
  639.         {
  640.             DWORD dwPixel = m_pRGBAData[y*ddsd.dwWidth+x];
  641.             BYTE r = (BYTE)((dwPixel>>24)&0x000000ff);
  642.             BYTE g = (BYTE)((dwPixel>>16)&0x000000ff);
  643.             BYTE b = (BYTE)((dwPixel>> 8)&0x000000ff);
  644.             BYTE a = (BYTE)((dwPixel>> 0)&0x000000ff);
  645.             DWORD dr = ((r>>(dwRShiftL))<<dwRShiftR)&dwRMask;
  646.             DWORD dg = ((g>>(dwGShiftL))<<dwGShiftR)&dwGMask;
  647.             DWORD db = ((b>>(dwBShiftL))<<dwBShiftR)&dwBMask;
  648.             DWORD da = ((a>>(dwAShiftL))<<dwAShiftR)&dwAMask;
  649.             if( 32 == ddsd.ddpfPixelFormat.dwRGBBitCount )
  650.                 pDstData32[x] = (DWORD)(dr+dg+db+da);
  651.             else
  652.                 pDstData16[x] = (WORD)(dr+dg+db+da);
  653.         }
  654.     
  655.         pBytes += ddsd.lPitch;
  656.     }
  657.     pddsTempSurface->Unlock(0);
  658.     // Copy the temp surface to the real texture surface
  659.     m_pddsSurface->Blt( NULL, pddsTempSurface, NULL, DDBLT_WAIT, NULL );
  660.     // Done with the temp objects
  661.     pddsTempSurface->Release();
  662.     pDD->Release();
  663.     return S_OK;
  664. }
  665. //-----------------------------------------------------------------------------
  666. // Name: D3DTextr_SetTexturePath()
  667. // Desc: Enumeration callback routine to find a best-matching texture format.
  668. //-----------------------------------------------------------------------------
  669. VOID D3DTextr_SetTexturePath( TCHAR* strTexturePath )
  670. {
  671.     if( NULL == strTexturePath )
  672.         strTexturePath = _T("");
  673.     lstrcpy( g_strTexturePath, strTexturePath );
  674. }
  675. //-----------------------------------------------------------------------------
  676. // Name: D3DTextr_CreateTextureFromFile()
  677. // Desc: Is passed a filename and creates a local Bitmap from that file.
  678. //       The texture can not be used until it is restored, however.
  679. //-----------------------------------------------------------------------------
  680. HRESULT D3DTextr_CreateTextureFromFile( TCHAR* strName, DWORD dwStage,
  681.                                         DWORD dwFlags )
  682. {
  683.     // Check parameters
  684.     if( NULL == strName )
  685.         return E_INVALIDARG;
  686.     // Check first to see if the texture is already loaded
  687.     if( NULL != FindTexture( strName ) )
  688.         return S_OK;
  689.     // Allocate and add the texture to the linked list of textures;
  690.     TextureContainer* ptcTexture = new TextureContainer( strName, dwStage,
  691.                                                          dwFlags );
  692.     if( NULL == ptcTexture )
  693.         return E_OUTOFMEMORY;
  694.     // Create a bitmap and load the texture file into it,
  695.     if( FAILED( ptcTexture->LoadImageData() ) )
  696.     {
  697.         delete ptcTexture;
  698.         return E_FAIL;
  699.     }
  700.     // Save the image's dimensions
  701.     if( ptcTexture->m_hbmBitmap )
  702.     {
  703.         BITMAP bm;
  704.         GetObject( ptcTexture->m_hbmBitmap, sizeof(BITMAP), &bm );
  705.         ptcTexture->m_dwWidth  = (DWORD)bm.bmWidth;
  706.         ptcTexture->m_dwHeight = (DWORD)bm.bmHeight;
  707.         ptcTexture->m_dwBPP    = (DWORD)bm.bmBitsPixel;
  708.     }
  709.     return S_OK;
  710. }
  711. //-----------------------------------------------------------------------------
  712. // Name: D3DTextr_CreateEmptyTexture()
  713. // Desc: Creates an empty texture.
  714. //-----------------------------------------------------------------------------
  715. HRESULT D3DTextr_CreateEmptyTexture( TCHAR* strName, DWORD dwWidth,
  716.                                      DWORD dwHeight, DWORD dwStage, 
  717.                                      DWORD dwFlags )
  718. {
  719.     // Check parameters
  720.     if( NULL == strName )
  721.         return E_INVALIDARG;
  722.     // Check first to see if the texture is already loaded
  723.     if( NULL != FindTexture( strName ) )
  724.         return E_FAIL;
  725.     // Allocate and add the texture to the linked list of textures;
  726.     TextureContainer* ptcTexture = new TextureContainer( strName, dwStage,
  727.                                                          dwFlags );
  728.     if( NULL == ptcTexture )
  729.         return E_OUTOFMEMORY;
  730.     // Save dimensions
  731.     ptcTexture->m_dwWidth  = dwWidth;
  732.     ptcTexture->m_dwHeight = dwHeight;
  733.     ptcTexture->m_dwBPP    = 16;
  734.     if( ptcTexture->m_dwFlags & D3DTEXTR_32BITSPERPIXEL )
  735.         ptcTexture->m_dwBPP = 32;
  736.     // Save alpha usage flag
  737.     if( dwFlags & D3DTEXTR_CREATEWITHALPHA )
  738.         ptcTexture->m_bHasAlpha = TRUE;
  739.     return S_OK;
  740. }
  741. //-----------------------------------------------------------------------------
  742. // Name: D3DTextr_Restore()
  743. // Desc: Invalidates the current texture objects and rebuilds new ones
  744. //       using the new device.
  745. //-----------------------------------------------------------------------------
  746. HRESULT D3DTextr_Restore( TCHAR* strName, LPDIRECT3DDEVICE7 pd3dDevice )
  747. {
  748.     TextureContainer* ptcTexture = FindTexture( strName );
  749.     if( NULL == ptcTexture )
  750.         return DDERR_NOTFOUND;
  751.     // Restore the texture (this recreates the new surface for this device).
  752.     return ptcTexture->Restore( pd3dDevice );
  753. }
  754. //-----------------------------------------------------------------------------
  755. // Name: D3DTextr_RestoreAllTextures()
  756. // Desc: This function is called when a mode is changed. It updates all
  757. //       texture objects to be valid with the new device.
  758. //-----------------------------------------------------------------------------
  759. HRESULT D3DTextr_RestoreAllTextures( LPDIRECT3DDEVICE7 pd3dDevice )
  760. {
  761.     TextureContainer* ptcTexture = g_ptcTextureList;
  762.     while( ptcTexture )
  763.     {
  764.         D3DTextr_Restore( ptcTexture->m_strName, pd3dDevice );
  765.         ptcTexture = ptcTexture->m_pNext;
  766.     }
  767.     return S_OK;
  768. }
  769. //-----------------------------------------------------------------------------
  770. // Name: D3DTextr_Invalidate()
  771. // Desc: Used to bump a texture out of (video) memory, this function
  772. //       actually destroys the d3dtexture and ddsurface of the texture
  773. //-----------------------------------------------------------------------------
  774. HRESULT D3DTextr_Invalidate( TCHAR* strName )
  775. {
  776.     TextureContainer* ptcTexture = FindTexture( strName );
  777.     if( NULL == ptcTexture )
  778.         return DDERR_NOTFOUND;
  779.     SAFE_RELEASE( ptcTexture->m_pddsSurface );
  780.     return S_OK;
  781. }
  782. //-----------------------------------------------------------------------------
  783. // Name: D3DTextr_InvalidateAllTextures()
  784. // Desc: This function is called when a mode is changed. It invalidates
  785. //       all texture objects so their device can be safely released.
  786. //-----------------------------------------------------------------------------
  787. HRESULT D3DTextr_InvalidateAllTextures()
  788. {
  789.     TextureContainer* ptcTexture = g_ptcTextureList;
  790.     while( ptcTexture )
  791.     {
  792.         SAFE_RELEASE( ptcTexture->m_pddsSurface );
  793.         ptcTexture = ptcTexture->m_pNext;
  794.     }
  795.     return S_OK;
  796. }
  797. //-----------------------------------------------------------------------------
  798. // Name: D3DTextr_DestroyTexture()
  799. // Desc: Frees the resources for the specified texture container
  800. //-----------------------------------------------------------------------------
  801. HRESULT D3DTextr_DestroyTexture( TCHAR* strName )
  802. {
  803.     TextureContainer* ptcTexture = FindTexture( strName );
  804.     SAFE_DELETE( ptcTexture );
  805.     return S_OK;
  806. }
  807. //-----------------------------------------------------------------------------
  808. // Name: D3DTextr_GetSurface()
  809. // Desc: Returns a pointer to a d3dSurface from the name of the texture
  810. //-----------------------------------------------------------------------------
  811. LPDIRECTDRAWSURFACE7 D3DTextr_GetSurface( TCHAR* strName )
  812. {
  813.     TextureContainer* ptcTexture = FindTexture( strName );
  814.     return ptcTexture ? ptcTexture->m_pddsSurface : NULL;
  815. }