307 lines
8.3 KiB
C++
307 lines
8.3 KiB
C++
|
#ifndef __TEXTURE_HPP__
|
||
|
#define __TEXTURE_HPP__
|
||
|
|
||
|
/*==========================================================================;
|
||
|
*
|
||
|
* Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
|
||
|
*
|
||
|
* File: texture.h
|
||
|
* Content: Base class for all texture objects. Texture management is
|
||
|
* done at this level.
|
||
|
*
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
|
||
|
// The mip texture class has all of the functionality of the
|
||
|
// the Base Object class along with some additional state for
|
||
|
// managing LODs.
|
||
|
#include <limits.h>
|
||
|
#include "resource.hpp"
|
||
|
#include "pixel.hpp"
|
||
|
|
||
|
#define __INVALIDPALETTE USHRT_MAX
|
||
|
|
||
|
class CBaseTexture : public IDirect3DBaseTexture8, public CResource
|
||
|
{
|
||
|
public:
|
||
|
// Constructor
|
||
|
CBaseTexture(
|
||
|
CBaseDevice *pDevice,
|
||
|
DWORD cLevels,
|
||
|
D3DPOOL UserPool,
|
||
|
D3DFORMAT UserFormat,
|
||
|
REF_TYPE refType);
|
||
|
|
||
|
// Function to convert a IDirect3DBaseTexture8 * to
|
||
|
// a CBaseTexture *.
|
||
|
static CBaseTexture *SafeCast(IDirect3DBaseTexture8 *pInterface);
|
||
|
|
||
|
// Returns the format that the user passed in
|
||
|
D3DFORMAT GetUserFormat() const
|
||
|
{
|
||
|
return m_formatUser;
|
||
|
} // GetUserFormat
|
||
|
|
||
|
BOOL IsPaletted() const
|
||
|
{
|
||
|
DXGASSERT(GetBufferDesc()->Format == GetUserFormat());
|
||
|
return CPixel::IsPaletted(GetUserFormat());
|
||
|
}
|
||
|
|
||
|
// Returns the current palette
|
||
|
DWORD GetPalette() const
|
||
|
{
|
||
|
DXGASSERT(GetBufferDesc()->Format == GetUserFormat());
|
||
|
DXGASSERT(CPixel::IsPaletted(GetUserFormat()));
|
||
|
return m_Palette;
|
||
|
} // GetPalette
|
||
|
|
||
|
// Set the current palette
|
||
|
void SetPalette(DWORD Palette)
|
||
|
{
|
||
|
DXGASSERT(GetBufferDesc()->Format == GetUserFormat());
|
||
|
#if DBG
|
||
|
if(Palette != __INVALIDPALETTE)
|
||
|
{
|
||
|
DXGASSERT(CPixel::IsPaletted(GetUserFormat()));
|
||
|
}
|
||
|
#endif
|
||
|
DXGASSERT(Palette <= USHRT_MAX);
|
||
|
m_Palette = (WORD)Palette;
|
||
|
} // SetPalette
|
||
|
|
||
|
// Return current LOD
|
||
|
DWORD GetLODI() const
|
||
|
{
|
||
|
return m_LOD;
|
||
|
}
|
||
|
|
||
|
// Sets current LOD (but doesn't actually do any work)
|
||
|
DWORD SetLODI(DWORD LOD)
|
||
|
{
|
||
|
DXGASSERT(LOD <= UCHAR_MAX);
|
||
|
DWORD oldLOD = m_LOD;
|
||
|
m_LOD = (BYTE)LOD;
|
||
|
return oldLOD;
|
||
|
}
|
||
|
|
||
|
// Method for UpdateTexture to call; does type-specific
|
||
|
// parameter checking before calling UpdateDirtyPortion
|
||
|
virtual HRESULT UpdateTexture(CBaseTexture *pTextureTarget) PURE;
|
||
|
|
||
|
// Parameter validation method to make sure that no part of
|
||
|
// the texture is locked.
|
||
|
#ifdef DEBUG
|
||
|
virtual BOOL IsTextureLocked() PURE;
|
||
|
#endif // DEBUG
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
// DPF helper for explaining why lock failed
|
||
|
void ReportWhyLockFailed(void) const;
|
||
|
#else // !DEBUG
|
||
|
void ReportWhyLockFailed(void) const
|
||
|
{
|
||
|
// Do Nothing In Retail
|
||
|
} // ReportWhyLockFailed
|
||
|
#endif // !DEBUG
|
||
|
|
||
|
protected:
|
||
|
|
||
|
// Remember the format that the user passed in
|
||
|
D3DFORMAT m_formatUser;
|
||
|
|
||
|
// Currently all textures have a number of levels;
|
||
|
// If that changes, then we should create a derived
|
||
|
// class CMipTexture and move this data member there.
|
||
|
BYTE m_cLevels;
|
||
|
|
||
|
// Contains the current LOD for D3D managed textures
|
||
|
BYTE m_LOD;
|
||
|
|
||
|
// Currently set palette (valid only if format is paletted)
|
||
|
WORD m_Palette;
|
||
|
|
||
|
// Level Count accessor
|
||
|
DWORD GetLevelCountImpl() const
|
||
|
{
|
||
|
return m_cLevels;
|
||
|
}; // GetLevelCountImpl
|
||
|
|
||
|
// Function to verify external parameters
|
||
|
// to various texture create APIs
|
||
|
static HRESULT Validate(CBaseDevice *pDevice,
|
||
|
D3DRESOURCETYPE Type,
|
||
|
D3DPOOL Pool,
|
||
|
DWORD Usage,
|
||
|
D3DFORMAT Format);
|
||
|
|
||
|
// Infer usage flags based on external parameters
|
||
|
// (All inferences MUST be device-independent.)
|
||
|
static DWORD InferUsageFlags(D3DPOOL Pool,
|
||
|
DWORD Usage,
|
||
|
D3DFORMAT Format);
|
||
|
|
||
|
// Helper to check if TexBlt is support on this
|
||
|
// device for this texture
|
||
|
BOOL CanTexBlt(CBaseTexture *pDestTexture) const;
|
||
|
|
||
|
// Helper function to scale a Rect down by some
|
||
|
// number of powers of two; useful for figuring out
|
||
|
// what part of mip-sub-levels to copy
|
||
|
static void ScaleRectDown(RECT *pRect, UINT PowersOfTwo = 1);
|
||
|
|
||
|
// Box version for volumes
|
||
|
static void ScaleBoxDown(D3DBOX *pBox, UINT PowersOfTwo = 1);
|
||
|
|
||
|
// Compute Levels for the user
|
||
|
static UINT ComputeLevels(UINT width, UINT height = 0, UINT depth = 0);
|
||
|
|
||
|
// Common implementation for Set/Get LOD.
|
||
|
DWORD SetLODImpl(DWORD LOD);
|
||
|
DWORD GetLODImpl();
|
||
|
|
||
|
private:
|
||
|
|
||
|
// Textures overload this to call OnTextureDestroy on the
|
||
|
// Device before calling Sync.
|
||
|
virtual void OnDestroy(void);
|
||
|
|
||
|
}; // class CBaseTexture
|
||
|
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CBaseTexture::CBaseTexture"
|
||
|
|
||
|
|
||
|
// Inlines
|
||
|
inline CBaseTexture::CBaseTexture(
|
||
|
CBaseDevice *pDevice,
|
||
|
DWORD cLevels,
|
||
|
D3DPOOL UserPool,
|
||
|
D3DFORMAT UserFormat,
|
||
|
REF_TYPE refType)
|
||
|
:
|
||
|
CResource(pDevice, UserPool, refType),
|
||
|
m_cLevels((BYTE)cLevels),
|
||
|
m_Palette(__INVALIDPALETTE),
|
||
|
m_formatUser(UserFormat)
|
||
|
{
|
||
|
DXGASSERT(cLevels > 0 && cLevels < 256);
|
||
|
}; // CBaseTexture::CBaseTexture
|
||
|
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CBaseTexture::SafeCast"
|
||
|
|
||
|
// Function to convert a IDirect3DBaseTexture8 * to
|
||
|
// a CBaseTexture *. Classes that expose IDirect3DBaseTexture8
|
||
|
// must list CBaseTexture FIRST and IDirect3DFoo8*
|
||
|
// SECOND in their list of inheritances. (The Foo8 interface
|
||
|
// must itself inherit from IDirect3DBaseTexture8*.
|
||
|
inline CBaseTexture * CBaseTexture::SafeCast(IDirect3DBaseTexture8 *pInterface)
|
||
|
{
|
||
|
if (pInterface == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
// Textures must by law obey certain layout rules. In
|
||
|
// particular the CBaseTexture object must reside precisely
|
||
|
// before the IDirect3DBaseTexture8 interface
|
||
|
BYTE *pbInt = reinterpret_cast<BYTE *>(pInterface);
|
||
|
CBaseTexture *pTex = reinterpret_cast<CBaseTexture *>(pbInt - sizeof(CBaseTexture));
|
||
|
return pTex;
|
||
|
} // CBaseTexture::SafeCast
|
||
|
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CBaseTexture::ScaleRectDown"
|
||
|
|
||
|
// We round down on for left and top; and we round up for
|
||
|
// right and bottom
|
||
|
inline void CBaseTexture::ScaleRectDown(RECT *pRect, UINT PowersOfTwo)
|
||
|
{
|
||
|
DXGASSERT(PowersOfTwo > 0);
|
||
|
DXGASSERT(PowersOfTwo < 32);
|
||
|
DXGASSERT(pRect->right > 0);
|
||
|
DXGASSERT(pRect->bottom > 0);
|
||
|
DXGASSERT(pRect->left < pRect->right);
|
||
|
DXGASSERT(pRect->top < pRect->bottom);
|
||
|
DXGASSERT(pRect->left >= 0);
|
||
|
DXGASSERT(pRect->top >= 0);
|
||
|
|
||
|
// Rounding down is automatic with the shift operator
|
||
|
pRect->left >>= PowersOfTwo;
|
||
|
pRect->top >>= PowersOfTwo;
|
||
|
|
||
|
if (pRect->right & ((1 << PowersOfTwo) - 1))
|
||
|
{
|
||
|
pRect->right >>= PowersOfTwo;
|
||
|
pRect->right++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pRect->right >>= PowersOfTwo;
|
||
|
}
|
||
|
|
||
|
if (pRect->bottom & ((1 << PowersOfTwo) - 1))
|
||
|
{
|
||
|
pRect->bottom >>= PowersOfTwo;
|
||
|
pRect->bottom++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pRect->bottom >>= PowersOfTwo;
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
} // CBaseTexture::ScaleRectDown
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CBaseTexture::ScaleBoxDown"
|
||
|
|
||
|
inline void CBaseTexture::ScaleBoxDown(D3DBOX *pBox, UINT PowersOfTwo)
|
||
|
{
|
||
|
DXGASSERT(pBox);
|
||
|
DXGASSERT(pBox->Front < pBox->Back);
|
||
|
DXGASSERT(pBox->Back > 0);
|
||
|
|
||
|
ScaleRectDown((RECT*)pBox, PowersOfTwo);
|
||
|
|
||
|
// Rounding down is automatic with the shift operator
|
||
|
pBox->Front >>= PowersOfTwo;
|
||
|
if (pBox->Back & ((1 << PowersOfTwo) - 1))
|
||
|
{
|
||
|
pBox->Back >>= PowersOfTwo;
|
||
|
pBox->Back++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pBox->Back >>= PowersOfTwo;
|
||
|
}
|
||
|
|
||
|
} // CBaseTexture::ScaleBoxDown
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CBaseTexture::ComputeLevels"
|
||
|
|
||
|
inline UINT CBaseTexture::ComputeLevels(UINT width,
|
||
|
UINT height, // = 0,
|
||
|
UINT depth // = 0
|
||
|
)
|
||
|
{
|
||
|
UINT maxEdge = max(width, height);
|
||
|
maxEdge = max(maxEdge, depth);
|
||
|
|
||
|
UINT cLevels = 0;
|
||
|
while (maxEdge)
|
||
|
{
|
||
|
cLevels++;
|
||
|
|
||
|
// D3D rule is that sizes round down always
|
||
|
maxEdge >>= 1;
|
||
|
}
|
||
|
|
||
|
return cLevels;
|
||
|
} // CBaseTexture::ComputeLevels
|
||
|
|
||
|
#endif // __TEXTURE_HPP__
|