1043 lines
33 KiB
C++
1043 lines
33 KiB
C++
//-----------------------------------------------------------------------------
|
|
// 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;
|
|
}
|
|
|
|
|
|
|
|
|