source-engine/public/togles/linuxwin/dxabstract.h
2022-06-19 15:07:41 +03:00

1445 lines
54 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 "togles/rendermechanism.h"
#include "tier0/platform.h"
#include "tier0/dbg.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( uintp ) );
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, DWORD MinLod, float LodBias );
void TOGLMETHODCALLTYPE SetSamplerStatesNonInline(DWORD Sampler, DWORD AddressU, DWORD AddressV, DWORD AddressW, DWORD MinFilter, DWORD MagFilter, DWORD MipFilter, DWORD MinLod, float LodBias );
#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 uintp 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, DWORD MinLod,
float LodBias)
{
#if GLMDEBUG || GL_BATCH_PERF_ANALYSIS
SetSamplerStatesNonInline( Sampler, AddressU, AddressV, AddressW, MinFilter, MagFilter, MipFilter, MinLod, LodBias );
#else
Assert( GetCurrentOwnerThreadId() == ThreadGetCurrentId() );
Assert( Sampler < GLM_SAMPLER_COUNT);
m_ctx->SetSamplerDirty( Sampler );
m_ctx->SetSamplerStates( Sampler, AddressU, AddressV, AddressW, MinFilter, MagFilter, MipFilter, MinLod, LodBias );
#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