|
|
//-----------------------------------------------------------------------------
// File: D3DTextr.cpp
//
// Desc: Functions to manage textures, including creating (loading from a
// file), restoring lost surfaces, invalidating, and destroying.
//
// Note: the implementation of these fucntions maintain an internal list
// of loaded textures. After creation, individual textures are referenced
// via their ASCII names.
//
// Copyright (c) 1996-1999 Microsoft Corporation. All rights reserved
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "D3DTextr.h"
#include "D3DUtil.h"
//-----------------------------------------------------------------------------
// Macros, function prototypes and static variable
//-----------------------------------------------------------------------------
TCHAR g_strTexturePath[512]; // Path for files
//-----------------------------------------------------------------------------
// Name: TextureContainer
// Desc: Linked list structure to hold info per texture
//-----------------------------------------------------------------------------
struct TextureContainer { TextureContainer* m_pNext; // Linked list ptr
TCHAR m_strName[80]; // Name of texture (doubles as image filename)
DWORD m_dwWidth; DWORD m_dwHeight; DWORD m_dwStage; // Texture stage (for multitexture devices)
DWORD m_dwBPP; DWORD m_dwFlags; BOOL m_bHasAlpha;
LPDIRECTDRAWSURFACE7 m_pddsSurface; // Surface of the texture
HBITMAP m_hbmBitmap; // Bitmap containing texture image
DWORD* m_pRGBAData;
public: HRESULT LoadImageData(); HRESULT LoadBitmapFile(TCHAR* strPathname); HRESULT LoadTargaFile(TCHAR* strPathname); HRESULT Restore(LPDIRECT3DDEVICE7 pd3dDevice); HRESULT CopyBitmapToSurface(); HRESULT CopyRGBADataToSurface();
TextureContainer(TCHAR* strName, DWORD dwStage, DWORD dwFlags); ~TextureContainer(); };
// Local list of textures
static TextureContainer* g_ptcTextureList = NULL;
//-----------------------------------------------------------------------------
// Name: CD3DTextureManager
// Desc: Class used to automatically construct and destruct the static
// texture engine class.
//-----------------------------------------------------------------------------
class CD3DTextureManager { public: CD3DTextureManager() {} ~CD3DTextureManager() { if (g_ptcTextureList) delete g_ptcTextureList; } };
// Global instance
CD3DTextureManager g_StaticTextureEngine;
//-----------------------------------------------------------------------------
// Name: struct TEXTURESEARCHINFO
// Desc: Structure used to search for texture formats
//-----------------------------------------------------------------------------
struct TEXTURESEARCHINFO { DWORD dwDesiredBPP; // Input for texture format search
BOOL bUseAlpha; BOOL bUsePalette; BOOL bFoundGoodFormat;
DDPIXELFORMAT* pddpf; // Output of texture format search
};
//-----------------------------------------------------------------------------
// Name: TextureSearchCallback()
// Desc: Enumeration callback routine to find a best-matching texture format.
// The param data is the DDPIXELFORMAT of the best-so-far matching
// texture. Note: the desired BPP is passed in the dwSize field, and the
// default BPP is passed in the dwFlags field.
//-----------------------------------------------------------------------------
static HRESULT CALLBACK TextureSearchCallback(DDPIXELFORMAT* pddpf, VOID* param) { if (NULL==pddpf || NULL==param) return DDENUMRET_OK;
TEXTURESEARCHINFO* ptsi = (TEXTURESEARCHINFO*)param;
// Skip any funky modes
if (pddpf->dwFlags & (DDPF_LUMINANCE|DDPF_BUMPLUMINANCE|DDPF_BUMPDUDV)) return DDENUMRET_OK;
// Check for palettized formats
if (ptsi->bUsePalette) { if (!(pddpf->dwFlags & DDPF_PALETTEINDEXED8)) return DDENUMRET_OK;
// Accept the first 8-bit palettized format we get
memcpy(ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT)); ptsi->bFoundGoodFormat = TRUE; return DDENUMRET_CANCEL; }
// Else, skip any paletized formats (all modes under 16bpp)
if (pddpf->dwRGBBitCount < 16) return DDENUMRET_OK;
// Skip any FourCC formats
if (pddpf->dwFourCC != 0) return DDENUMRET_OK;
// Skip any ARGB 4444 formats (which are best used for pre-authored
// content designed speciafically for an ARGB 4444 format).
if (pddpf->dwRGBAlphaBitMask == 0x0000f000) return DDENUMRET_OK;
// Make sure current alpha format agrees with requested format type
if ((ptsi->bUseAlpha==TRUE) && !(pddpf->dwFlags&DDPF_ALPHAPIXELS)) return DDENUMRET_OK; if ((ptsi->bUseAlpha==FALSE) && (pddpf->dwFlags&DDPF_ALPHAPIXELS)) return DDENUMRET_OK;
// Check if we found a good match
if (pddpf->dwRGBBitCount == ptsi->dwDesiredBPP) { memcpy(ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT)); ptsi->bFoundGoodFormat = TRUE; return DDENUMRET_CANCEL; }
return DDENUMRET_OK; }
//-----------------------------------------------------------------------------
// Name: FindTexture()
// Desc: Searches the internal list of textures for a texture specified by
// its name. Returns the structure associated with that texture.
//-----------------------------------------------------------------------------
static TextureContainer* FindTexture(TCHAR* strTextureName) { TextureContainer* ptcTexture = g_ptcTextureList;
while(ptcTexture) { if (!StrCmpI(strTextureName, ptcTexture->m_strName)) return ptcTexture; ptcTexture = ptcTexture->m_pNext; }
return NULL; }
//-----------------------------------------------------------------------------
// Name: TextureContainer()
// Desc: Constructor for a texture object
//-----------------------------------------------------------------------------
TextureContainer::TextureContainer(TCHAR* strName, DWORD dwStage, DWORD dwFlags) { lstrcpy(m_strName, strName); m_dwWidth = 0; m_dwHeight = 0; m_dwStage = dwStage; m_dwBPP = 0; m_dwFlags = dwFlags; m_bHasAlpha = 0;
m_pddsSurface = NULL; m_hbmBitmap = NULL; m_pRGBAData = NULL;
// Add the texture to the head of the global texture list
m_pNext = g_ptcTextureList; g_ptcTextureList = this; }
//-----------------------------------------------------------------------------
// Name: ~TextureContainer()
// Desc: Destructs the contents of the texture container
//-----------------------------------------------------------------------------
TextureContainer::~TextureContainer() { SAFE_RELEASE(m_pddsSurface); SAFE_DELETE(m_pRGBAData); DeleteObject(m_hbmBitmap);
// Remove the texture container from the global list
if (g_ptcTextureList == this) g_ptcTextureList = m_pNext; else { for(TextureContainer* ptc=g_ptcTextureList; ptc; ptc=ptc->m_pNext) if (ptc->m_pNext == this) ptc->m_pNext = m_pNext; } }
//-----------------------------------------------------------------------------
// Name: LoadImageData()
// Desc: Loads the texture map's image data
//-----------------------------------------------------------------------------
HRESULT TextureContainer::LoadImageData() { HRESULT hr = S_OK;
// Check the executable's resource. If it's there, we're done!
m_hbmBitmap = (HBITMAP)LoadImage(GetModuleHandle(NULL), m_strName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); if (!m_hbmBitmap) { TCHAR* strExtension; TCHAR strPathname[256];
// First check if the file exists in the global texture path
lstrcpy(strPathname, g_strTexturePath); lstrcat(strPathname, m_strName);
if (!PathFileExists(strPathname)) { // Then check if the file exists in the DirectX SDK media path
lstrcpy(strPathname, D3DUtil_GetDXSDKMediaPath()); lstrcat(strPathname, m_strName); }
if (PathFileExists(strPathname)) { // Get the filename extension
if (NULL == (strExtension = StrChr(m_strName, TEXT('.')))) return DDERR_UNSUPPORTED;
// Load bitmap files
if (!lstrcmpi(strExtension, TEXT(".bmp"))) return LoadBitmapFile(strPathname);
// Load targa files
if (!lstrcmpi(strExtension, TEXT(".tga"))) return LoadTargaFile(strPathname); } else { hr = DDERR_NOTFOUND; } }
// Can add code here to check for other file formats before failing
return DDERR_UNSUPPORTED; }
//-----------------------------------------------------------------------------
// Name: LoadBitmapFile()
// Desc: Loads data from a .bmp file, and stores it in a bitmap structure.
//-----------------------------------------------------------------------------
HRESULT TextureContainer::LoadBitmapFile(TCHAR* strPathname) { // Try to load the bitmap as a file
m_hbmBitmap = (HBITMAP)LoadImage(NULL, strPathname, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION); if (m_hbmBitmap) return S_OK; return DDERR_NOTFOUND; }
BYTE GetFileByte(HANDLE hFile) { BYTE byte = 0; DWORD cbRead;
if (!ReadFile(hFile, &byte, sizeof(byte), &cbRead, NULL) || (sizeof(byte) != cbRead)) { return 0; }
return byte; }
//-----------------------------------------------------------------------------
// Name: LoadTargaFile()
// Desc: Loads RGBA data from a .tga file, and stores it in allocated memory
// for the specified texture container
//-----------------------------------------------------------------------------
HRESULT TextureContainer::LoadTargaFile(TCHAR* strPathname) { HANDLE hFile = CreateFile(strPathname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile) return E_FAIL;
struct TargaHeader { BYTE IDLength; BYTE ColormapType; BYTE ImageType; BYTE ColormapSpecification[5]; WORD XOrigin; WORD YOrigin; WORD ImageWidth; WORD ImageHeight; BYTE PixelDepth; BYTE ImageDescriptor; } tga;
DWORD cbRead; if (ReadFile(hFile, &tga, sizeof(tga), &cbRead, NULL)) { // Only true color, non-mapped images are supported
if ((0 != tga.ColormapType) || (tga.ImageType != 10 && tga.ImageType != 2)) { CloseHandle(hFile); return E_FAIL; }
// Skip the ID field. The first byte of the header is the length of this field
if (tga.IDLength) { SetFilePointer(hFile, tga.IDLength, 0, FILE_CURRENT); }
m_dwWidth = tga.ImageWidth; m_dwHeight = tga.ImageHeight; m_dwBPP = tga.PixelDepth; m_pRGBAData = new DWORD[m_dwWidth*m_dwHeight];
if (m_pRGBAData == NULL) { CloseHandle(hFile); return E_FAIL; }
for(DWORD y=0; y<m_dwHeight; y++) { DWORD dwOffset = y*m_dwWidth;
if (0 == (tga.ImageDescriptor & 0x0010)) dwOffset = (m_dwHeight-y-1)*m_dwWidth;
for(DWORD x=0; x<m_dwWidth; x) { if (tga.ImageType == 10) { BYTE PacketInfo = GetFileByte(hFile); WORD PacketType = 0x80 & PacketInfo; WORD PixelCount = (0x007f & PacketInfo) + 1;
if (PacketType) { DWORD b = GetFileByte(hFile); DWORD g = GetFileByte(hFile); DWORD r = GetFileByte(hFile); DWORD a = 0xff; if (m_dwBPP == 32) a = GetFileByte(hFile);
while(PixelCount--) { m_pRGBAData[dwOffset+x] = (r<<24L)+(g<<16L)+(b<<8L)+(a); x++; } } else { while(PixelCount--) { BYTE b = GetFileByte(hFile); BYTE g = GetFileByte(hFile); BYTE r = GetFileByte(hFile); BYTE a = 0xff; if (m_dwBPP == 32) a = GetFileByte(hFile);
m_pRGBAData[dwOffset+x] = (r<<24L)+(g<<16L)+(b<<8L)+(a); x++; } } } else { BYTE b = GetFileByte(hFile); BYTE g = GetFileByte(hFile); BYTE r = GetFileByte(hFile); BYTE a = 0xff; if (m_dwBPP == 32) a = GetFileByte(hFile);
m_pRGBAData[dwOffset+x] = (r<<24L)+(g<<16L)+(b<<8L)+(a); x++; } } } } CloseHandle(hFile);
// Check for alpha content
for(DWORD i=0; i<(m_dwWidth*m_dwHeight); i++) { if ((m_pRGBAData[i] & 0x000000ff) != 0xff) { m_bHasAlpha = TRUE; break; } } return S_OK; }
//-----------------------------------------------------------------------------
// Name: Restore()
// Desc: Rebuilds the texture surface using the new device.
//-----------------------------------------------------------------------------
HRESULT TextureContainer::Restore(LPDIRECT3DDEVICE7 pd3dDevice) { // Release any previously created objects
SAFE_RELEASE(m_pddsSurface);
// Check params
if (NULL == pd3dDevice) return DDERR_INVALIDPARAMS;
// Get the device caps
D3DDEVICEDESC7 ddDesc; if (FAILED(pd3dDevice->GetCaps(&ddDesc))) return E_FAIL;
// Setup the new surface desc
DDSURFACEDESC2 ddsd; D3DUtil_InitSurfaceDesc(ddsd); ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH| DDSD_PIXELFORMAT|DDSD_TEXTURESTAGE; ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; ddsd.dwTextureStage = m_dwStage; ddsd.dwWidth = m_dwWidth; ddsd.dwHeight = m_dwHeight;
// Turn on texture management for hardware devices
if (ddDesc.deviceGUID == IID_IDirect3DHALDevice) ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE; else if (ddDesc.deviceGUID == IID_IDirect3DTnLHalDevice) ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE; else ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
// Adjust width and height to be powers of 2, if the device requires it
if (ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) { for(ddsd.dwWidth=1; m_dwWidth>ddsd.dwWidth; ddsd.dwWidth<<=1); for(ddsd.dwHeight=1; m_dwHeight>ddsd.dwHeight; ddsd.dwHeight<<=1); }
// Limit max texture sizes, if the driver can't handle large textures
DWORD dwMaxWidth = ddDesc.dwMaxTextureWidth; DWORD dwMaxHeight = ddDesc.dwMaxTextureHeight; ddsd.dwWidth = min(ddsd.dwWidth, (dwMaxWidth ? dwMaxWidth : 256)); ddsd.dwHeight = min(ddsd.dwHeight, (dwMaxHeight ? dwMaxHeight : 256));
// Make the texture square, if the driver requires it
if (ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY) { if (ddsd.dwWidth > ddsd.dwHeight) ddsd.dwHeight = ddsd.dwWidth; else ddsd.dwWidth = ddsd.dwHeight; }
// Setup the structure to be used for texture enumration.
TEXTURESEARCHINFO tsi; tsi.bFoundGoodFormat = FALSE; tsi.pddpf = &ddsd.ddpfPixelFormat; tsi.dwDesiredBPP = m_dwBPP; tsi.bUsePalette = (m_dwBPP <= 8); tsi.bUseAlpha = m_bHasAlpha; if (m_dwFlags & D3DTEXTR_16BITSPERPIXEL) tsi.dwDesiredBPP = 16; else if (m_dwFlags & D3DTEXTR_32BITSPERPIXEL) tsi.dwDesiredBPP = 32;
if (m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK)) { if (tsi.bUsePalette) { if (ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_ALPHAPALETTE) { tsi.bUseAlpha = TRUE; tsi.bUsePalette = TRUE; } else { tsi.bUseAlpha = TRUE; tsi.bUsePalette = FALSE; } } }
// Enumerate the texture formats, and find the closest device-supported
// texture pixel format
pd3dDevice->EnumTextureFormats(TextureSearchCallback, &tsi);
// If we couldn't find a format, let's try a default format
if (FALSE == tsi.bFoundGoodFormat) { tsi.bUsePalette = FALSE; tsi.dwDesiredBPP = 16; pd3dDevice->EnumTextureFormats(TextureSearchCallback, &tsi);
// If we still fail, we cannot create this texture
if (FALSE == tsi.bFoundGoodFormat) return E_FAIL; }
// Get the DirectDraw interface for creating surfaces
LPDIRECTDRAW7 pDD; LPDIRECTDRAWSURFACE7 pddsRender; pd3dDevice->GetRenderTarget(&pddsRender); pddsRender->GetDDInterface((VOID**)&pDD); pddsRender->Release();
// Create a new surface for the texture
HRESULT hr = pDD->CreateSurface(&ddsd, &m_pddsSurface, NULL);
// Done with DDraw
pDD->Release();
if (FAILED(hr)) return hr;
// For bitmap-based textures, copy the bitmap image.
if (m_hbmBitmap) return CopyBitmapToSurface();
if (m_pRGBAData) return CopyRGBADataToSurface();
// At this point, code can be added to handle other file formats (such as
// .dds files, .jpg files, etc.).
return S_OK; }
//-----------------------------------------------------------------------------
// Name: CopyBitmapToSurface()
// Desc: Copies the image of a bitmap into a surface
//-----------------------------------------------------------------------------
HRESULT TextureContainer::CopyBitmapToSurface() { // Get a DDraw object to create a temporary surface
LPDIRECTDRAW7 pDD; m_pddsSurface->GetDDInterface((VOID**)&pDD);
// Get the bitmap structure (to extract width, height, and bpp)
BITMAP bm; GetObject(m_hbmBitmap, sizeof(BITMAP), &bm);
// Setup the new surface desc
DDSURFACEDESC2 ddsd; ddsd.dwSize = sizeof(ddsd); m_pddsSurface->GetSurfaceDesc(&ddsd); ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT| DDSD_TEXTURESTAGE; ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE|DDSCAPS_SYSTEMMEMORY; ddsd.ddsCaps.dwCaps2 = 0L; ddsd.dwWidth = bm.bmWidth; ddsd.dwHeight = bm.bmHeight;
// Create a new surface for the texture
LPDIRECTDRAWSURFACE7 pddsTempSurface; HRESULT hr; if (FAILED(hr = pDD->CreateSurface(&ddsd, &pddsTempSurface, NULL))) { pDD->Release(); return hr; }
// Get a DC for the bitmap
HDC hdcBitmap = CreateCompatibleDC(NULL); if (NULL == hdcBitmap) { pddsTempSurface->Release(); pDD->Release(); return hr; } SelectObject(hdcBitmap, m_hbmBitmap);
// Handle palettized textures. Need to attach a palette
if (ddsd.ddpfPixelFormat.dwRGBBitCount == 8) { LPDIRECTDRAWPALETTE pPalette; DWORD dwPaletteFlags = DDPCAPS_8BIT|DDPCAPS_ALLOW256; DWORD pe[256]; WORD wNumColors = (WORD) GetDIBColorTable(hdcBitmap, 0, 256, (RGBQUAD*)pe);
// Create the color table
for(WORD i=0; i<wNumColors; i++) { pe[i] = RGB(GetBValue(pe[i]), GetGValue(pe[i]), GetRValue(pe[i]));
// Handle textures with transparent pixels
if (m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK)) { // Set alpha for opaque pixels
if (m_dwFlags & D3DTEXTR_TRANSPARENTBLACK) { if (pe[i] != 0x00000000) pe[i] |= 0xff000000; } else if (m_dwFlags & D3DTEXTR_TRANSPARENTWHITE) { if (pe[i] != 0x00ffffff) pe[i] |= 0xff000000; } } } // Add DDPCAPS_ALPHA flag for textures with transparent pixels
if (m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK)) dwPaletteFlags |= DDPCAPS_ALPHA;
// Create & attach a palette
pDD->CreatePalette(dwPaletteFlags, (PALETTEENTRY*)pe, &pPalette, NULL); pddsTempSurface->SetPalette(pPalette); m_pddsSurface->SetPalette(pPalette); SAFE_RELEASE(pPalette); }
// Copy the bitmap image to the surface.
HDC hdcSurface; if (SUCCEEDED(pddsTempSurface->GetDC(&hdcSurface))) { BitBlt(hdcSurface, 0, 0, bm.bmWidth, bm.bmHeight, hdcBitmap, 0, 0, SRCCOPY); pddsTempSurface->ReleaseDC(hdcSurface); } DeleteDC(hdcBitmap);
// Copy the temp surface to the real texture surface
m_pddsSurface->Blt(NULL, pddsTempSurface, NULL, DDBLT_WAIT, NULL);
// Done with the temp surface
pddsTempSurface->Release();
// For textures with real alpha (not palettized), set transparent bits
if (ddsd.ddpfPixelFormat.dwRGBAlphaBitMask) { if (m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK)) { // Lock the texture surface
DDSURFACEDESC2 ddsd; ddsd.dwSize = sizeof(ddsd); while(m_pddsSurface->Lock(NULL, &ddsd, 0, NULL) == DDERR_WASSTILLDRAWING);
DWORD dwAlphaMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask; DWORD dwRGBMask = (ddsd.ddpfPixelFormat.dwRBitMask | ddsd.ddpfPixelFormat.dwGBitMask | ddsd.ddpfPixelFormat.dwBBitMask); DWORD dwColorkey = 0x00000000; // Colorkey on black
if (m_dwFlags & D3DTEXTR_TRANSPARENTWHITE) dwColorkey = dwRGBMask; // Colorkey on white
// Add an opaque alpha value to each non-colorkeyed pixel
for(DWORD y=0; y<ddsd.dwHeight; y++) { WORD* p16 = (WORD*)((BYTE*)ddsd.lpSurface + y*ddsd.lPitch); DWORD* p32 = (DWORD*)((BYTE*)ddsd.lpSurface + y*ddsd.lPitch);
for(DWORD x=0; x<ddsd.dwWidth; x++) { if (ddsd.ddpfPixelFormat.dwRGBBitCount == 16) { if ((*p16 &= dwRGBMask) != dwColorkey) *p16 |= dwAlphaMask; p16++; } if (ddsd.ddpfPixelFormat.dwRGBBitCount == 32) { if ((*p32 &= dwRGBMask) != dwColorkey) *p32 |= dwAlphaMask; p32++; } } } m_pddsSurface->Unlock(NULL); } }
pDD->Release();
return S_OK;; }
//-----------------------------------------------------------------------------
// Name: CopyRGBADataToSurface()
// Desc: Invalidates the current texture objects and rebuilds new ones
// using the new device.
//-----------------------------------------------------------------------------
HRESULT TextureContainer::CopyRGBADataToSurface() { // Get a DDraw object to create a temporary surface
LPDIRECTDRAW7 pDD; m_pddsSurface->GetDDInterface((VOID**)&pDD);
// Setup the new surface desc
DDSURFACEDESC2 ddsd; ddsd.dwSize = sizeof(ddsd); m_pddsSurface->GetSurfaceDesc(&ddsd); ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT| DDSD_TEXTURESTAGE; ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE|DDSCAPS_SYSTEMMEMORY; ddsd.ddsCaps.dwCaps2 = 0L; ddsd.dwWidth = m_dwWidth; ddsd.dwHeight = m_dwHeight;
// Create a new surface for the texture
LPDIRECTDRAWSURFACE7 pddsTempSurface; HRESULT hr; if (FAILED(hr = pDD->CreateSurface(&ddsd, &pddsTempSurface, NULL))) { pDD->Release(); return NULL; }
while(pddsTempSurface->Lock(NULL, &ddsd, 0, 0) == DDERR_WASSTILLDRAWING); DWORD lPitch = ddsd.lPitch; BYTE* pBytes = (BYTE*)ddsd.lpSurface;
DWORD dwRMask = ddsd.ddpfPixelFormat.dwRBitMask; DWORD dwGMask = ddsd.ddpfPixelFormat.dwGBitMask; DWORD dwBMask = ddsd.ddpfPixelFormat.dwBBitMask; DWORD dwAMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask;
DWORD dwRShiftL = 8, dwRShiftR = 0; DWORD dwGShiftL = 8, dwGShiftR = 0; DWORD dwBShiftL = 8, dwBShiftR = 0; DWORD dwAShiftL = 8, dwAShiftR = 0;
DWORD dwMask; for(dwMask=dwRMask; dwMask && !(dwMask&0x1); dwMask>>=1) dwRShiftR++; for(; dwMask; dwMask>>=1) dwRShiftL--;
for(dwMask=dwGMask; dwMask && !(dwMask&0x1); dwMask>>=1) dwGShiftR++; for(; dwMask; dwMask>>=1) dwGShiftL--;
for(dwMask=dwBMask; dwMask && !(dwMask&0x1); dwMask>>=1) dwBShiftR++; for(; dwMask; dwMask>>=1) dwBShiftL--;
for(dwMask=dwAMask; dwMask && !(dwMask&0x1); dwMask>>=1) dwAShiftR++; for(; dwMask; dwMask>>=1) dwAShiftL--;
for(DWORD y=0; y<ddsd.dwHeight; y++) { DWORD* pDstData32 = (DWORD*)pBytes; WORD* pDstData16 = (WORD*)pBytes;
for(DWORD x=0; x<ddsd.dwWidth; x++) { DWORD dwPixel = m_pRGBAData[y*ddsd.dwWidth+x];
BYTE r = (BYTE)((dwPixel>>24)&0x000000ff); BYTE g = (BYTE)((dwPixel>>16)&0x000000ff); BYTE b = (BYTE)((dwPixel>> 8)&0x000000ff); BYTE a = (BYTE)((dwPixel>> 0)&0x000000ff);
DWORD dr = ((r>>(dwRShiftL))<<dwRShiftR)&dwRMask; DWORD dg = ((g>>(dwGShiftL))<<dwGShiftR)&dwGMask; DWORD db = ((b>>(dwBShiftL))<<dwBShiftR)&dwBMask; DWORD da = ((a>>(dwAShiftL))<<dwAShiftR)&dwAMask;
if (32 == ddsd.ddpfPixelFormat.dwRGBBitCount) pDstData32[x] = (DWORD)(dr+dg+db+da); else pDstData16[x] = (WORD)(dr+dg+db+da); } pBytes += ddsd.lPitch; }
pddsTempSurface->Unlock(0);
// Copy the temp surface to the real texture surface
m_pddsSurface->Blt(NULL, pddsTempSurface, NULL, DDBLT_WAIT, NULL);
// Done with the temp objects
pddsTempSurface->Release(); pDD->Release();
return S_OK; }
//-----------------------------------------------------------------------------
// Name: D3DTextr_SetTexturePath()
// Desc: Enumeration callback routine to find a best-matching texture format.
//-----------------------------------------------------------------------------
VOID D3DTextr_SetTexturePath(TCHAR* strTexturePath) { if (NULL == strTexturePath) strTexturePath[0] = 0; lstrcpy(g_strTexturePath, strTexturePath); }
//-----------------------------------------------------------------------------
// Name: D3DTextr_CreateTextureFromFile()
// Desc: Is passed a filename and creates a local Bitmap from that file.
// The texture can not be used until it is restored, however.
//-----------------------------------------------------------------------------
HRESULT D3DTextr_CreateTextureFromFile(TCHAR* strName, DWORD dwStage, DWORD dwFlags) { // Check parameters
if (NULL == strName) return E_INVALIDARG;
// Check first to see if the texture is already loaded
if (NULL != FindTexture(strName)) return S_OK;
// Allocate and add the texture to the linked list of textures;
TextureContainer* ptcTexture = new TextureContainer(strName, dwStage, dwFlags); if (NULL == ptcTexture) return E_OUTOFMEMORY;
// Create a bitmap and load the texture file into it,
if (FAILED(ptcTexture->LoadImageData())) { delete ptcTexture; return E_FAIL; }
// Save the image's dimensions
if (ptcTexture->m_hbmBitmap) { BITMAP bm; GetObject(ptcTexture->m_hbmBitmap, sizeof(BITMAP), &bm); ptcTexture->m_dwWidth = (DWORD)bm.bmWidth; ptcTexture->m_dwHeight = (DWORD)bm.bmHeight; ptcTexture->m_dwBPP = (DWORD)bm.bmBitsPixel; }
return S_OK; }
//-----------------------------------------------------------------------------
// Name: D3DTextr_CreateEmptyTexture()
// Desc: Creates an empty texture.
//-----------------------------------------------------------------------------
HRESULT D3DTextr_CreateEmptyTexture(TCHAR* strName, DWORD dwWidth, DWORD dwHeight, DWORD dwStage, DWORD dwFlags) { // Check parameters
if (NULL == strName) return E_INVALIDARG;
// Check first to see if the texture is already loaded
if (NULL != FindTexture(strName)) return E_FAIL;
// Allocate and add the texture to the linked list of textures;
TextureContainer* ptcTexture = new TextureContainer(strName, dwStage, dwFlags); if (NULL == ptcTexture) return E_OUTOFMEMORY;
// Save dimensions
ptcTexture->m_dwWidth = dwWidth; ptcTexture->m_dwHeight = dwHeight; ptcTexture->m_dwBPP = 16; if (ptcTexture->m_dwFlags & D3DTEXTR_32BITSPERPIXEL) ptcTexture->m_dwBPP = 32;
// Save alpha usage flag
if (dwFlags & D3DTEXTR_CREATEWITHALPHA) ptcTexture->m_bHasAlpha = TRUE;
return S_OK; }
//-----------------------------------------------------------------------------
// Name: D3DTextr_Restore()
// Desc: Invalidates the current texture objects and rebuilds new ones
// using the new device.
//-----------------------------------------------------------------------------
HRESULT D3DTextr_Restore(TCHAR* strName, LPDIRECT3DDEVICE7 pd3dDevice) { TextureContainer* ptcTexture = FindTexture(strName); if (NULL == ptcTexture) return DDERR_NOTFOUND;
// Restore the texture (this recreates the new surface for this device).
return ptcTexture->Restore(pd3dDevice); }
//-----------------------------------------------------------------------------
// Name: D3DTextr_RestoreAllTextures()
// Desc: This function is called when a mode is changed. It updates all
// texture objects to be valid with the new device.
//-----------------------------------------------------------------------------
HRESULT D3DTextr_RestoreAllTextures(LPDIRECT3DDEVICE7 pd3dDevice) { TextureContainer* ptcTexture = g_ptcTextureList;
while(ptcTexture) { D3DTextr_Restore(ptcTexture->m_strName, pd3dDevice); ptcTexture = ptcTexture->m_pNext; }
return S_OK; }
//-----------------------------------------------------------------------------
// Name: D3DTextr_Invalidate()
// Desc: Used to bump a texture out of (video) memory, this function
// actually destroys the d3dtexture and ddsurface of the texture
//-----------------------------------------------------------------------------
HRESULT D3DTextr_Invalidate(TCHAR* strName) { TextureContainer* ptcTexture = FindTexture(strName); if (NULL == ptcTexture) return DDERR_NOTFOUND;
SAFE_RELEASE(ptcTexture->m_pddsSurface);
return S_OK; }
//-----------------------------------------------------------------------------
// Name: D3DTextr_InvalidateAllTextures()
// Desc: This function is called when a mode is changed. It invalidates
// all texture objects so their device can be safely released.
//-----------------------------------------------------------------------------
HRESULT D3DTextr_InvalidateAllTextures() { TextureContainer* ptcTexture = g_ptcTextureList;
while(ptcTexture) { SAFE_RELEASE(ptcTexture->m_pddsSurface); ptcTexture = ptcTexture->m_pNext; }
return S_OK; }
//-----------------------------------------------------------------------------
// Name: D3DTextr_DestroyTexture()
// Desc: Frees the resources for the specified texture container
//-----------------------------------------------------------------------------
HRESULT D3DTextr_DestroyTexture(TCHAR* strName) { TextureContainer* ptcTexture = FindTexture(strName);
SAFE_DELETE(ptcTexture);
return S_OK; }
//-----------------------------------------------------------------------------
// Name: D3DTextr_GetSurface()
// Desc: Returns a pointer to a d3dSurface from the name of the texture
//-----------------------------------------------------------------------------
LPDIRECTDRAWSURFACE7 D3DTextr_GetSurface(TCHAR* strName) { TextureContainer* ptcTexture = FindTexture(strName);
return ptcTexture ? ptcTexture->m_pddsSurface : NULL; }
|