This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2020-08-04 13:13:01 -04:00

1703 lines
65 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// dxabstract.h
//
//==================================================================================================
#ifndef DXABSTRACT_H
#define DXABSTRACT_H
#ifdef DX_TO_GL_ABSTRACTION
#include "togl/rendermechanism.h"
#include "tier0/dbg.h"
#include "tier0/platform.h"
#include "tier1/utlmap.h"
// turn this on to get refcount logging from IUnknown
#define IUNKNOWN_ALLOC_SPEW 0
#define IUNKNOWN_ALLOC_SPEW_MARK_ALL 0
TOGL_INTERFACE void toglGetClientRect(VD3DHWND hWnd, RECT* destRect);
struct TOGL_CLASS IUnknown {
int m_refcount[2];
bool m_mark;
IUnknown() {
m_refcount[0] = 1;
m_refcount[1] = 0;
m_mark = (IUNKNOWN_ALLOC_SPEW_MARK_ALL !=
0); // either all are marked, or only the ones that have
// SetMark(true) called on them
#if IUNKNOWN_ALLOC_SPEW
if (m_mark) {
GLMPRINTF(("-A- IUnew (%08x) refc -> (%d,%d) ", this, m_refcount[0],
m_refcount[1]));
}
#endif
};
virtual ~IUnknown() {
#if IUNKNOWN_ALLOC_SPEW
if (m_mark) {
GLMPRINTF(("-A- IUdel (%08x) ", this));
}
#endif
};
void AddRef(int which = 0, char* comment = NULL) {
Assert(which >= 0);
Assert(which < 2);
m_refcount[which]++;
#if IUNKNOWN_ALLOC_SPEW
if (m_mark) {
GLMPRINTF(("-A- IUAddRef (%08x,%d) refc -> (%d,%d) [%s]", this,
which, m_refcount[0], m_refcount[1],
comment ? comment : "..."));
if (!comment) {
GLMPRINTF(("")); // place to hang a breakpoint
}
}
#endif
};
ULONG __stdcall Release(int which = 0, char* comment = NULL) {
Assert(which >= 0);
Assert(which < 2);
// int oldrefcs[2] = { m_refcount[0], m_refcount[1] };
bool deleting = false;
m_refcount[which]--;
if ((!m_refcount[0]) && (!m_refcount[1])) {
deleting = true;
}
#if IUNKNOWN_ALLOC_SPEW
if (m_mark) {
GLMPRINTF(("-A- IURelease (%08x,%d) refc -> (%d,%d) [%s] %s", this,
which, m_refcount[0], m_refcount[1],
comment ? comment : "...",
deleting ? "->DELETING" : ""));
if (!comment) {
GLMPRINTF(("")); // place to hang a breakpoint
}
}
#endif
if (deleting) {
if (m_mark) {
GLMPRINTF(("")); // place to hang a breakpoint
}
delete this;
return 0;
} else {
return m_refcount[0];
}
};
void SetMark(bool markValue, char* comment = NULL) {
#if IUNKNOWN_ALLOC_SPEW
if (!m_mark && markValue) // leading edge detect
{
// print the same thing that the constructor would have printed if
// it had been marked from the beginning i.e. it's anticipated that
// callers asking for marking will do so right at create time
GLMPRINTF(("-A- IUSetMark (%08x) refc -> (%d,%d) (%s) ", this,
m_refcount[0], m_refcount[1],
comment ? comment : "..."));
}
#endif
m_mark = markValue;
}
};
// ------------------------------------------------------------------------------------------------------------------------------
// // INTERFACES
// ------------------------------------------------------------------------------------------------------------------------------
// //
struct TOGL_CLASS IDirect3DResource9 : public IUnknown {
IDirect3DDevice9* m_device; // parent device
D3DRESOURCETYPE m_restype;
DWORD SetPriority(DWORD PriorityNew);
};
struct TOGL_CLASS IDirect3DBaseTexture9
: public IDirect3DResource9 // "A Texture.."
{
D3DSURFACE_DESC m_descZero; // desc of top level.
CGLMTex* m_tex; // a CGLMTex can represent all forms of tex
virtual ~IDirect3DBaseTexture9();
D3DRESOURCETYPE TOGLMETHODCALLTYPE GetType();
DWORD TOGLMETHODCALLTYPE GetLevelCount();
HRESULT TOGLMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc);
};
struct TOGL_CLASS IDirect3DTexture9
: public IDirect3DBaseTexture9 // "Texture 2D"
{
IDirect3DSurface9* m_surfZero; // surf of top level.
virtual ~IDirect3DTexture9();
HRESULT TOGLMETHODCALLTYPE LockRect(UINT Level, D3DLOCKED_RECT* pLockedRect,
CONST RECT* pRect, DWORD Flags);
HRESULT TOGLMETHODCALLTYPE UnlockRect(UINT Level);
HRESULT TOGLMETHODCALLTYPE
GetSurfaceLevel(UINT Level, IDirect3DSurface9** ppSurfaceLevel);
};
struct TOGL_CLASS IDirect3DCubeTexture9
: public IDirect3DBaseTexture9 // "Texture Cube Map"
{
IDirect3DSurface9* m_surfZero[6]; // surfs of top level.
virtual ~IDirect3DCubeTexture9();
HRESULT TOGLMETHODCALLTYPE
GetCubeMapSurface(D3DCUBEMAP_FACES FaceType, UINT Level,
IDirect3DSurface9** ppCubeMapSurface);
HRESULT TOGLMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC* pDesc);
};
struct TOGL_CLASS IDirect3DVolumeTexture9
: public IDirect3DBaseTexture9 // "Texture 3D"
{
IDirect3DSurface9* m_surfZero; // surf of top level.
D3DVOLUME_DESC m_volDescZero; // volume desc top level
virtual ~IDirect3DVolumeTexture9();
HRESULT TOGLMETHODCALLTYPE LockBox(UINT Level, D3DLOCKED_BOX* pLockedVolume,
CONST D3DBOX* pBox, DWORD Flags);
HRESULT TOGLMETHODCALLTYPE UnlockBox(UINT Level);
HRESULT TOGLMETHODCALLTYPE GetLevelDesc(UINT level, D3DVOLUME_DESC* pDesc);
};
// for the moment, a "D3D surface" is modeled as a GLM tex, a face, and a mip.
// no Create method, these are filled in by the various create surface methods.
struct TOGL_CLASS IDirect3DSurface9 : public IDirect3DResource9 {
virtual ~IDirect3DSurface9();
HRESULT TOGLMETHODCALLTYPE LockRect(D3DLOCKED_RECT* pLockedRect,
CONST RECT* pRect, DWORD Flags);
HRESULT TOGLMETHODCALLTYPE UnlockRect();
HRESULT TOGLMETHODCALLTYPE GetDesc(D3DSURFACE_DESC* pDesc);
D3DSURFACE_DESC m_desc;
CGLMTex* m_tex;
int m_face;
int m_mip;
};
struct TOGL_CLASS IDirect3D9 : public IUnknown {
virtual ~IDirect3D9();
UINT TOGLMETHODCALLTYPE GetAdapterCount();
HRESULT TOGLMETHODCALLTYPE GetDeviceCaps(UINT Adapter,
D3DDEVTYPE DeviceType,
D3DCAPS9* pCaps);
HRESULT TOGLMETHODCALLTYPE GetAdapterIdentifier(
UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9* pIdentifier);
HRESULT TOGLMETHODCALLTYPE CheckDeviceFormat(
UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat,
DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat);
UINT TOGLMETHODCALLTYPE GetAdapterModeCount(UINT Adapter, D3DFORMAT Format);
HRESULT TOGLMETHODCALLTYPE EnumAdapterModes(UINT Adapter, D3DFORMAT Format,
UINT Mode,
D3DDISPLAYMODE* pMode);
HRESULT TOGLMETHODCALLTYPE CheckDeviceType(UINT Adapter, D3DDEVTYPE DevType,
D3DFORMAT AdapterFormat,
D3DFORMAT BackBufferFormat,
BOOL bWindowed);
HRESULT TOGLMETHODCALLTYPE GetAdapterDisplayMode(UINT Adapter,
D3DDISPLAYMODE* pMode);
HRESULT TOGLMETHODCALLTYPE CheckDepthStencilMatch(
UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat,
D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat);
HRESULT TOGLMETHODCALLTYPE CheckDeviceMultiSampleType(
UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat,
BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType,
DWORD* pQualityLevels);
HRESULT TOGLMETHODCALLTYPE CreateDevice(
UINT Adapter, D3DDEVTYPE DeviceType, VD3DHWND hFocusWindow,
DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters,
IDirect3DDevice9** ppReturnedDeviceInterface);
};
struct TOGL_CLASS IDirect3DVertexDeclaration9 : public IUnknown {
IDirect3DDevice9* m_device;
uint m_elemCount;
D3DVERTEXELEMENT9_GL m_elements[MAX_D3DVERTEXELEMENTS];
uint8 m_VertexAttribDescToStreamIndex[256];
virtual ~IDirect3DVertexDeclaration9();
};
struct TOGL_CLASS IDirect3DQuery9 : public IDirect3DResource9 // was IUnknown
{
D3DQUERYTYPE m_type; // D3DQUERYTYPE_OCCLUSION or D3DQUERYTYPE_EVENT
GLMContext* m_ctx;
CGLMQuery* m_query;
uint m_nIssueStartThreadID, m_nIssueEndThreadID;
uint m_nIssueStartDrawCallIndex, m_nIssueEndDrawCallIndex;
uint m_nIssueStartFrameIndex, m_nIssueEndFrameIndex;
uint m_nIssueStartQueryCreationCounter, m_nIssueEndQueryCreationCounter;
virtual ~IDirect3DQuery9();
HRESULT Issue(DWORD dwIssueFlags);
HRESULT GetData(void* pData, DWORD dwSize, DWORD dwGetDataFlags);
};
struct TOGL_CLASS IDirect3DVertexBuffer9
: public IDirect3DResource9 // was IUnknown
{
GLMContext* m_ctx;
CGLMBuffer* m_vtxBuffer;
D3DVERTEXBUFFER_DESC m_vtxDesc; // to satisfy GetDesc
virtual ~IDirect3DVertexBuffer9();
HRESULT Lock(UINT OffsetToLock, UINT SizeToLock, void** ppbData,
DWORD Flags);
HRESULT Unlock();
void UnlockActualSize(uint nActualSize, const void* pActualData = NULL);
};
struct TOGL_CLASS IDirect3DIndexBuffer9
: public IDirect3DResource9 // was IUnknown
{
GLMContext* m_ctx;
CGLMBuffer* m_idxBuffer;
D3DINDEXBUFFER_DESC m_idxDesc; // to satisfy GetDesc
virtual ~IDirect3DIndexBuffer9();
HRESULT Lock(UINT OffsetToLock, UINT SizeToLock, void** ppbData,
DWORD Flags);
HRESULT Unlock();
void UnlockActualSize(uint nActualSize, const void* pActualData = NULL);
HRESULT GetDesc(D3DINDEXBUFFER_DESC* pDesc);
};
struct TOGL_CLASS IDirect3DPixelShader9
: public IDirect3DResource9 // was IUnknown
{
CGLMProgram* m_pixProgram;
uint
m_pixHighWater; // count of active constant slots referenced by shader.
uint m_pixSamplerMask; // (1<<n) mask of samplers referemnced by this pixel
// shader this can help FlushSamplers avoid SRGB
// flipping on textures not being referenced...
uint m_pixSamplerTypes; // SAMPLER_TYPE_2D, etc.
uint m_pixFragDataMask; // (1<<n) mask of gl_FragData[n] referenced by this
// pixel shader
virtual ~IDirect3DPixelShader9();
};
struct TOGL_CLASS IDirect3DVertexShader9
: public IDirect3DResource9 // was IUnknown
{
CGLMProgram* m_vtxProgram;
uint
m_vtxHighWater; // count of active constant slots referenced by shader.
uint m_vtxHighWaterBone;
unsigned char
m_vtxAttribMap[16]; // high nibble is usage, low nibble is usageindex,
// array position is attrib number
uint m_maxVertexAttrs;
virtual ~IDirect3DVertexShader9();
};
#ifdef _MSC_VER
typedef class TOGL_CLASS CUtlMemory<D3DMATRIX> CD3DMATRIXAllocator;
typedef class TOGL_CLASS CUtlVector<D3DMATRIX, CD3DMATRIXAllocator>
CD3DMATRIXStack;
#else
typedef class CUtlMemory<D3DMATRIX> CD3DMATRIXAllocator;
typedef class CUtlVector<D3DMATRIX, CD3DMATRIXAllocator> CD3DMATRIXStack;
#endif
struct TOGL_CLASS ID3DXMatrixStack //: public IUnknown
{
int m_refcount[2];
bool m_mark;
CD3DMATRIXStack m_stack;
int m_stackTop; // top of stack is at the highest index, this is that
// index. push increases, pop decreases.
ID3DXMatrixStack();
void AddRef(int which = 0, char* comment = NULL);
ULONG Release(int which = 0, char* comment = NULL);
HRESULT Create(void);
D3DXMATRIX* GetTop();
void Push();
void Pop();
void LoadIdentity();
void LoadMatrix(const D3DXMATRIX* pMat);
void MultMatrix(const D3DXMATRIX* pMat);
void MultMatrixLocal(const D3DXMATRIX* pMat);
HRESULT ScaleLocal(FLOAT x, FLOAT y, FLOAT z);
// Left multiply the current matrix with the computed rotation
// matrix, counterclockwise about the given axis with the given angle.
// (rotation is about the local origin of the object)
HRESULT RotateAxisLocal(CONST D3DXVECTOR3* pV, FLOAT Angle);
// Left multiply the current matrix with the computed translation
// matrix. (transformation is about the local origin of the object)
HRESULT TranslateLocal(FLOAT x, FLOAT y, FLOAT z);
};
typedef ID3DXMatrixStack* LPD3DXMATRIXSTACK;
struct RenderTargetState_t {
void clear() { V_memset(this, 0, sizeof(*this)); }
CGLMTex* m_pRenderTargets[4];
CGLMTex* m_pDepthStencil;
inline bool RefersTo(CGLMTex* pSurf) const {
for (uint i = 0; i < 4; i++)
if (m_pRenderTargets[i] == pSurf) return true;
if (m_pDepthStencil == pSurf) return true;
return false;
}
static inline bool LessFunc(const RenderTargetState_t& lhs,
const RenderTargetState_t& rhs) {
COMPILE_TIME_ASSERT(sizeof(lhs.m_pRenderTargets[0]) == sizeof(uint32));
uint64 lhs0 = reinterpret_cast<const uint64*>(lhs.m_pRenderTargets)[0];
uint64 rhs0 = reinterpret_cast<const uint64*>(rhs.m_pRenderTargets)[0];
if (lhs0 < rhs0)
return true;
else if (lhs0 == rhs0) {
uint64 lhs1 =
reinterpret_cast<const uint64*>(lhs.m_pRenderTargets)[1];
uint64 rhs1 =
reinterpret_cast<const uint64*>(rhs.m_pRenderTargets)[1];
if (lhs1 < rhs1)
return true;
else if (lhs1 == rhs1) {
return lhs.m_pDepthStencil < rhs.m_pDepthStencil;
}
}
return false;
}
inline bool operator<(const RenderTargetState_t& rhs) const {
return LessFunc(*this, rhs);
}
};
typedef CUtlMap<RenderTargetState_t, CGLMFBO*> CGLMFBOMap;
class simple_bitmap;
struct TOGL_CLASS IDirect3DDevice9 : public IUnknown {
friend class GLMContext;
friend struct IDirect3DBaseTexture9;
friend struct IDirect3DTexture9;
friend struct IDirect3DCubeTexture9;
friend struct IDirect3DVolumeTexture9;
friend struct IDirect3DSurface9;
friend struct IDirect3DVertexBuffer9;
friend struct IDirect3DIndexBuffer9;
friend struct IDirect3DPixelShader9;
friend struct IDirect3DVertexShader9;
friend struct IDirect3DQuery9;
friend struct IDirect3DVertexDeclaration9;
IDirect3DDevice9();
virtual ~IDirect3DDevice9();
// Create call invoked from IDirect3D9
HRESULT TOGLMETHODCALLTYPE Create(IDirect3DDevice9Params* params);
//
// Basics
//
HRESULT TOGLMETHODCALLTYPE
Reset(D3DPRESENT_PARAMETERS* pPresentationParameters);
HRESULT TOGLMETHODCALLTYPE SetViewport(CONST D3DVIEWPORT9* pViewport);
HRESULT TOGLMETHODCALLTYPE GetViewport(D3DVIEWPORT9* pViewport);
HRESULT TOGLMETHODCALLTYPE BeginScene();
HRESULT TOGLMETHODCALLTYPE Clear(DWORD Count, CONST D3DRECT* pRects,
DWORD Flags, D3DCOLOR Color, float Z,
DWORD Stencil);
HRESULT TOGLMETHODCALLTYPE EndScene();
HRESULT TOGLMETHODCALLTYPE Present(CONST RECT* pSourceRect,
CONST RECT* pDestRect,
VD3DHWND hDestWindowOverride,
CONST RGNDATA* pDirtyRegion);
// textures
HRESULT TOGLMETHODCALLTYPE CreateTexture(UINT Width, UINT Height,
UINT Levels, DWORD Usage,
D3DFORMAT Format, D3DPOOL Pool,
IDirect3DTexture9** ppTexture,
VD3DHANDLE* pSharedHandle,
char* debugLabel = NULL);
HRESULT TOGLMETHODCALLTYPE CreateCubeTexture(
UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format,
D3DPOOL Pool, IDirect3DCubeTexture9** ppCubeTexture,
VD3DHANDLE* pSharedHandle, char* debugLabel = NULL);
HRESULT TOGLMETHODCALLTYPE
CreateVolumeTexture(UINT Width, UINT Height, UINT Depth, UINT Levels,
DWORD Usage, D3DFORMAT Format, D3DPOOL Pool,
IDirect3DVolumeTexture9** ppVolumeTexture,
VD3DHANDLE* pSharedHandle, char* debugLabel = NULL);
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
SetTexture(DWORD Stage, IDirect3DBaseTexture9* pTexture);
HRESULT TOGLMETHODCALLTYPE
SetTextureNonInline(DWORD Stage, IDirect3DBaseTexture9* pTexture);
HRESULT TOGLMETHODCALLTYPE GetTexture(DWORD Stage,
IDirect3DBaseTexture9** ppTexture);
// render targets, color and depthstencil, surfaces, blit
HRESULT TOGLMETHODCALLTYPE CreateRenderTarget(
UINT Width, UINT Height, D3DFORMAT Format,
D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
BOOL Lockable, IDirect3DSurface9** ppSurface, VD3DHANDLE* pSharedHandle,
char* debugLabel = NULL);
HRESULT TOGLMETHODCALLTYPE
SetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9* pRenderTarget);
HRESULT TOGLMETHODCALLTYPE GetRenderTarget(
DWORD RenderTargetIndex, IDirect3DSurface9** ppRenderTarget);
HRESULT TOGLMETHODCALLTYPE CreateOffscreenPlainSurface(
UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool,
IDirect3DSurface9** ppSurface, VD3DHANDLE* pSharedHandle);
HRESULT TOGLMETHODCALLTYPE CreateDepthStencilSurface(
UINT Width, UINT Height, D3DFORMAT Format,
D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard,
IDirect3DSurface9** ppSurface, VD3DHANDLE* pSharedHandle);
HRESULT TOGLMETHODCALLTYPE
SetDepthStencilSurface(IDirect3DSurface9* pNewZStencil);
HRESULT TOGLMETHODCALLTYPE
GetDepthStencilSurface(IDirect3DSurface9** ppZStencilSurface);
HRESULT TOGLMETHODCALLTYPE GetRenderTargetData(
IDirect3DSurface9* pRenderTarget,
IDirect3DSurface9* pDestSurface); // ? is anyone using this ?
HRESULT TOGLMETHODCALLTYPE
GetFrontBufferData(UINT iSwapChain, IDirect3DSurface9* pDestSurface);
HRESULT TOGLMETHODCALLTYPE StretchRect(IDirect3DSurface9* pSourceSurface,
CONST RECT* pSourceRect,
IDirect3DSurface9* pDestSurface,
CONST RECT* pDestRect,
D3DTEXTUREFILTERTYPE Filter);
// pixel shaders
HRESULT TOGLMETHODCALLTYPE
CreatePixelShader(CONST DWORD* pFunction, IDirect3DPixelShader9** ppShader,
const char* pShaderName, char* debugLabel = NULL,
const uint32* pCentroidMask = NULL);
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
SetPixelShader(IDirect3DPixelShader9* pShader);
HRESULT TOGLMETHODCALLTYPE
SetPixelShaderNonInline(IDirect3DPixelShader9* pShader);
FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetPixelShaderConstantF(
UINT StartRegister, CONST float* pConstantData, UINT Vector4fCount);
HRESULT TOGLMETHODCALLTYPE SetPixelShaderConstantFNonInline(
UINT StartRegister, CONST float* pConstantData, UINT Vector4fCount);
HRESULT TOGLMETHODCALLTYPE SetPixelShaderConstantB(
UINT StartRegister, CONST BOOL* pConstantData, UINT BoolCount);
HRESULT TOGLMETHODCALLTYPE SetPixelShaderConstantI(UINT StartRegister,
CONST int* pConstantData,
UINT Vector4iCount);
// vertex shaders
HRESULT TOGLMETHODCALLTYPE CreateVertexShader(
CONST DWORD* pFunction, IDirect3DVertexShader9** ppShader,
const char* pShaderName, char* debugLabel = NULL);
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
SetVertexShader(IDirect3DVertexShader9* pShader);
HRESULT TOGLMETHODCALLTYPE
SetVertexShaderNonInline(IDirect3DVertexShader9* pShader);
FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetVertexShaderConstantF(
UINT StartRegister, CONST float* pConstantData, UINT Vector4fCount);
HRESULT TOGLMETHODCALLTYPE SetVertexShaderConstantFNonInline(
UINT StartRegister, CONST float* pConstantData, UINT Vector4fCount);
FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetVertexShaderConstantB(
UINT StartRegister, CONST BOOL* pConstantData, UINT BoolCount);
HRESULT TOGLMETHODCALLTYPE SetVertexShaderConstantBNonInline(
UINT StartRegister, CONST BOOL* pConstantData, UINT BoolCount);
FORCEINLINE HRESULT TOGLMETHODCALLTYPE SetVertexShaderConstantI(
UINT StartRegister, CONST int* pConstantData, UINT Vector4iCount);
HRESULT TOGLMETHODCALLTYPE SetVertexShaderConstantINonInline(
UINT StartRegister, CONST int* pConstantData, UINT Vector4iCount);
// POSIX only - preheating for a specific vertex/pixel shader pair - trigger
// GLSL link inside GLM
HRESULT TOGLMETHODCALLTYPE LinkShaderPair(IDirect3DVertexShader9* vs,
IDirect3DPixelShader9* ps);
HRESULT TOGLMETHODCALLTYPE ValidateShaderPair(IDirect3DVertexShader9* vs,
IDirect3DPixelShader9* ps);
HRESULT TOGLMETHODCALLTYPE QueryShaderPair(int index,
GLMShaderPairInfo* infoOut);
// vertex buffers
HRESULT TOGLMETHODCALLTYPE
CreateVertexDeclaration(CONST D3DVERTEXELEMENT9* pVertexElements,
IDirect3DVertexDeclaration9** ppDecl);
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl);
HRESULT TOGLMETHODCALLTYPE
SetVertexDeclarationNonInline(IDirect3DVertexDeclaration9* pDecl);
HRESULT TOGLMETHODCALLTYPE
SetFVF(DWORD FVF); // we might not be using these ?
HRESULT TOGLMETHODCALLTYPE GetFVF(DWORD* pFVF);
HRESULT CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF,
D3DPOOL Pool,
IDirect3DVertexBuffer9** ppVertexBuffer,
VD3DHANDLE* pSharedHandle);
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9* pStreamData,
UINT OffsetInBytes, UINT Stride);
HRESULT SetStreamSourceNonInline(UINT StreamNumber,
IDirect3DVertexBuffer9* pStreamData,
UINT OffsetInBytes, UINT Stride);
// index buffers
HRESULT TOGLMETHODCALLTYPE CreateIndexBuffer(
UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool,
IDirect3DIndexBuffer9** ppIndexBuffer, VD3DHANDLE* pSharedHandle);
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
SetIndices(IDirect3DIndexBuffer9* pIndexData);
HRESULT TOGLMETHODCALLTYPE
SetIndicesNonInline(IDirect3DIndexBuffer9* pIndexData);
// State management.
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
SetRenderStateInline(D3DRENDERSTATETYPE State, DWORD Value);
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
SetRenderStateConstInline(D3DRENDERSTATETYPE State, DWORD Value);
HRESULT TOGLMETHODCALLTYPE SetRenderState(D3DRENDERSTATETYPE State,
DWORD Value);
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value);
HRESULT TOGLMETHODCALLTYPE SetSamplerStateNonInline(
DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value);
FORCEINLINE void TOGLMETHODCALLTYPE SetSamplerStates(
DWORD Sampler, DWORD AddressU, DWORD AddressV, DWORD AddressW,
DWORD MinFilter, DWORD MagFilter, DWORD MipFilter);
void TOGLMETHODCALLTYPE SetSamplerStatesNonInline(
DWORD Sampler, DWORD AddressU, DWORD AddressV, DWORD AddressW,
DWORD MinFilter, DWORD MagFilter, DWORD MipFilter);
#ifdef OSX
// required for 10.6 support
HRESULT TOGLMETHODCALLTYPE
FlushIndexBindings(void); // push index buffer (set index ptr)
HRESULT TOGLMETHODCALLTYPE FlushVertexBindings(
uint baseVertexIndex); // push vertex streams (set attrib ptrs)
#endif
// Draw.
HRESULT TOGLMETHODCALLTYPE DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType,
UINT StartVertex,
UINT PrimitiveCount);
HRESULT TOGLMETHODCALLTYPE DrawIndexedPrimitive(
D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex,
UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount);
HRESULT TOGLMETHODCALLTYPE DrawIndexedPrimitiveUP(
D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices,
UINT PrimitiveCount, CONST void* pIndexData, D3DFORMAT IndexDataFormat,
CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride);
// misc
BOOL TOGLMETHODCALLTYPE ShowCursor(BOOL bShow);
HRESULT TOGLMETHODCALLTYPE ValidateDevice(DWORD* pNumPasses);
HRESULT TOGLMETHODCALLTYPE SetMaterial(CONST D3DMATERIAL9* pMaterial);
HRESULT TOGLMETHODCALLTYPE LightEnable(DWORD Index, BOOL Enable);
HRESULT TOGLMETHODCALLTYPE SetScissorRect(CONST RECT* pRect);
HRESULT TOGLMETHODCALLTYPE CreateQuery(D3DQUERYTYPE Type,
IDirect3DQuery9** ppQuery);
HRESULT TOGLMETHODCALLTYPE GetDeviceCaps(D3DCAPS9* pCaps);
HRESULT TOGLMETHODCALLTYPE TestCooperativeLevel();
HRESULT TOGLMETHODCALLTYPE EvictManagedResources();
HRESULT TOGLMETHODCALLTYPE SetLight(DWORD Index, CONST D3DLIGHT9*);
void TOGLMETHODCALLTYPE SetGammaRamp(UINT iSwapChain, DWORD Flags,
CONST D3DGAMMARAMP* pRamp);
void TOGLMETHODCALLTYPE SaveGLState();
void TOGLMETHODCALLTYPE RestoreGLState();
// Talk to JasonM about this one. It's tricky in GL.
HRESULT TOGLMETHODCALLTYPE SetClipPlane(DWORD Index, CONST float* pPlane);
//
//
// **** FIXED FUNCTION STUFF - None of this stuff needs support in GL.
//
//
HRESULT TOGLMETHODCALLTYPE SetTransform(D3DTRANSFORMSTATETYPE State,
CONST D3DMATRIX* pMatrix);
HRESULT TOGLMETHODCALLTYPE SetTextureStageState(
DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value);
void TOGLMETHODCALLTYPE AcquireThreadOwnership();
void TOGLMETHODCALLTYPE ReleaseThreadOwnership();
inline DWORD TOGLMETHODCALLTYPE GetCurrentOwnerThreadId() const {
return m_ctx->m_nCurOwnerThreadId;
}
FORCEINLINE void TOGLMETHODCALLTYPE
SetMaxUsedVertexShaderConstantsHint(uint nMaxReg);
void TOGLMETHODCALLTYPE
SetMaxUsedVertexShaderConstantsHintNonInline(uint nMaxReg);
void DumpStatsToConsole(const CCommand* pArgs);
#if GLMDEBUG
void DumpTextures(const CCommand* pArgs);
#endif
private:
IDirect3DDevice9(const IDirect3DDevice9&);
IDirect3DDevice9& operator=(const IDirect3DDevice9&);
// Flushing changes to GL
void FlushClipPlaneEquation();
void InitStates();
void FullFlushStates();
void UpdateBoundFBO();
void ResetFBOMap();
void ScrubFBOMap(CGLMTex* pTex);
// response to retired objects (when refcount goes to zero and they
// self-delete..)
void ReleasedVertexDeclaration(IDirect3DVertexDeclaration9* pDecl);
void ReleasedTexture(
IDirect3DBaseTexture9* baseTex); // called from texture destructor -
// need to scrub samplers
void ReleasedCGLMTex(CGLMTex* pTex);
void ReleasedSurface(
IDirect3DSurface9* surface); // called from any surface destructor -
// need to scrub RT table if an RT
void ReleasedPixelShader(
IDirect3DPixelShader9*
pixelShader); // called from IDirect3DPixelShader9 destructor
void ReleasedVertexShader(
IDirect3DVertexShader9*
vertexShader); // called from IDirect3DVertexShader9 destructor
void ReleasedVertexBuffer(
IDirect3DVertexBuffer9*
vertexBuffer); // called from IDirect3DVertexBuffer9 destructor
void ReleasedIndexBuffer(
IDirect3DIndexBuffer9*
indexBuffer); // called from IDirect3DIndexBuffer9 destructor
void ReleasedQuery(
IDirect3DQuery9* query); // called from IDirect3DQuery9 destructor
// Member variables
DWORD m_nValidMarker;
public:
IDirect3DDevice9Params m_params; // mirror of the creation inputs
private:
// D3D flavor stuff
IDirect3DSurface9* m_pRenderTargets[4];
IDirect3DSurface9* m_pDepthStencil;
IDirect3DSurface9* m_pDefaultColorSurface; // default color surface.
IDirect3DSurface9*
m_pDefaultDepthStencilSurface; // queried by GetDepthStencilSurface.
IDirect3DVertexDeclaration9* m_pVertDecl; // Set by SetVertexDeclaration...
D3DStreamDesc m_streams[D3D_MAX_STREAMS]; // Set by SetStreamSource..
CGLMBuffer* m_vtx_buffers[D3D_MAX_STREAMS];
CGLMBuffer* m_pDummy_vtx_buffer;
D3DIndexDesc m_indices; // Set by SetIndices..
IDirect3DVertexShader9* m_vertexShader; // Set by SetVertexShader...
IDirect3DPixelShader9* m_pixelShader; // Set by SetPixelShader...
IDirect3DBaseTexture9*
m_textures[GLM_SAMPLER_COUNT]; // set by SetTexture... NULL if stage
// inactive
// GLM flavor stuff
GLMContext* m_ctx;
CGLMFBOMap* m_pFBOs;
bool m_bFBODirty;
struct ObjectStats_t {
int m_nTotalFBOs;
int m_nTotalVertexShaders;
int m_nTotalPixelShaders;
int m_nTotalVertexDecls;
int m_nTotalIndexBuffers;
int m_nTotalVertexBuffers;
int m_nTotalRenderTargets;
int m_nTotalTextures;
int m_nTotalSurfaces;
int m_nTotalQueries;
void clear() { V_memset(this, 0, sizeof(*this)); }
ObjectStats_t& operator-=(const ObjectStats_t& rhs) {
m_nTotalFBOs -= rhs.m_nTotalFBOs;
m_nTotalVertexShaders -= rhs.m_nTotalVertexShaders;
m_nTotalPixelShaders -= rhs.m_nTotalPixelShaders;
m_nTotalVertexDecls -= rhs.m_nTotalVertexDecls;
m_nTotalIndexBuffers -= rhs.m_nTotalIndexBuffers;
m_nTotalVertexBuffers -= rhs.m_nTotalVertexBuffers;
m_nTotalRenderTargets -= rhs.m_nTotalRenderTargets;
m_nTotalTextures -= rhs.m_nTotalTextures;
m_nTotalSurfaces -= rhs.m_nTotalSurfaces;
m_nTotalQueries -= m_nTotalQueries;
return *this;
}
};
ObjectStats_t m_ObjectStats;
ObjectStats_t m_PrevObjectStats;
void PrintObjectStats(const ObjectStats_t& stats);
// GL state
struct {
// render state buckets
GLAlphaTestEnable_t m_AlphaTestEnable;
GLAlphaTestFunc_t m_AlphaTestFunc;
GLAlphaToCoverageEnable_t m_AlphaToCoverageEnable;
GLDepthTestEnable_t m_DepthTestEnable;
GLDepthMask_t m_DepthMask;
GLDepthFunc_t m_DepthFunc;
GLClipPlaneEnable_t m_ClipPlaneEnable[kGLMUserClipPlanes];
GLClipPlaneEquation_t m_ClipPlaneEquation[kGLMUserClipPlanes];
GLColorMaskSingle_t m_ColorMaskSingle;
GLColorMaskMultiple_t m_ColorMaskMultiple;
GLCullFaceEnable_t m_CullFaceEnable;
GLCullFrontFace_t m_CullFrontFace;
GLPolygonMode_t m_PolygonMode;
GLDepthBias_t m_DepthBias;
GLScissorEnable_t m_ScissorEnable;
GLScissorBox_t m_ScissorBox;
GLViewportBox_t m_ViewportBox;
GLViewportDepthRange_t m_ViewportDepthRange;
GLBlendEnable_t m_BlendEnable;
GLBlendFactor_t m_BlendFactor;
GLBlendEquation_t m_BlendEquation;
GLBlendColor_t m_BlendColor;
GLBlendEnableSRGB_t m_BlendEnableSRGB;
GLStencilTestEnable_t m_StencilTestEnable;
GLStencilFunc_t m_StencilFunc;
GLStencilOp_t m_StencilOp;
GLStencilWriteMask_t m_StencilWriteMask;
GLClearColor_t m_ClearColor;
GLClearDepth_t m_ClearDepth;
GLClearStencil_t m_ClearStencil;
bool m_FogEnable; // not really pushed to GL, just latched here
// samplers
// GLMTexSamplingParams m_samplers[GLM_SAMPLER_COUNT];
} gl;
#if GL_BATCH_PERF_ANALYSIS
simple_bitmap* m_pBatch_vis_bitmap;
uint m_nBatchVisY;
uint m_nBatchVisFrameIndex, m_nBatchVisFileIdx;
uint m_nNumProgramChanges;
uint m_nTotalD3DCalls;
double m_flTotalD3DTime;
uint m_nTotalGLCalls;
double m_flTotalGLTime;
uint m_nTotalPrims;
uint m_nOverallProgramChanges;
uint m_nOverallDraws;
uint m_nOverallPrims;
uint m_nOverallD3DCalls;
double m_flOverallD3DTime;
uint m_nOverallGLCalls;
double m_flOverallGLTime;
double m_flOverallPresentTime;
double m_flOverallPresentTimeSquared;
double m_flOverallSwapWindowTime;
double m_flOverallSwapWindowTimeSquared;
uint m_nOverallPresents;
#endif
};
FORCEINLINE HRESULT TOGLMETHODCALLTYPE IDirect3DDevice9::SetSamplerState(
DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value) {
#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS
return SetSamplerStateNonInline(Sampler, Type, Value);
#else
Assert(GetCurrentOwnerThreadId() == ThreadGetCurrentId());
Assert(Sampler < GLM_SAMPLER_COUNT);
m_ctx->SetSamplerDirty(Sampler);
switch (Type) {
case D3DSAMP_ADDRESSU:
m_ctx->SetSamplerAddressU(Sampler, Value);
break;
case D3DSAMP_ADDRESSV:
m_ctx->SetSamplerAddressV(Sampler, Value);
break;
case D3DSAMP_ADDRESSW:
m_ctx->SetSamplerAddressW(Sampler, Value);
break;
case D3DSAMP_BORDERCOLOR:
m_ctx->SetSamplerBorderColor(Sampler, Value);
break;
case D3DSAMP_MAGFILTER:
m_ctx->SetSamplerMagFilter(Sampler, Value);
break;
case D3DSAMP_MIPFILTER:
m_ctx->SetSamplerMipFilter(Sampler, Value);
break;
case D3DSAMP_MINFILTER:
m_ctx->SetSamplerMinFilter(Sampler, Value);
break;
case D3DSAMP_MIPMAPLODBIAS:
m_ctx->SetSamplerMipMapLODBias(Sampler, Value);
break;
case D3DSAMP_MAXMIPLEVEL:
m_ctx->SetSamplerMaxMipLevel(Sampler, Value);
break;
case D3DSAMP_MAXANISOTROPY:
m_ctx->SetSamplerMaxAnisotropy(Sampler, Value);
break;
case D3DSAMP_SRGBTEXTURE:
// m_samplers[ Sampler ].m_srgb = Value;
m_ctx->SetSamplerSRGBTexture(Sampler, Value);
break;
case D3DSAMP_SHADOWFILTER:
m_ctx->SetShadowFilter(Sampler, Value);
break;
default:
DXABSTRACT_BREAK_ON_ERROR();
break;
}
return S_OK;
#endif
}
FORCEINLINE void TOGLMETHODCALLTYPE IDirect3DDevice9::SetSamplerStates(
DWORD Sampler, DWORD AddressU, DWORD AddressV, DWORD AddressW,
DWORD MinFilter, DWORD MagFilter, DWORD MipFilter) {
#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS
SetSamplerStatesNonInline(Sampler, AddressU, AddressV, AddressW, MinFilter,
MagFilter, MipFilter);
#else
Assert(GetCurrentOwnerThreadId() == ThreadGetCurrentId());
Assert(Sampler < GLM_SAMPLER_COUNT);
m_ctx->SetSamplerDirty(Sampler);
m_ctx->SetSamplerStates(Sampler, AddressU, AddressV, AddressW, MinFilter,
MagFilter, MipFilter);
#endif
}
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
IDirect3DDevice9::SetTexture(DWORD Stage, IDirect3DBaseTexture9* pTexture) {
#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS
return SetTextureNonInline(Stage, pTexture);
#else
Assert(GetCurrentOwnerThreadId() == ThreadGetCurrentId());
Assert(Stage < GLM_SAMPLER_COUNT);
m_textures[Stage] = pTexture;
m_ctx->SetSamplerTex(Stage, pTexture ? pTexture->m_tex : NULL);
return S_OK;
#endif
}
inline GLenum D3DCompareFuncToGL(DWORD function) {
switch (function) {
case D3DCMP_NEVER:
return GL_NEVER; // Always fail the test.
case D3DCMP_LESS:
return GL_LESS; // Accept the new pixel if its value is less than
// the value of the current pixel.
case D3DCMP_EQUAL:
return GL_EQUAL; // Accept the new pixel if its value equals the
// value of the current pixel.
case D3DCMP_LESSEQUAL:
return GL_LEQUAL; // Accept the new pixel if its value is less than
// or equal to the value of the current pixel. **
case D3DCMP_GREATER:
return GL_GREATER; // Accept the new pixel if its value is greater
// than the value of the current pixel.
case D3DCMP_NOTEQUAL:
return GL_NOTEQUAL; // Accept the new pixel if its value does not
// equal the value of the current pixel.
case D3DCMP_GREATEREQUAL:
return GL_GEQUAL; // Accept the new pixel if its value is greater
// than or equal to the value of the current
// pixel.
case D3DCMP_ALWAYS:
return GL_ALWAYS; // Always pass the test.
default:
DXABSTRACT_BREAK_ON_ERROR();
return 0xFFFFFFFF;
}
}
FORCEINLINE GLenum D3DBlendOperationToGL(DWORD operation) {
switch (operation) {
case D3DBLENDOP_ADD:
return GL_FUNC_ADD; // The result is the destination added to the
// source. Result = Source + Destination
case D3DBLENDOP_SUBTRACT:
return GL_FUNC_SUBTRACT; // The result is the destination
// subtracted from to the source. Result =
// Source - Destination
case D3DBLENDOP_REVSUBTRACT:
return GL_FUNC_REVERSE_SUBTRACT; // The result is the source
// subtracted from the
// destination. Result =
// Destination - Source
case D3DBLENDOP_MIN:
return GL_MIN; // The result is the minimum of the source and
// destination. Result = MIN(Source, Destination)
case D3DBLENDOP_MAX:
return GL_MAX; // The result is the maximum of the source and
// destination. Result = MAX(Source, Destination)
default:
DXABSTRACT_BREAK_ON_ERROR();
return 0xFFFFFFFF;
break;
}
}
FORCEINLINE GLenum D3DBlendFactorToGL(DWORD equation) {
switch (equation) {
case D3DBLEND_ZERO:
return GL_ZERO; // Blend factor is (0, 0, 0, 0).
case D3DBLEND_ONE:
return GL_ONE; // Blend factor is (1, 1, 1, 1).
case D3DBLEND_SRCCOLOR:
return GL_SRC_COLOR; // Blend factor is (Rs, Gs, Bs, As).
case D3DBLEND_INVSRCCOLOR:
return GL_ONE_MINUS_SRC_COLOR; // Blend factor is (1 - Rs, 1 - Gs,
// 1 - Bs, 1 - As).
case D3DBLEND_SRCALPHA:
return GL_SRC_ALPHA; // Blend factor is (As, As, As, As).
case D3DBLEND_INVSRCALPHA:
return GL_ONE_MINUS_SRC_ALPHA; // Blend factor is ( 1 - As, 1 - As,
// 1 - As, 1 - As).
case D3DBLEND_DESTALPHA:
return GL_DST_ALPHA; // Blend factor is (Ad Ad Ad Ad).
case D3DBLEND_INVDESTALPHA:
return GL_ONE_MINUS_DST_ALPHA; // Blend factor is (1 - Ad 1 - Ad 1
// - Ad 1 - Ad).
case D3DBLEND_DESTCOLOR:
return GL_DST_COLOR; // Blend factor is (Rd, Gd, Bd, Ad).
case D3DBLEND_INVDESTCOLOR:
return GL_ONE_MINUS_DST_COLOR; // Blend factor is (1 - Rd, 1 - Gd,
// 1 - Bd, 1 - Ad).
case D3DBLEND_SRCALPHASAT:
return GL_SRC_ALPHA_SATURATE; // Blend factor is (f, f, f, 1);
// where f = min(As, 1 - Ad).
/*
// these are weird.... break if we hit them
case D3DBLEND_BOTHSRCALPHA : Assert(0); return GL_ZERO;
// Obsolete. Starting with DirectX 6, you can achieve the same effect by
setting the source and destination blend factors to D3DBLEND_SRCALPHA
and D3DBLEND_INVSRCALPHA in separate calls. case
D3DBLEND_BOTHINVSRCALPHA: Assert(0); return GL_ZERO; //
Source blend factor is (1 - As, 1 - As, 1 - As, 1 - As), and destination
blend factor is (As, As, As, As); the destination blend selection is
overridden. This blend mode is supported only for the D3DRS_SRCBLEND
render state.
case D3DBLEND_BLENDFACTOR : Assert(0); return GL_ZERO;
// Constant color blending factor used by the frame-buffer blender. This
blend mode is supported only if D3DPBLENDCAPS_BLENDFACTOR is set in the
SrcBlendCaps or DestBlendCaps members of D3DCAPS9.
dxabstract.h has not heard of these, so let them hit the debugger if
they come through case D3DBLEND_INVBLENDFACTOR: //Inverted
constant color-blending factor used by the frame-buffer blender. This
blend mode is supported only if the D3DPBLENDCAPS_BLENDFACTOR bit is set
in the SrcBlendCaps or DestBlendCaps members of D3DCAPS9. case
D3DBLEND_SRCCOLOR2: // Blend factor is (PSOutColor[1]r,
PSOutColor[1]g, PSOutColor[1]b, not used). This flag is available
in Direct3D 9Ex only.
case D3DBLEND_INVSRCCOLOR2: // Blend factor is (1 -
PSOutColor[1]r, 1 - PSOutColor[1]g, 1 - PSOutColor[1]b, not used)). This
flag is available in Direct3D 9Ex only.
*/
default:
DXABSTRACT_BREAK_ON_ERROR();
return 0xFFFFFFFF;
break;
}
}
FORCEINLINE GLenum D3DStencilOpToGL(DWORD operation) {
switch (operation) {
case D3DSTENCILOP_KEEP:
return GL_KEEP;
case D3DSTENCILOP_ZERO:
return GL_ZERO;
case D3DSTENCILOP_REPLACE:
return GL_REPLACE;
case D3DSTENCILOP_INCRSAT:
return GL_INCR;
case D3DSTENCILOP_DECRSAT:
return GL_DECR;
case D3DSTENCILOP_INVERT:
return GL_INVERT;
case D3DSTENCILOP_INCR:
return GL_INCR_WRAP_EXT;
case D3DSTENCILOP_DECR:
return GL_DECR_WRAP_EXT;
default:
DXABSTRACT_BREAK_ON_ERROR();
return 0xFFFFFFFF;
}
}
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
IDirect3DDevice9::SetRenderStateInline(D3DRENDERSTATETYPE State, DWORD Value) {
#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS
return SetRenderState(State, Value);
#else
TOGL_NULL_DEVICE_CHECK;
Assert(GetCurrentOwnerThreadId() == ThreadGetCurrentId());
switch (State) {
case D3DRS_ZENABLE: // kGLDepthTestEnable
{
gl.m_DepthTestEnable.enable = Value;
m_ctx->WriteDepthTestEnable(&gl.m_DepthTestEnable);
break;
}
case D3DRS_ZWRITEENABLE: // kGLDepthMask
{
gl.m_DepthMask.mask = Value;
m_ctx->WriteDepthMask(&gl.m_DepthMask);
break;
}
case D3DRS_ZFUNC: {
// kGLDepthFunc
GLenum func = D3DCompareFuncToGL(Value);
gl.m_DepthFunc.func = func;
m_ctx->WriteDepthFunc(&gl.m_DepthFunc);
break;
}
case D3DRS_COLORWRITEENABLE: // kGLColorMaskSingle
{
gl.m_ColorMaskSingle.r =
((Value & D3DCOLORWRITEENABLE_RED) != 0) ? 0xFF : 0x00;
gl.m_ColorMaskSingle.g =
((Value & D3DCOLORWRITEENABLE_GREEN) != 0) ? 0xFF : 0x00;
gl.m_ColorMaskSingle.b =
((Value & D3DCOLORWRITEENABLE_BLUE) != 0) ? 0xFF : 0x00;
gl.m_ColorMaskSingle.a =
((Value & D3DCOLORWRITEENABLE_ALPHA) != 0) ? 0xFF : 0x00;
m_ctx->WriteColorMaskSingle(&gl.m_ColorMaskSingle);
break;
}
case D3DRS_CULLMODE: // kGLCullFaceEnable / kGLCullFrontFace
{
switch (Value) {
case D3DCULL_NONE: {
gl.m_CullFaceEnable.enable = false;
gl.m_CullFrontFace.value = GL_CCW; // doesn't matter
m_ctx->WriteCullFaceEnable(&gl.m_CullFaceEnable);
m_ctx->WriteCullFrontFace(&gl.m_CullFrontFace);
break;
}
case D3DCULL_CW: {
gl.m_CullFaceEnable.enable = true;
gl.m_CullFrontFace.value = GL_CW; // origGL_CCW;
m_ctx->WriteCullFaceEnable(&gl.m_CullFaceEnable);
m_ctx->WriteCullFrontFace(&gl.m_CullFrontFace);
break;
}
case D3DCULL_CCW: {
gl.m_CullFaceEnable.enable = true;
gl.m_CullFrontFace.value = GL_CCW; // origGL_CW;
m_ctx->WriteCullFaceEnable(&gl.m_CullFaceEnable);
m_ctx->WriteCullFrontFace(&gl.m_CullFrontFace);
break;
}
default: {
DXABSTRACT_BREAK_ON_ERROR();
break;
}
}
break;
}
//--------------------------------------------------------------------------------------------
//alphablend stuff
case D3DRS_ALPHABLENDENABLE: // kGLBlendEnable
{
gl.m_BlendEnable.enable = Value;
m_ctx->WriteBlendEnable(&gl.m_BlendEnable);
break;
}
case D3DRS_BLENDOP: // kGLBlendEquation
// // D3D blend-op ==> GL blend equation
{
GLenum equation = D3DBlendOperationToGL(Value);
gl.m_BlendEquation.equation = equation;
m_ctx->WriteBlendEquation(&gl.m_BlendEquation);
break;
}
case D3DRS_SRCBLEND: // kGLBlendFactor // D3D
// blend-factor ==> GL blend factor
case D3DRS_DESTBLEND: // kGLBlendFactor
{
GLenum factor = D3DBlendFactorToGL(Value);
if (State == D3DRS_SRCBLEND) {
gl.m_BlendFactor.srcfactor = factor;
} else {
gl.m_BlendFactor.dstfactor = factor;
}
m_ctx->WriteBlendFactor(&gl.m_BlendFactor);
break;
}
case D3DRS_SRGBWRITEENABLE: // kGLBlendEnableSRGB
{
gl.m_BlendEnableSRGB.enable = Value;
m_ctx->WriteBlendEnableSRGB(&gl.m_BlendEnableSRGB);
break;
}
//--------------------------------------------------------------------------------------------
//alphatest stuff
case D3DRS_ALPHATESTENABLE: {
gl.m_AlphaTestEnable.enable = Value;
m_ctx->WriteAlphaTestEnable(&gl.m_AlphaTestEnable);
break;
}
case D3DRS_ALPHAREF: {
gl.m_AlphaTestFunc.ref = Value / 255.0f;
m_ctx->WriteAlphaTestFunc(&gl.m_AlphaTestFunc);
break;
}
case D3DRS_ALPHAFUNC: {
GLenum func = D3DCompareFuncToGL(Value);
;
gl.m_AlphaTestFunc.func = func;
m_ctx->WriteAlphaTestFunc(&gl.m_AlphaTestFunc);
break;
}
//--------------------------------------------------------------------------------------------
//stencil stuff
case D3DRS_STENCILENABLE: // GLStencilTestEnable_t
{
gl.m_StencilTestEnable.enable = Value;
m_ctx->WriteStencilTestEnable(&gl.m_StencilTestEnable);
break;
}
case D3DRS_STENCILFAIL: // GLStencilOp_t "what do you do if
// stencil test fails"
{
GLenum stencilop = D3DStencilOpToGL(Value);
gl.m_StencilOp.sfail = stencilop;
m_ctx->WriteStencilOp(&gl.m_StencilOp, 0);
m_ctx->WriteStencilOp(&gl.m_StencilOp,
1); // ********* need to recheck this
break;
}
case D3DRS_STENCILZFAIL: // GLStencilOp_t "what do you do if
// stencil test passes *but* depth test fails,
// if depth test happened"
{
GLenum stencilop = D3DStencilOpToGL(Value);
gl.m_StencilOp.dpfail = stencilop;
m_ctx->WriteStencilOp(&gl.m_StencilOp, 0);
m_ctx->WriteStencilOp(&gl.m_StencilOp,
1); // ********* need to recheck this
break;
}
case D3DRS_STENCILPASS: // GLStencilOp_t "what do you do if
// stencil test and depth test both pass"
{
GLenum stencilop = D3DStencilOpToGL(Value);
gl.m_StencilOp.dppass = stencilop;
m_ctx->WriteStencilOp(&gl.m_StencilOp, 0);
m_ctx->WriteStencilOp(&gl.m_StencilOp,
1); // ********* need to recheck this
break;
}
case D3DRS_STENCILFUNC: // GLStencilFunc_t
{
GLenum stencilfunc = D3DCompareFuncToGL(Value);
gl.m_StencilFunc.frontfunc = gl.m_StencilFunc.backfunc =
stencilfunc;
m_ctx->WriteStencilFunc(&gl.m_StencilFunc);
break;
}
case D3DRS_STENCILREF: // GLStencilFunc_t
{
gl.m_StencilFunc.ref = Value;
m_ctx->WriteStencilFunc(&gl.m_StencilFunc);
break;
}
case D3DRS_STENCILMASK: // GLStencilFunc_t
{
gl.m_StencilFunc.mask = Value;
m_ctx->WriteStencilFunc(&gl.m_StencilFunc);
break;
}
case D3DRS_STENCILWRITEMASK: // GLStencilWriteMask_t
{
gl.m_StencilWriteMask.mask = Value;
m_ctx->WriteStencilWriteMask(&gl.m_StencilWriteMask);
break;
}
case D3DRS_FOGENABLE: // none of these are implemented yet... erk
{
gl.m_FogEnable = (Value != 0);
GLMPRINTF(("-D- fogenable = %d", Value));
break;
}
case D3DRS_SCISSORTESTENABLE: // kGLScissorEnable
{
gl.m_ScissorEnable.enable = Value;
m_ctx->WriteScissorEnable(&gl.m_ScissorEnable);
break;
}
case D3DRS_DEPTHBIAS: // kGLDepthBias
{
// the value in the dword is actually a float
float fvalue = *(float*)&Value;
gl.m_DepthBias.units = fvalue;
m_ctx->WriteDepthBias(&gl.m_DepthBias);
break;
}
// good ref on these:
// http://aras-p.info/blog/2008/06/12/depth-bias-and-the-power-of-deceiving-yourself/
case D3DRS_SLOPESCALEDEPTHBIAS: {
// the value in the dword is actually a float
float fvalue = *(float*)&Value;
gl.m_DepthBias.factor = fvalue;
m_ctx->WriteDepthBias(&gl.m_DepthBias);
break;
}
// Alpha to coverage
case D3DRS_ADAPTIVETESS_Y: {
gl.m_AlphaToCoverageEnable.enable = Value;
m_ctx->WriteAlphaToCoverageEnable(&gl.m_AlphaToCoverageEnable);
break;
}
case D3DRS_CLIPPLANEENABLE: // kGLClipPlaneEnable
{
// d3d packs all the enables into one word.
// we break that out so we don't do N glEnable calls to sync -
// GLM is tracking one unique enable per plane.
for (int i = 0; i < kGLMUserClipPlanes; i++) {
gl.m_ClipPlaneEnable[i].enable = (Value & (1 << i)) != 0;
}
for (int x = 0; x < kGLMUserClipPlanes; x++)
m_ctx->WriteClipPlaneEnable(&gl.m_ClipPlaneEnable[x], x);
break;
}
//--------------------------------------------------------------------------------------------
//polygon/fill mode
case D3DRS_FILLMODE: {
GLuint mode = 0;
switch (Value) {
case D3DFILL_POINT:
mode = GL_POINT;
break;
case D3DFILL_WIREFRAME:
mode = GL_LINE;
break;
case D3DFILL_SOLID:
mode = GL_FILL;
break;
default:
DXABSTRACT_BREAK_ON_ERROR();
break;
}
gl.m_PolygonMode.values[0] = gl.m_PolygonMode.values[1] = mode;
m_ctx->WritePolygonMode(&gl.m_PolygonMode);
break;
}
}
return S_OK;
#endif
}
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
IDirect3DDevice9::SetRenderStateConstInline(D3DRENDERSTATETYPE State,
DWORD Value) {
// State is a compile time constant - luckily no need to do anything special
// to get the compiler to optimize this case.
return SetRenderStateInline(State, Value);
}
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
IDirect3DDevice9::SetIndices(IDirect3DIndexBuffer9* pIndexData) {
#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS
return SetIndicesNonInline(pIndexData);
#else
Assert(GetCurrentOwnerThreadId() == ThreadGetCurrentId());
// just latch it.
m_indices.m_idxBuffer = pIndexData;
return S_OK;
#endif
}
FORCEINLINE HRESULT TOGLMETHODCALLTYPE IDirect3DDevice9::SetStreamSource(
UINT StreamNumber, IDirect3DVertexBuffer9* pStreamData, UINT OffsetInBytes,
UINT Stride) {
#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS
return SetStreamSourceNonInline(StreamNumber, pStreamData, OffsetInBytes,
Stride);
#else
Assert(GetCurrentOwnerThreadId() == ThreadGetCurrentId());
Assert(StreamNumber < D3D_MAX_STREAMS);
Assert((Stride & 3) ==
0); // we support non-DWORD aligned strides, but on some drivers
// (like AMD's) perf goes off a cliff
// perfectly legal to see a vertex buffer of NULL get passed in here.
// so we need an array to track these.
// OK, we are being given the stride, we don't need to calc it..
GLMPRINTF(
("-X- IDirect3DDevice9::SetStreamSource setting stream #%d to D3D buf "
"%p (GL name %d); offset %d, stride %d",
StreamNumber, pStreamData,
(pStreamData) ? pStreamData->m_vtxBuffer->m_name : -1, OffsetInBytes,
Stride));
if (!pStreamData) {
OffsetInBytes = 0;
Stride = 0;
m_vtx_buffers[StreamNumber] = m_pDummy_vtx_buffer;
} else {
// We do not support strides of 0
Assert(Stride > 0);
m_vtx_buffers[StreamNumber] = pStreamData->m_vtxBuffer;
}
m_streams[StreamNumber].m_vtxBuffer = pStreamData;
m_streams[StreamNumber].m_offset = OffsetInBytes;
m_streams[StreamNumber].m_stride = Stride;
return S_OK;
#endif
}
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
IDirect3DDevice9::SetVertexShaderConstantF(
UINT StartRegister, CONST float* pConstantData,
UINT Vector4fCount) // groups of 4 floats!
{
#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS
return SetVertexShaderConstantFNonInline(StartRegister, pConstantData,
Vector4fCount);
#else
TOGL_NULL_DEVICE_CHECK;
Assert(GetCurrentOwnerThreadId() == ThreadGetCurrentId());
m_ctx->SetProgramParametersF(kGLMVertexProgram, StartRegister,
(float*)pConstantData, Vector4fCount);
return S_OK;
#endif
}
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
IDirect3DDevice9::SetVertexShaderConstantB(UINT StartRegister,
CONST BOOL* pConstantData,
UINT BoolCount) {
#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS
return SetVertexShaderConstantBNonInline(StartRegister, pConstantData,
BoolCount);
#else
TOGL_NULL_DEVICE_CHECK;
Assert(GetCurrentOwnerThreadId() == ThreadGetCurrentId());
m_ctx->SetProgramParametersB(kGLMVertexProgram, StartRegister,
(int*)pConstantData, BoolCount);
return S_OK;
#endif
}
FORCEINLINE HRESULT IDirect3DDevice9::SetVertexShaderConstantI(
UINT StartRegister, CONST int* pConstantData,
UINT Vector4iCount) // groups of 4 ints!
{
#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS
return SetVertexShaderConstantINonInline(StartRegister, pConstantData,
Vector4iCount);
#else
TOGL_NULL_DEVICE_CHECK;
Assert(GetCurrentOwnerThreadId() == ThreadGetCurrentId());
m_ctx->SetProgramParametersI(kGLMVertexProgram, StartRegister,
(int*)pConstantData, Vector4iCount);
return S_OK;
#endif
}
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
IDirect3DDevice9::SetPixelShaderConstantF(UINT StartRegister,
CONST float* pConstantData,
UINT Vector4fCount) {
#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS
return SetPixelShaderConstantFNonInline(StartRegister, pConstantData,
Vector4fCount);
#else
TOGL_NULL_DEVICE_CHECK;
Assert(GetCurrentOwnerThreadId() == ThreadGetCurrentId());
m_ctx->SetProgramParametersF(kGLMFragmentProgram, StartRegister,
(float*)pConstantData, Vector4fCount);
return S_OK;
#endif
}
HRESULT IDirect3DDevice9::SetVertexShader(IDirect3DVertexShader9* pShader) {
#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS
return SetVertexShaderNonInline(pShader);
#else
Assert(GetCurrentOwnerThreadId() == ThreadGetCurrentId());
m_ctx->SetVertexProgram(pShader ? pShader->m_vtxProgram : NULL);
m_vertexShader = pShader;
return S_OK;
#endif
}
FORCEINLINE HRESULT TOGLMETHODCALLTYPE
IDirect3DDevice9::SetPixelShader(IDirect3DPixelShader9* pShader) {
#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS
return SetPixelShaderNonInline(pShader);
#else
Assert(GetCurrentOwnerThreadId() == ThreadGetCurrentId());
m_ctx->SetFragmentProgram(pShader ? pShader->m_pixProgram : NULL);
m_pixelShader = pShader;
return S_OK;
#endif
}
FORCEINLINE HRESULT
IDirect3DDevice9::SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl) {
#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS
return SetVertexDeclarationNonInline(pDecl);
#else
Assert(GetCurrentOwnerThreadId() == ThreadGetCurrentId());
m_pVertDecl = pDecl;
return S_OK;
#endif
}
FORCEINLINE void IDirect3DDevice9::SetMaxUsedVertexShaderConstantsHint(
uint nMaxReg) {
#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS
return SetMaxUsedVertexShaderConstantsHintNonInline(nMaxReg);
#else
Assert(GetCurrentOwnerThreadId() == ThreadGetCurrentId());
m_ctx->SetMaxUsedVertexShaderConstantsHint(nMaxReg);
#endif
}
// ------------------------------------------------------------------------------------------------------------------------------
// // D3DX
// ------------------------------------------------------------------------------------------------------------------------------
// //
struct ID3DXInclude {
virtual HRESULT Open(D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName,
LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes);
virtual HRESULT Close(LPCVOID pData);
};
typedef ID3DXInclude* LPD3DXINCLUDE;
struct TOGL_CLASS ID3DXBuffer : public IUnknown {
void* GetBufferPointer();
DWORD GetBufferSize();
};
typedef ID3DXBuffer* LPD3DXBUFFER;
class ID3DXConstantTable : public IUnknown {};
typedef ID3DXConstantTable* LPD3DXCONSTANTTABLE;
TOGL_INTERFACE const char* D3DXGetPixelShaderProfile(IDirect3DDevice9* pDevice);
TOGL_INTERFACE D3DXMATRIX* D3DXMatrixMultiply(D3DXMATRIX* pOut,
CONST D3DXMATRIX* pM1,
CONST D3DXMATRIX* pM2);
TOGL_INTERFACE D3DXVECTOR3* D3DXVec3TransformCoord(D3DXVECTOR3* pOut,
CONST D3DXVECTOR3* pV,
CONST D3DXMATRIX* pM);
TOGL_INTERFACE HRESULT D3DXCreateMatrixStack(DWORD Flags,
LPD3DXMATRIXSTACK* ppStack);
TOGL_INTERFACE void D3DXMatrixIdentity(D3DXMATRIX*);
TOGL_INTERFACE D3DXINLINE D3DXVECTOR3* D3DXVec3Subtract(
D3DXVECTOR3* pOut, CONST D3DXVECTOR3* pV1, CONST D3DXVECTOR3* pV2) {
pOut->x = pV1->x - pV2->x;
pOut->y = pV1->y - pV2->y;
pOut->z = pV1->z - pV2->z;
return pOut;
}
TOGL_INTERFACE D3DXINLINE D3DXVECTOR3* D3DXVec3Cross(D3DXVECTOR3* pOut,
CONST D3DXVECTOR3* pV1,
CONST D3DXVECTOR3* pV2) {
D3DXVECTOR3 v;
v.x = pV1->y * pV2->z - pV1->z * pV2->y;
v.y = pV1->z * pV2->x - pV1->x * pV2->z;
v.z = pV1->x * pV2->y - pV1->y * pV2->x;
*pOut = v;
return pOut;
}
TOGL_INTERFACE D3DXINLINE FLOAT D3DXVec3Dot(CONST D3DXVECTOR3* pV1,
CONST D3DXVECTOR3* pV2) {
return pV1->x * pV2->x + pV1->y * pV2->y + pV1->z * pV2->z;
}
TOGL_INTERFACE D3DXMATRIX* D3DXMatrixInverse(D3DXMATRIX* pOut,
FLOAT* pDeterminant,
CONST D3DXMATRIX* pM);
TOGL_INTERFACE D3DXMATRIX* D3DXMatrixTranspose(D3DXMATRIX* pOut,
CONST D3DXMATRIX* pM);
TOGL_INTERFACE D3DXPLANE* D3DXPlaneNormalize(D3DXPLANE* pOut,
CONST D3DXPLANE* pP);
TOGL_INTERFACE D3DXVECTOR4* D3DXVec4Transform(D3DXVECTOR4* pOut,
CONST D3DXVECTOR4* pV,
CONST D3DXMATRIX* pM);
TOGL_INTERFACE D3DXVECTOR4* D3DXVec4Normalize(D3DXVECTOR4* pOut,
CONST D3DXVECTOR4* pV);
TOGL_INTERFACE D3DXMATRIX* D3DXMatrixTranslation(D3DXMATRIX* pOut, FLOAT x,
FLOAT y, FLOAT z);
// Build an ortho projection matrix. (right-handed)
TOGL_INTERFACE D3DXMATRIX* D3DXMatrixOrthoOffCenterRH(D3DXMATRIX* pOut, FLOAT l,
FLOAT r, FLOAT b, FLOAT t,
FLOAT zn, FLOAT zf);
TOGL_INTERFACE D3DXMATRIX* D3DXMatrixPerspectiveRH(D3DXMATRIX* pOut, FLOAT w,
FLOAT h, FLOAT zn, FLOAT zf);
TOGL_INTERFACE D3DXMATRIX* D3DXMatrixPerspectiveOffCenterRH(D3DXMATRIX* pOut,
FLOAT l, FLOAT r,
FLOAT b, FLOAT t,
FLOAT zn, FLOAT zf);
// Transform a plane by a matrix. The vector (a,b,c) must be normal.
// M should be the inverse transpose of the transformation desired.
TOGL_INTERFACE D3DXPLANE* D3DXPlaneTransform(D3DXPLANE* pOut,
CONST D3DXPLANE* pP,
CONST D3DXMATRIX* pM);
TOGL_INTERFACE IDirect3D9* Direct3DCreate9(UINT SDKVersion);
TOGL_INTERFACE void D3DPERF_SetOptions(DWORD dwOptions);
TOGL_INTERFACE HRESULT D3DXCompileShader(LPCSTR pSrcData, UINT SrcDataLen,
CONST D3DXMACRO* pDefines,
LPD3DXINCLUDE pInclude,
LPCSTR pFunctionName, LPCSTR pProfile,
DWORD Flags, LPD3DXBUFFER* ppShader,
LPD3DXBUFFER* ppErrorMsgs,
LPD3DXCONSTANTTABLE* ppConstantTable);
// fake D3D usage constant for SRGB tex creation
#define D3DUSAGE_TEXTURE_SRGB (0x80000000L)
#else
// USE_ACTUAL_DX
#ifndef WIN32
#error sorry man
#endif
#ifdef _X360
#include "d3d9.h"
#include "d3dx9.h"
#else
#include <windows.h>
#include "../../dx9sdk/include/d3d9.h"
#include "../../dx9sdk/include/d3dx9.h"
#endif
typedef HWND VD3DHWND;
#endif // DX_TO_GL_ABSTRACTION
#endif // DXABSTRACT_H