6367 lines
220 KiB
C++
6367 lines
220 KiB
C++
![]() |
/**********************************************************************
|
||
|
|
||
|
Filename : GRendererD3DxImpl.cpp
|
||
|
Content : Direct3D 8 & 9 Sample renderer implementation
|
||
|
Created :
|
||
|
Authors : Michael Antonov
|
||
|
|
||
|
Copyright : (c) 2001-2006 Scaleform Corp. All Rights Reserved.
|
||
|
|
||
|
Notes :
|
||
|
|
||
|
Licensees may use this file in accordance with the valid Scaleform
|
||
|
Commercial License Agreement provided with the software.
|
||
|
|
||
|
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
|
||
|
THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE.
|
||
|
|
||
|
**********************************************************************/
|
||
|
|
||
|
|
||
|
#include "GImage.h"
|
||
|
#include "GAtomic.h"
|
||
|
#include "GArray.h"
|
||
|
#include "GStd.h"
|
||
|
#include "GHash.h"
|
||
|
#include "GString.h"
|
||
|
#include "GMsgFormat.h"
|
||
|
#if defined(GFC_OS_WIN32)
|
||
|
#include <windows.h>
|
||
|
#endif
|
||
|
|
||
|
#include "GRendererCommonImpl.h"
|
||
|
#include <string.h> // for memset()
|
||
|
|
||
|
#ifndef GFC_D3D_VERSION
|
||
|
#define GFC_D3D_VERSION 9
|
||
|
#endif
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
|
||
|
#include "GRendererD3D9.h"
|
||
|
|
||
|
//#define GRENDERER_USE_PS11
|
||
|
//#define GRENDERER_USE_PS20
|
||
|
|
||
|
#if defined(GFC_BUILD_DEFINE_NEW) && defined(GFC_DEFINE_NEW)
|
||
|
#undef new
|
||
|
#endif
|
||
|
#include <d3d9.h>
|
||
|
#include <d3dx9.h>
|
||
|
#if defined(GFC_BUILD_DEFINE_NEW) && defined(GFC_DEFINE_NEW)
|
||
|
#define new GFC_DEFINE_NEW
|
||
|
#endif
|
||
|
|
||
|
// MOOSE - TODO support asm shaders in 3D
|
||
|
#ifndef GFC_NO_3D
|
||
|
#if 0 // def GRENDERER_USE_PS11
|
||
|
#include "ShadersD3D9/asm11.cpp"
|
||
|
#elif 0 // defined(GRENDERER_USE_PS20)
|
||
|
#include "ShadersD3D9/asm20.cpp"
|
||
|
#else
|
||
|
#include "ShadersD3D9/hlsl.cpp"
|
||
|
#endif
|
||
|
#else
|
||
|
#include "ShadersD3D9/hlsl.cpp"
|
||
|
#endif
|
||
|
|
||
|
#include "D3D9/D3D9BinaryShaders.cpp"
|
||
|
#include "D3D9/D3D9Shaders.h"
|
||
|
|
||
|
#define GRendererD3Dx GRendererD3D9
|
||
|
#define GTextureD3Dx GTextureD3D9
|
||
|
#define GRendererD3DxImpl GRendererD3D9Impl
|
||
|
#define GTextureD3DxImpl GTextureD3D9Impl
|
||
|
#define GDynamicVertexStream GDynamicVertexStreamD3D9
|
||
|
|
||
|
#define IDirect3DDeviceX IDirect3DDevice9
|
||
|
#define IDirect3DResourceX IDirect3DResource9
|
||
|
#define IDirect3DTextureX IDirect3DTexture9
|
||
|
#define IDirect3DSurfaceX IDirect3DSurface9
|
||
|
#define IDirect3DIndexBufferX IDirect3DIndexBuffer9
|
||
|
#define IDirect3DVertexBufferX IDirect3DVertexBuffer9
|
||
|
#define D3DCAPSx D3DCAPS9
|
||
|
#define D3DVIEWPORTx D3DVIEWPORT9
|
||
|
#define LPDIRECT3Dx LPDIRECT3D9
|
||
|
#define LPDIRECT3DDEVICEx LPDIRECT3DDEVICE9
|
||
|
|
||
|
#define SetVertexShaderConstant SetVertexShaderConstantF
|
||
|
#define SetPixelShaderConstant SetPixelShaderConstantF
|
||
|
|
||
|
// Used for functions that have an extra last argument of NULL in D3D9 only
|
||
|
#define NULL9 , NULL
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
|
||
|
#include "GRendererD3D8.h"
|
||
|
|
||
|
#if defined(GFC_BUILD_DEFINE_NEW) && defined(GFC_DEFINE_NEW)
|
||
|
#undef new
|
||
|
#endif
|
||
|
#include <d3d8.h>
|
||
|
#include <d3dx8.h>
|
||
|
#if defined(GFC_BUILD_DEFINE_NEW) && defined(GFC_DEFINE_NEW)
|
||
|
#define new GFC_DEFINE_NEW
|
||
|
#endif
|
||
|
|
||
|
#define GRENDERER_USE_PS11
|
||
|
#include "ShadersD3D8/asm11.cpp"
|
||
|
|
||
|
#define GRendererD3Dx GRendererD3D8
|
||
|
#define GTextureD3Dx GTextureD3D8
|
||
|
#define GRendererD3DxImpl GRendererD3D8Impl
|
||
|
#define GTextureD3DxImpl GTextureD3D8Impl
|
||
|
#define GDynamicVertexStream GDynamicVertexStreamD3D8
|
||
|
|
||
|
#define IDirect3DDeviceX IDirect3DDevice8
|
||
|
#define IDirect3DResourceX IDirect3DResource8
|
||
|
#define IDirect3DTextureX IDirect3DTexture8
|
||
|
#define IDirect3DSurfaceX IDirect3DSurface8
|
||
|
#define IDirect3DIndexBufferX IDirect3DIndexBuffer8
|
||
|
#define IDirect3DVertexBufferX IDirect3DVertexBuffer8
|
||
|
#define D3DCAPSx D3DCAPS8
|
||
|
#define D3DVIEWPORTx D3DVIEWPORT8
|
||
|
#define LPDIRECT3Dx LPDIRECT3D8
|
||
|
#define LPDIRECT3DDEVICEx LPDIRECT3DDEVICE8
|
||
|
|
||
|
// Used for functions that have an extra last argument of NULL in D3D9 only
|
||
|
#define NULL9
|
||
|
|
||
|
#else
|
||
|
#error Define GFC_D3D_VERSION to 8 or 9
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// ***** Classes implemented
|
||
|
class GRendererD3DxImpl;
|
||
|
class GTextureD3DxImpl;
|
||
|
|
||
|
|
||
|
// ***** GTextureD3DxImpl implementation
|
||
|
|
||
|
|
||
|
// GTextureD3DxImpl declaration
|
||
|
class GTextureD3DxImpl : public GTextureD3Dx
|
||
|
{
|
||
|
public:
|
||
|
D3DFORMAT TextureFormat;
|
||
|
bool IsManaged;
|
||
|
|
||
|
// Renderer
|
||
|
GRendererD3DxImpl* pRenderer;
|
||
|
SInt TexWidth, TexHeight;
|
||
|
SInt Mipmaps;
|
||
|
|
||
|
// D3Dx Texture pointer
|
||
|
IDirect3DTextureX* pD3DTexture;
|
||
|
|
||
|
GTextureD3DxImpl(GRendererD3DxImpl *prenderer);
|
||
|
~GTextureD3DxImpl();
|
||
|
|
||
|
virtual void ReleaseTexture();
|
||
|
|
||
|
// Obtains the renderer that create TextureInfo
|
||
|
virtual GRenderer* GetRenderer() const;
|
||
|
virtual bool IsDataValid() const;
|
||
|
|
||
|
// Init Texture implementation.
|
||
|
virtual bool InitTexture(IDirect3DTextureX *ptex, bool Managed = 0);
|
||
|
virtual bool InitTexture(GImageBase* pim, UInt usage = Usage_Wrap);
|
||
|
virtual bool InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage);
|
||
|
virtual void Update(int level, int n, const UpdateRect *rects, const GImageBase *pim);
|
||
|
|
||
|
virtual int Map(int level, int n, MapRect* maps, int flags);
|
||
|
virtual bool Unmap(int level, int n, MapRect* maps, int flags);
|
||
|
virtual bool LoadFromImage(GImageBase* sourceImg);
|
||
|
|
||
|
// Remove texture from renderer, notifies of renderer destruction
|
||
|
void RemoveFromRenderer();
|
||
|
|
||
|
virtual IDirect3DTextureX* GetNativeTexture() const { return pD3DTexture; }
|
||
|
|
||
|
virtual int IsYUVTexture() { return 0; }
|
||
|
virtual void Bind(int stage, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps);
|
||
|
};
|
||
|
|
||
|
class GTextureD3DxImplYUV : public GTextureD3DxImpl
|
||
|
{
|
||
|
public:
|
||
|
bool IsAlpha;
|
||
|
IDirect3DTextureX* pD3DTextureUVA[3];
|
||
|
|
||
|
GTextureD3DxImplYUV(GRendererD3DxImpl *prenderer) : GTextureD3DxImpl(prenderer)
|
||
|
{ pD3DTextureUVA[0] = pD3DTextureUVA[1] = pD3DTextureUVA[2] = 0; }
|
||
|
~GTextureD3DxImplYUV();
|
||
|
|
||
|
virtual bool InitTexture(IDirect3DTextureX *, bool = 0) { return 0; }
|
||
|
virtual bool InitTexture(GImageBase*, UInt = Usage_Wrap) { return 0; }
|
||
|
virtual void Update(int, int, const UpdateRect *, const GImageBase *) { }
|
||
|
|
||
|
virtual bool InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage);
|
||
|
virtual int Map(int level, int n, MapRect* maps, int flags);
|
||
|
virtual bool Unmap(int level, int n, MapRect* maps, int flags);
|
||
|
|
||
|
virtual void ReleaseTexture();
|
||
|
|
||
|
virtual int IsYUVTexture() { return IsAlpha ? 2 : 1; }
|
||
|
virtual void Bind(int stage, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps);
|
||
|
};
|
||
|
|
||
|
class GDepthBufferD3D9Impl : public GTextureD3DxImpl
|
||
|
{
|
||
|
public:
|
||
|
IDirect3DSurfaceX* pDepthStencil;
|
||
|
|
||
|
GDepthBufferD3D9Impl(GRendererD3DxImpl *prenderer) : GTextureD3DxImpl(prenderer)
|
||
|
{ pDepthStencil = 0; }
|
||
|
~GDepthBufferD3D9Impl();
|
||
|
|
||
|
virtual bool IsDataValid() const { return pDepthStencil != 0; }
|
||
|
virtual bool InitTexture(IDirect3DTextureX *, bool = 0) { return 0; }
|
||
|
virtual bool InitTexture(GImageBase*, UInt = Usage_Wrap) { return 0; }
|
||
|
virtual void Update(int, int, const UpdateRect *, const GImageBase *) { }
|
||
|
|
||
|
virtual bool InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage);
|
||
|
virtual int Map(int, int, MapRect*, int) { return 0; }
|
||
|
virtual bool Unmap(int, int, MapRect*, int) { return 0; }
|
||
|
|
||
|
virtual void ReleaseTexture();
|
||
|
};
|
||
|
|
||
|
class GRenderTargetD3D9Impl : public GRenderTargetD3D9
|
||
|
{
|
||
|
public:
|
||
|
UInt TargetWidth, TargetHeight;
|
||
|
GRendererD3DxImpl* pRenderer;
|
||
|
GPtr<GTextureD3DxImpl> pTexture; // if this is non-null, then pRenderSurface is NULL
|
||
|
IDirect3DSurfaceX* pRenderSurface; // if this is non-null, then pTexture is NULL
|
||
|
GPtr<GDepthBufferD3D9Impl> pStencilTexture; // if this is non-null, then pRenderSurface is NULL
|
||
|
IDirect3DSurfaceX* pStencilSurface; // if this is non-null, then pStencilTexture is NULL
|
||
|
bool IsTemp;
|
||
|
|
||
|
GRenderTargetD3D9Impl(GRendererD3DxImpl *pRend);
|
||
|
~GRenderTargetD3D9Impl();
|
||
|
|
||
|
virtual GRenderer* GetRenderer() const;
|
||
|
void RemoveFromRenderer();
|
||
|
void ReleaseResources();
|
||
|
|
||
|
virtual bool InitRenderTarget(GTexture *ptarget, GTexture* pdepth = 0, GTexture* pstencil = 0);
|
||
|
virtual bool InitRenderTarget(D3D9RenderTargetParams RTParams);
|
||
|
};
|
||
|
|
||
|
// ***** Vertex Declarations and Shaders
|
||
|
|
||
|
// Vertex shader declarations we can use
|
||
|
enum VDeclType
|
||
|
{
|
||
|
VD_None,
|
||
|
VD_Strip,
|
||
|
VD_Glyph,
|
||
|
VD_XY16iC32,
|
||
|
VD_XY16iCF32,
|
||
|
VD_Count
|
||
|
};
|
||
|
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
|
||
|
// Our vertex coords consist of two signed 16-bit integers, for (x,y) position only.
|
||
|
static D3DVERTEXELEMENT9 StripVertexDecl[] =
|
||
|
{
|
||
|
{0, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
||
|
D3DDECL_END()
|
||
|
};
|
||
|
static D3DVERTEXELEMENT9 GlyphVertexDecl[] =
|
||
|
{
|
||
|
{0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
||
|
{0, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
|
||
|
{0,16, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
|
||
|
D3DDECL_END()
|
||
|
};
|
||
|
|
||
|
// Gouraud vertices used with Edge AA
|
||
|
static D3DVERTEXELEMENT9 VertexDeclXY16iC32[] =
|
||
|
{
|
||
|
{0, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
||
|
{0, 4, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
|
||
|
D3DDECL_END()
|
||
|
};
|
||
|
static D3DVERTEXELEMENT9 VertexDeclXY16iCF32[] =
|
||
|
{
|
||
|
{0, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
||
|
{0, 4, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
|
||
|
{0, 8, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1 },
|
||
|
D3DDECL_END()
|
||
|
};
|
||
|
|
||
|
// old shaders
|
||
|
static D3DVERTEXELEMENT9 GlyphVertexDecl_Szc[] =
|
||
|
{
|
||
|
{0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
||
|
{0, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
|
||
|
{0,16, D3DDECLTYPE_D3DCOLOR,D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
|
||
|
D3DDECL_END()
|
||
|
};
|
||
|
static D3DVERTEXELEMENT9 VertexDeclXY16iC32_Szc[] =
|
||
|
{
|
||
|
{0, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
||
|
{0, 4, D3DDECLTYPE_D3DCOLOR,D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
|
||
|
D3DDECL_END()
|
||
|
};
|
||
|
static D3DVERTEXELEMENT9 VertexDeclXY16iCF32_Szc[] =
|
||
|
{
|
||
|
{0, 0, D3DDECLTYPE_SHORT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
||
|
{0, 4, D3DDECLTYPE_D3DCOLOR,D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
|
||
|
{0, 8, D3DDECLTYPE_D3DCOLOR,D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1 },
|
||
|
D3DDECL_END()
|
||
|
};
|
||
|
|
||
|
// Vertex declaration lookup table, must correspond to VDeclType +1
|
||
|
static const D3DVERTEXELEMENT9 *VertexDeclTypeTable[VD_Count*2 - 2] =
|
||
|
{
|
||
|
StripVertexDecl,
|
||
|
GlyphVertexDecl,
|
||
|
VertexDeclXY16iC32,
|
||
|
VertexDeclXY16iCF32,
|
||
|
|
||
|
StripVertexDecl,
|
||
|
GlyphVertexDecl_Szc,
|
||
|
VertexDeclXY16iC32_Szc,
|
||
|
VertexDeclXY16iCF32_Szc
|
||
|
};
|
||
|
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
|
||
|
static DWORD StripVertexDecl[] = {
|
||
|
D3DVSD_STREAM(0),
|
||
|
D3DVSD_REG(0, D3DVSDT_SHORT2),
|
||
|
D3DVSD_END()
|
||
|
};
|
||
|
|
||
|
static DWORD GlyphVertexDecl_Szc[] = {
|
||
|
D3DVSD_STREAM(0),
|
||
|
D3DVSD_REG(0, D3DVSDT_FLOAT2),
|
||
|
D3DVSD_REG(7, D3DVSDT_FLOAT2),
|
||
|
D3DVSD_REG(5, D3DVSDT_D3DCOLOR),
|
||
|
D3DVSD_END()
|
||
|
};
|
||
|
|
||
|
static DWORD VertexDeclXY16iC32_Szc[] = {
|
||
|
D3DVSD_STREAM(0),
|
||
|
D3DVSD_REG(0, D3DVSDT_SHORT2),
|
||
|
D3DVSD_REG(5, D3DVSDT_D3DCOLOR),
|
||
|
D3DVSD_END()
|
||
|
};
|
||
|
|
||
|
static DWORD VertexDeclXY16iCF32_Szc[] = {
|
||
|
D3DVSD_STREAM(0),
|
||
|
D3DVSD_REG(0, D3DVSDT_SHORT2),
|
||
|
D3DVSD_REG(5, D3DVSDT_D3DCOLOR),
|
||
|
D3DVSD_REG(6, D3DVSDT_D3DCOLOR),
|
||
|
D3DVSD_END()
|
||
|
};
|
||
|
|
||
|
static DWORD* VertexDeclTable[VD_Count] =
|
||
|
{
|
||
|
0,
|
||
|
StripVertexDecl,
|
||
|
GlyphVertexDecl_Szc,
|
||
|
VertexDeclXY16iC32_Szc,
|
||
|
VertexDeclXY16iCF32_Szc
|
||
|
};
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
enum VShaderType
|
||
|
{
|
||
|
VS_None,
|
||
|
VS_Strip,
|
||
|
VS_Glyph,
|
||
|
VS_XY16iC32,
|
||
|
VS_XY16iCF32,
|
||
|
VS_XY16iCF32_T2,
|
||
|
VS_Count
|
||
|
};
|
||
|
|
||
|
// Vertex shader text lookup table, must correspond to VShaderType +1
|
||
|
static const char *VertexShaderTextTable[VS_Count*2 - 2] =
|
||
|
{
|
||
|
pStripVShaderText,
|
||
|
pGlyphVShaderText,
|
||
|
pStripVShaderXY16iC32Text,
|
||
|
pStripVShaderXY16iCF32Text,
|
||
|
pStripVShaderXY16iCF32_T2Text,
|
||
|
|
||
|
pStripVShaderText,
|
||
|
|
||
|
// swap color channel
|
||
|
pGlyphVShaderSzcText,
|
||
|
pStripVShaderXY16iC32SzcText,
|
||
|
pStripVShaderXY16iCF32SzcText,
|
||
|
pStripVShaderXY16iCF32Szc_T2Text
|
||
|
};
|
||
|
|
||
|
static const VDeclType VertexShaderDeclTable[VS_Count] =
|
||
|
{
|
||
|
VD_None,
|
||
|
VD_Strip,
|
||
|
VD_Glyph,
|
||
|
VD_XY16iC32,
|
||
|
VD_XY16iCF32,
|
||
|
VD_XY16iCF32,
|
||
|
};
|
||
|
|
||
|
// Vertex buffer structure used for glyphs.
|
||
|
struct GGlyphVertex
|
||
|
{
|
||
|
float x,y;
|
||
|
float u,v;
|
||
|
GColor color;
|
||
|
|
||
|
void SetVertex2D(float xx, float yy, float uu, float vv, GColor c)
|
||
|
{
|
||
|
x = xx; y = yy; u = uu; v = vv;
|
||
|
color = c;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
// Pixel shaders
|
||
|
enum PixelShaderType
|
||
|
{
|
||
|
PS_None = 0,
|
||
|
PS_SolidColor,
|
||
|
PS_CxformTexture,
|
||
|
PS_CxformTextureMultiply,
|
||
|
PS_TintTexture,
|
||
|
PS_TintTextureMultiply,
|
||
|
PS_TextTextureAlpha,
|
||
|
PS_TextTextureColor,
|
||
|
PS_TextTextureColorMultiply,
|
||
|
PS_TextTextureYUV,
|
||
|
PS_TextTextureYUVMultiply,
|
||
|
PS_TextTextureYUVA,
|
||
|
PS_TextTextureYUVAMultiply,
|
||
|
|
||
|
PS_CxformGauraud,
|
||
|
PS_CxformGauraudNoAddAlpha,
|
||
|
PS_CxformGauraudTexture,
|
||
|
PS_Cxform2Texture,
|
||
|
|
||
|
// Multiplies - must come in same order as other gourauds
|
||
|
PS_CxformGauraudMultiply,
|
||
|
PS_CxformGauraudMultiplyNoAddAlpha,
|
||
|
PS_CxformGauraudMultiplyTexture,
|
||
|
PS_CxformMultiply2Texture,
|
||
|
|
||
|
PS_CmatrixTexture,
|
||
|
PS_CmatrixTextureMultiply,
|
||
|
|
||
|
// premultiplied alpha
|
||
|
PS_AcNone,
|
||
|
PS_AcSolidColor,
|
||
|
PS_AcCxformTexture,
|
||
|
PS_AcCxformTextureMultiply,
|
||
|
PS_AcTintTexture,
|
||
|
PS_AcTintTextureMultiply,
|
||
|
PS_AcTextTextureAlpha,
|
||
|
PS_AcTextTextureColor,
|
||
|
PS_AcTextTextureColorMultiply,
|
||
|
PS_AcTextTextureYUV,
|
||
|
PS_AcTextTextureYUVMultiply,
|
||
|
PS_AcTextTextureYUVA,
|
||
|
PS_AcTextTextureYUVAMultiply,
|
||
|
|
||
|
PS_AcCxformGouraud,
|
||
|
PS_AcCxformGouraudNoAddAlpha,
|
||
|
PS_AcCxformGouraudTexture,
|
||
|
PS_AcCxform2Texture,
|
||
|
|
||
|
PS_AcCxformGouraudMultiply,
|
||
|
PS_AcCxformGouraudMultiplyNoAddAlpha,
|
||
|
PS_AcCxformGouraudMultiplyTexture,
|
||
|
PS_AcCxformMultiply2Texture,
|
||
|
|
||
|
PS_AcCmatrixTexture,
|
||
|
PS_AcCmatrixTextureMultiply,
|
||
|
|
||
|
PS_Count,
|
||
|
PS_CountSource = PS_AcNone,
|
||
|
PS_CountAcSource = PS_CmatrixTexture,
|
||
|
PS_AcOffset = PS_AcCxformTexture-PS_CxformTexture,
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
// Pixel shader constants assignments, maintained through driver
|
||
|
//
|
||
|
// c0 -> constant solid color
|
||
|
//
|
||
|
// c2, c3 -> cxform
|
||
|
//
|
||
|
|
||
|
|
||
|
struct TextureStageDesc
|
||
|
{
|
||
|
DWORD Stage; // -1 for last state
|
||
|
D3DTEXTURESTAGESTATETYPE State;
|
||
|
DWORD Value;
|
||
|
};
|
||
|
|
||
|
struct PixelShaderDesc
|
||
|
{
|
||
|
// Shader, used if not mull.
|
||
|
const char* pShader;
|
||
|
|
||
|
// Texture stage descriptors otherwise.
|
||
|
const TextureStageDesc* pPass0Desc;
|
||
|
const TextureStageDesc* pPass1Desc;
|
||
|
};
|
||
|
|
||
|
|
||
|
/* *** Fixed Function Pipeline Support Notes
|
||
|
|
||
|
Texture stages below try to replicate the necessary shader behavior with fixed
|
||
|
function pipeline texture stages. However, there a number of FF limitations that
|
||
|
make this challenging or impossible.
|
||
|
|
||
|
Specifically:
|
||
|
|
||
|
1. Only one texture factor (D3DTA_TFACTOR) means that we can only
|
||
|
implement Multiply color matrix component. We try to work around
|
||
|
that by adding a second additive pass, but the math does not work
|
||
|
out correctly; which means that all Cxforms are not supported right.
|
||
|
|
||
|
2. Cxform ARE supported correctly for Non-EdgeAA solid fills, but
|
||
|
only because they are implemented in software.
|
||
|
|
||
|
3. EdgeAA with texturing is difficult to support due to the fact
|
||
|
that we need (1) Color with alpha (2) Texture/Color mixing factor
|
||
|
and (3) EdgeAA blend value. The (1) comes in as DIFFUSE, while
|
||
|
(2) + (3) are packed into SPECULAR. However, there does not seem
|
||
|
to be a direct way to use SPECULAR RGB channels to control blending.
|
||
|
|
||
|
There is probably a way to support FF pipeline at least partially with
|
||
|
textures, however, it would require complicated setup and would probably
|
||
|
produce even more problems with color matrix. For now, we just do not
|
||
|
report the Cap_FillGouraudTex flag, which means that player will not
|
||
|
pass textures to FillStyleGouraud. Hence, solid-color using shapes and
|
||
|
strokes will get EdgeAA, while textured shapes will not.
|
||
|
*/
|
||
|
|
||
|
|
||
|
// Solid color: take color from factor.
|
||
|
static const TextureStageDesc pStates_TS_SolidColor[] =
|
||
|
{
|
||
|
{ 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 },
|
||
|
{ 0, D3DTSS_COLORARG2, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 },
|
||
|
{ 0, D3DTSS_ALPHAARG2, D3DTA_TFACTOR },
|
||
|
{ (DWORD)-1, D3DTSS_FORCE_DWORD, 0 }
|
||
|
};
|
||
|
|
||
|
// Texture with color matrix.
|
||
|
// Factor = ColorMatrix multiply
|
||
|
static const TextureStageDesc pStates_TS_CxformTexture[] =
|
||
|
{
|
||
|
{ 0, D3DTSS_COLOROP, D3DTOP_MODULATE }, // C * Mc
|
||
|
{ 0, D3DTSS_COLORARG2, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_COLORARG1, D3DTA_TEXTURE },
|
||
|
{ 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE }, // A * Ma
|
||
|
{ 0, D3DTSS_ALPHAARG2, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE },
|
||
|
{ (DWORD)-1, D3DTSS_FORCE_DWORD, 0 }
|
||
|
};
|
||
|
// Second stage, attempts to add Ac and Aa of color matrix, but incorrectly
|
||
|
// (correct implementation impossible without shaders since we only have 1 texture factor).
|
||
|
static const TextureStageDesc pStates_TS_CxformTexture_Add[] =
|
||
|
{
|
||
|
{ 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 }, // + Ac (from factor)
|
||
|
{ 0, D3DTSS_COLORARG2, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 }, // + (Ca)
|
||
|
{ 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE },
|
||
|
//{ 0, D3DTSS_ALPHAARG2, D3DTA_TFACTOR },
|
||
|
{ (DWORD)-1, D3DTSS_FORCE_DWORD, 0 }
|
||
|
};
|
||
|
|
||
|
|
||
|
// Texture with color matrix.
|
||
|
static const TextureStageDesc pStates_TS_CxformTextureMultiply[] =
|
||
|
{
|
||
|
{ 0, D3DTSS_COLOROP, D3DTOP_MODULATE }, // C * Mc
|
||
|
{ 0, D3DTSS_COLORARG2, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_COLORARG1, D3DTA_TEXTURE },
|
||
|
{ 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE }, // A * Ma
|
||
|
{ 0, D3DTSS_ALPHAARG2, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE },
|
||
|
// Hacky:
|
||
|
// We need to get WHITE from somewhere, but diffuse, specular and TFACTOR are
|
||
|
// already in use. Per-stage constants are not supported on most HW.
|
||
|
// D3DTA_TEMP, however, is supported and defined to have a default value of 0.
|
||
|
// Alternative: use single-colored textures.
|
||
|
{ 1, D3DTSS_COLOROP, D3DTOP_BLENDCURRENTALPHA },
|
||
|
{ 1, D3DTSS_COLORARG1, D3DTA_CURRENT },
|
||
|
{ 1, D3DTSS_COLORARG2, D3DTA_TEMP | D3DTA_COMPLEMENT }, // 1.0
|
||
|
{ 1, D3DTSS_ALPHAOP, D3DTOP_BLENDCURRENTALPHA },
|
||
|
{ 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT },
|
||
|
{ 1, D3DTSS_ALPHAARG2, D3DTA_TEMP | D3DTA_COMPLEMENT }, // 1.0
|
||
|
{ (DWORD)-1, D3DTSS_FORCE_DWORD, 0 }
|
||
|
};
|
||
|
|
||
|
// Texture with 100% Tint color matrix.
|
||
|
static const TextureStageDesc pStates_TS_TintTexture[] =
|
||
|
{
|
||
|
{ 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 }, // Mc (used as add)
|
||
|
{ 0, D3DTSS_COLORARG1, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE }, // A * Ma
|
||
|
{ 0, D3DTSS_ALPHAARG2, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE },
|
||
|
{ (DWORD)-1, D3DTSS_FORCE_DWORD, 0 }
|
||
|
};
|
||
|
|
||
|
// Texture with 100% Tint color matrix.
|
||
|
static const TextureStageDesc pStates_TS_TintTextureMultiply[] =
|
||
|
{
|
||
|
{ 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 }, // Mc (used as add)
|
||
|
{ 0, D3DTSS_COLORARG1, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE }, // A * Ma
|
||
|
{ 0, D3DTSS_ALPHAARG2, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE },
|
||
|
{ 1, D3DTSS_COLOROP, D3DTOP_BLENDCURRENTALPHA },
|
||
|
{ 1, D3DTSS_COLORARG1, D3DTA_CURRENT },
|
||
|
{ 1, D3DTSS_COLORARG2, D3DTA_TEMP | D3DTA_COMPLEMENT }, // 1.0
|
||
|
{ 1, D3DTSS_ALPHAOP, D3DTOP_BLENDCURRENTALPHA },
|
||
|
{ 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT },
|
||
|
{ 1, D3DTSS_ALPHAARG2, D3DTA_TEMP | D3DTA_COMPLEMENT }, // 1.0
|
||
|
{ (DWORD)-1, D3DTSS_FORCE_DWORD, 0 }
|
||
|
};
|
||
|
|
||
|
// Text rendering.
|
||
|
static const TextureStageDesc pStates_TS_TextTextureAlpha[] =
|
||
|
{
|
||
|
{ 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 }, // Text color
|
||
|
{ 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE },
|
||
|
{ 0, D3DTSS_COLORARG1, D3DTA_TEXTURE },
|
||
|
{ 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE }, // Glyph bitmap alpha * Text alpha
|
||
|
{ 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE },
|
||
|
{ 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE },
|
||
|
{ (DWORD)-1, D3DTSS_FORCE_DWORD, 0 }
|
||
|
};
|
||
|
|
||
|
static const TextureStageDesc pStates_TS_TextTextureColor[] =
|
||
|
{
|
||
|
{ 0, D3DTSS_COLOROP, D3DTOP_MODULATE },
|
||
|
{ 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE },
|
||
|
{ 0, D3DTSS_COLORARG1, D3DTA_TEXTURE },
|
||
|
{ 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE },
|
||
|
{ 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE },
|
||
|
{ 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE },
|
||
|
{ (DWORD)-1, D3DTSS_FORCE_DWORD, 0 }
|
||
|
};
|
||
|
|
||
|
static const TextureStageDesc pStates_TS_TextTextureColorMultiply[] =
|
||
|
{
|
||
|
{ 0, D3DTSS_COLOROP, D3DTOP_MODULATE },
|
||
|
{ 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE },
|
||
|
{ 0, D3DTSS_COLORARG1, D3DTA_TEXTURE },
|
||
|
{ 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE },
|
||
|
{ 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE },
|
||
|
{ 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE },
|
||
|
// Hacky:
|
||
|
// We need to get WHITE from somewhere, but diffuse, specular and TFACTOR are
|
||
|
// already in use. Per-stage constants are not supported on most HW.
|
||
|
// D3DTA_TEMP, however, is supported and defined to have a default value of 0.
|
||
|
// Alternative: use single-colored textures.
|
||
|
{ 1, D3DTSS_COLOROP, D3DTOP_BLENDCURRENTALPHA },
|
||
|
{ 1, D3DTSS_COLORARG1, D3DTA_CURRENT },
|
||
|
{ 1, D3DTSS_COLORARG2, D3DTA_TEMP | D3DTA_COMPLEMENT }, // 1.0
|
||
|
{ 1, D3DTSS_ALPHAOP, D3DTOP_BLENDCURRENTALPHA },
|
||
|
{ 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT },
|
||
|
{ 1, D3DTSS_ALPHAARG2, D3DTA_TEMP | D3DTA_COMPLEMENT }, // 1.0
|
||
|
{ (DWORD)-1, D3DTSS_FORCE_DWORD, 0 }
|
||
|
};
|
||
|
|
||
|
// Last stage for alpha compositing.
|
||
|
static const TextureStageDesc pStates_TS_AlphaComposite[] =
|
||
|
{
|
||
|
{ 0, D3DTSS_COLOROP, D3DTOP_MODULATE },
|
||
|
{ 0, D3DTSS_COLORARG1, D3DTA_CURRENT },
|
||
|
{ 0, D3DTSS_COLORARG2, D3DTA_CURRENT | D3DTA_ALPHAREPLICATE },
|
||
|
{ 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 },
|
||
|
{ 0, D3DTSS_ALPHAARG1, D3DTA_CURRENT },
|
||
|
{ (DWORD)-1, D3DTSS_FORCE_DWORD, 0 }
|
||
|
};
|
||
|
|
||
|
|
||
|
// ***** Edge-AA versions.
|
||
|
|
||
|
// Texture with color matrix.
|
||
|
// Factor = ColorMatrix multiply
|
||
|
static const TextureStageDesc pStates_TS_CxformGauraud[] =
|
||
|
{
|
||
|
{ 0, D3DTSS_COLOROP, D3DTOP_MODULATE }, // C * Mc
|
||
|
{ 0, D3DTSS_COLORARG1, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE },
|
||
|
{ 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE }, // A * Ma
|
||
|
{ 0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE },
|
||
|
// EdgeAA:
|
||
|
{ 1, D3DTSS_COLOROP, D3DTOP_SELECTARG1 },
|
||
|
{ 1, D3DTSS_COLORARG1, D3DTA_CURRENT },
|
||
|
{ 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE }, // A * Ma
|
||
|
{ 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT },
|
||
|
{ 1, D3DTSS_ALPHAARG2, D3DTA_SPECULAR },
|
||
|
{ (DWORD)-1, D3DTSS_FORCE_DWORD, 0 }
|
||
|
};
|
||
|
static const TextureStageDesc pStates_TS_CxformGauraud_Add[] =
|
||
|
{
|
||
|
{ 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 }, // + Ac (from factor)
|
||
|
{ 0, D3DTSS_COLORARG2, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE }, // + (Ca)
|
||
|
{ 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE },
|
||
|
{ 0, D3DTSS_ALPHAARG2, D3DTA_SPECULAR },
|
||
|
{ (DWORD)-1, D3DTSS_FORCE_DWORD, 0 }
|
||
|
};
|
||
|
|
||
|
|
||
|
// Factor = ColorMatrix multiply
|
||
|
static const TextureStageDesc pStates_TS_CxformGauraudNoAddAlpha[] =
|
||
|
{
|
||
|
{ 0, D3DTSS_COLOROP, D3DTOP_MODULATE }, // C * Mc
|
||
|
{ 0, D3DTSS_COLORARG1, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE },
|
||
|
{ 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE }, // A * Ma
|
||
|
{ 0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE },
|
||
|
{ (DWORD)-1, D3DTSS_FORCE_DWORD, 0 }
|
||
|
};
|
||
|
static const TextureStageDesc pStates_TS_CxformGauraudNoAddAlpha_Add[] =
|
||
|
{
|
||
|
{ 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 }, // + Ac (from factor)
|
||
|
{ 0, D3DTSS_COLORARG1, D3DTA_TFACTOR },
|
||
|
{ 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 }, // + (Ca)
|
||
|
{ 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE },
|
||
|
//{ 0, D3DTSS_ALPHAARG2, D3DTA_SPECULAR },
|
||
|
{ (DWORD)-1, D3DTSS_FORCE_DWORD, 0 }
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
PixelShaderDesc PixelShaderInitTable[PS_Count] =
|
||
|
{
|
||
|
// Non-AA Shaders.
|
||
|
{ pSource_PS_SolidColor, pStates_TS_SolidColor, 0 },
|
||
|
{ pSource_PS_CxformTexture, pStates_TS_CxformTexture, pStates_TS_CxformTexture_Add },
|
||
|
{ pSource_PS_CxformTextureMultiply, pStates_TS_CxformTextureMultiply, 0 },
|
||
|
{ 0, pStates_TS_TintTexture, 0 },
|
||
|
{ 0, pStates_TS_TintTextureMultiply, 0 },
|
||
|
{ pSource_PS_TextTextureAlpha, pStates_TS_TextTextureAlpha, 0 },
|
||
|
{ pSource_PS_TextTextureColor, pStates_TS_TextTextureColor, pStates_TS_CxformTexture_Add},
|
||
|
{ pSource_PS_TextTextureColorMultiply, pStates_TS_TextTextureColorMultiply, 0 },
|
||
|
{ pSource_PS_TextTextureYUV, pStates_TS_SolidColor, 0 },
|
||
|
{ pSource_PS_TextTextureYUVMultiply, pStates_TS_SolidColor, 0 },
|
||
|
{ pSource_PS_TextTextureYUVA, pStates_TS_SolidColor, 0 },
|
||
|
{ pSource_PS_TextTextureYUVAMultiply, pStates_TS_SolidColor, 0 },
|
||
|
|
||
|
// AA Shaders.
|
||
|
{ pSource_PS_CxformGauraud, pStates_TS_CxformGauraud, pStates_TS_CxformGauraud_Add },
|
||
|
{ pSource_PS_CxformGauraudNoAddAlpha, pStates_TS_CxformGauraudNoAddAlpha, pStates_TS_CxformGauraudNoAddAlpha_Add },
|
||
|
// Texture stage fixed-function fall-backs only (their implementation is incorrect).
|
||
|
{ pSource_PS_CxformGauraudTexture, pStates_TS_CxformTexture, 0 },
|
||
|
{ pSource_PS_Cxform2Texture, pStates_TS_CxformTexture, 0 },
|
||
|
{ pSource_PS_CxformGauraudMultiply, pStates_TS_CxformGauraud, 0 },
|
||
|
{ pSource_PS_CxformGauraudMultiplyNoAddAlpha, pStates_TS_CxformGauraudNoAddAlpha, 0 },
|
||
|
{ pSource_PS_CxformGauraudMultiplyTexture, pStates_TS_CxformTextureMultiply, 0 },
|
||
|
{ pSource_PS_CxformMultiply2Texture, pStates_TS_CxformTextureMultiply, 0 },
|
||
|
|
||
|
{ pSource_PS_CmatrixTexture, pStates_TS_SolidColor, 0 },
|
||
|
{ pSource_PS_CmatrixTextureMultiply, pStates_TS_SolidColor, 0 },
|
||
|
|
||
|
#ifndef GRENDERER_USE_PS11
|
||
|
{0},
|
||
|
|
||
|
// alpha compositing shaders
|
||
|
{ pSource_PS_AcSolidColor},
|
||
|
{ pSource_PS_AcCxformTexture},
|
||
|
{ pSource_PS_AcCxformTextureMultiply},
|
||
|
{ 0 },
|
||
|
{ 0 },
|
||
|
{ pSource_PS_AcTextTextureAlpha},
|
||
|
{ pSource_PS_AcTextTextureColor},
|
||
|
{ pSource_PS_AcTextTextureColorMultiply},
|
||
|
{ pSource_PS_AcTextTextureYUV},
|
||
|
{ pSource_PS_AcTextTextureYUVMultiply},
|
||
|
{ pSource_PS_AcTextTextureYUVA},
|
||
|
{ pSource_PS_AcTextTextureYUVAMultiply},
|
||
|
{ pSource_PS_AcCxformGauraud},
|
||
|
{ pSource_PS_AcCxformGauraudNoAddAlpha},
|
||
|
{ pSource_PS_AcCxformGauraudTexture},
|
||
|
{ pSource_PS_AcCxform2Texture},
|
||
|
{ pSource_PS_AcCxformGauraudMultiply},
|
||
|
{ pSource_PS_AcCxformGauraudMultiplyNoAddAlpha},
|
||
|
{ pSource_PS_AcCxformGauraudMultiplyTexture},
|
||
|
{ pSource_PS_AcCxformMultiply2Texture},
|
||
|
{ pSource_PS_AcCmatrixTexture},
|
||
|
{ pSource_PS_AcCmatrixTextureMultiply}
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// **** GDynamicVertexStream - Dynamic vertex buffer streaming manager
|
||
|
|
||
|
// This class tracks the vertex and index buffers that were set on the
|
||
|
// renderer and streams them into dynamic buffers intelligently.
|
||
|
// Extra logic is included to handle buffer overruns; for example if
|
||
|
// the index buffer passed does not fit into allocated buffer, it
|
||
|
// will be streamed and rendered in pieces.
|
||
|
|
||
|
class GDynamicVertexStream
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
// Delegate used types for convenience.
|
||
|
typedef GRenderer::IndexFormat IndexFormat;
|
||
|
typedef GRenderer::VertexFormat VertexFormat;
|
||
|
typedef GRenderer::VertexXY16iC32 VertexXY16iC32;
|
||
|
typedef GRenderer::VertexXY16iCF32 VertexXY16iCF32;
|
||
|
|
||
|
// Default sizes of various buffers - in bytes; Change these to control memory that is used
|
||
|
enum {
|
||
|
// Warning: if vertex buffer size is not large enough for 65K vertices,
|
||
|
// we will fall back to SW indexing for those buffers that don't fit.
|
||
|
DefaultVertexBufferSize = 0x10000 * sizeof(VertexXY16iCF32),
|
||
|
DefaultIndexBufferSize = 0x18000 * sizeof(UInt16),
|
||
|
|
||
|
GlyphBufferVertexCount = 6 * 192,
|
||
|
GlyphBufferSize = GlyphBufferVertexCount * sizeof(GGlyphVertex)
|
||
|
};
|
||
|
|
||
|
|
||
|
// PrimitiveDesc - package structure for DrawPrimitive args.
|
||
|
struct PrimitiveDesc
|
||
|
{
|
||
|
int BaseVertexIndex, MinVertexIndex, NumVertices;
|
||
|
int StartIndex, TriangleCount;
|
||
|
|
||
|
PrimitiveDesc()
|
||
|
{
|
||
|
BaseVertexIndex = 0;
|
||
|
MinVertexIndex = 0;
|
||
|
NumVertices = 0;
|
||
|
StartIndex = 0;
|
||
|
TriangleCount = 0;
|
||
|
}
|
||
|
PrimitiveDesc(int baseVertexIndex, int minVertexIndex, int numVertices,
|
||
|
int startIndex, int triangleCount )
|
||
|
{
|
||
|
BaseVertexIndex = baseVertexIndex;
|
||
|
MinVertexIndex = minVertexIndex;
|
||
|
NumVertices = numVertices;
|
||
|
StartIndex = startIndex;
|
||
|
TriangleCount = triangleCount;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
private:
|
||
|
// Direct3D Device we are using.
|
||
|
IDirect3DDeviceX* pDevice;
|
||
|
|
||
|
// Flag set if buffers are released due to lost device.
|
||
|
bool LostDevice;
|
||
|
|
||
|
// Vertex data pointer
|
||
|
const void* pVertexData;
|
||
|
const void* pIndexData;
|
||
|
VertexFormat VertexFmt;
|
||
|
UInt VertexSize;
|
||
|
_D3DFORMAT IndexFmt;
|
||
|
UInt VertexCount;
|
||
|
UInt IndexCount;
|
||
|
|
||
|
// Dynamic Vertex/Index buffer state
|
||
|
GPtr<IDirect3DVertexBufferX> pVertexBuffer;
|
||
|
GPtr<IDirect3DIndexBufferX> pIndexBuffer;
|
||
|
// Allocated sizes
|
||
|
UInt VertexBufferSize;
|
||
|
UInt IndexBufferSize;
|
||
|
|
||
|
// Next available offset in vertex / index buffers
|
||
|
UInt NextIBOffset;
|
||
|
UInt NextVBOffset;
|
||
|
// If vertex data was uploaded into VB, VBDataInBuffer flag is set
|
||
|
// and VBDataOffset points to its first byte.
|
||
|
bool VBDataInBuffer;
|
||
|
bool IBDataInBuffer;
|
||
|
UInt VBDataOffset;
|
||
|
UInt VBDataIndex; // Used in D3D8 to support multiple arrays in vertex buffer
|
||
|
UInt IBDataOffset;
|
||
|
|
||
|
// Vertex size of last data in buffer. Can be different from VertexSize
|
||
|
// if data was uploaded directly through lock.
|
||
|
UInt VertexSizeInBuffer;
|
||
|
|
||
|
PrimitiveDesc Primitive;
|
||
|
|
||
|
enum RenderMethodType
|
||
|
{
|
||
|
RM_None,
|
||
|
RM_Indexed,
|
||
|
RM_IndexedInChunks,
|
||
|
RM_NotIndexed,
|
||
|
};
|
||
|
|
||
|
RenderMethodType RenderMethod;
|
||
|
int MaxTriangleCount;
|
||
|
|
||
|
// Helper functions to create/release vertex and index buffers.
|
||
|
bool CreateDynamicBuffers();
|
||
|
|
||
|
// Helper, performs un-indexing and copy of data into the target vertex buffer.
|
||
|
void InitVerticesFromIndex(void *pvertexDest, int baseVertexIndex, int vertexSize,
|
||
|
int startIndex, int triangleCount );
|
||
|
public:
|
||
|
|
||
|
|
||
|
GDynamicVertexStream();
|
||
|
~GDynamicVertexStream();
|
||
|
|
||
|
|
||
|
// Initializes stream, creating buffers. Called at renderer initialization.
|
||
|
bool Initialize(IDirect3DDeviceX *pdevice)
|
||
|
{
|
||
|
pDevice = pdevice;
|
||
|
if (CreateDynamicBuffers())
|
||
|
return 1;
|
||
|
pDevice = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void Reset()
|
||
|
{
|
||
|
ReleaseDynamicBuffers();
|
||
|
pDevice = 0;
|
||
|
}
|
||
|
|
||
|
void BeginDisplay()
|
||
|
{
|
||
|
if (LostDevice)
|
||
|
CreateDynamicBuffers();
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
pDevice->SetStreamSourceFreq(0, 1);
|
||
|
pDevice->SetIndices(pIndexBuffer);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// Called for a lost device.
|
||
|
void ReleaseDynamicBuffers(bool lostDevice = 0);
|
||
|
|
||
|
|
||
|
// *** Vertex Upload / Streaming interfaces.
|
||
|
|
||
|
// We allow for two types of streaming:
|
||
|
//
|
||
|
// 1. Direct upload by calling Lock/UnloadVertexBuffer. Such data
|
||
|
// can be rendered by calling DrawPrimitive after unlock.
|
||
|
//
|
||
|
// 2. Indexed upload through SetVertexData + SetIndexData. This data is
|
||
|
// rendered through PrepareTriangleData / DrawTriangles.
|
||
|
//
|
||
|
|
||
|
// Raw buffer locking; also configures the stream.
|
||
|
void* LockVertexBuffer(UInt vertexCount, UInt vertexSize);
|
||
|
void UnlockVertexBuffer();
|
||
|
void* LockIndexBuffer(UInt indexCount, UInt indexSize);
|
||
|
void UnlockIndexBuffer();
|
||
|
// Copies vertices directly into buffer; uses lock.
|
||
|
bool InitVertexBufferData(int vertexIndex, int vertexCount);
|
||
|
|
||
|
// Indexed data specification, used by PrepareVertexData.
|
||
|
void SetVertexData(const void* pvertices, int numVertices, VertexFormat vf);
|
||
|
void SetIndexData(const void* pindices, int numIndices, IndexFormat idxf);
|
||
|
|
||
|
// Specifies data ranges for DrawTriangles.
|
||
|
bool PrepareVertexData(const PrimitiveDesc &prim);
|
||
|
// Renders triangles prepared in buffer.
|
||
|
void DrawTriangles();
|
||
|
|
||
|
|
||
|
// Data availability check methods.
|
||
|
bool HasVertexData() const { return (pVertexData != 0); }
|
||
|
bool HasIndexData() const { return (pIndexData != 0); }
|
||
|
VertexFormat GetVertexFormat() const { return VertexFmt; }
|
||
|
_D3DFORMAT GetD3DIndexFormat() const { return IndexFmt; }
|
||
|
UInt GetStartIndex() const { return VBDataIndex; }
|
||
|
};
|
||
|
|
||
|
|
||
|
// *** Dynamic Vertex Stream implementation
|
||
|
|
||
|
GDynamicVertexStream::GDynamicVertexStream()
|
||
|
{
|
||
|
pDevice = 0;
|
||
|
LostDevice = 0;
|
||
|
|
||
|
pVertexData = 0;
|
||
|
pIndexData = 0;
|
||
|
IndexFmt = D3DFMT_UNKNOWN;
|
||
|
VertexFmt = GRenderer::Vertex_None;
|
||
|
VertexCount = 0;
|
||
|
IndexCount = 0;
|
||
|
|
||
|
NextIBOffset = 0;
|
||
|
NextVBOffset = 0;
|
||
|
VBDataInBuffer = 0;
|
||
|
IBDataInBuffer = 0;
|
||
|
VBDataOffset = 0;
|
||
|
IBDataOffset = 0;
|
||
|
VBDataIndex = 0;
|
||
|
|
||
|
GCOMPILER_ASSERT(DefaultVertexBufferSize >= GlyphBufferSize);
|
||
|
}
|
||
|
|
||
|
GDynamicVertexStream::~GDynamicVertexStream()
|
||
|
{
|
||
|
ReleaseDynamicBuffers();
|
||
|
}
|
||
|
|
||
|
|
||
|
// Helper function to create vertex and index buffers
|
||
|
bool GDynamicVertexStream::CreateDynamicBuffers()
|
||
|
{
|
||
|
VertexBufferSize = DefaultVertexBufferSize;
|
||
|
IndexBufferSize = DefaultIndexBufferSize;
|
||
|
|
||
|
if (!pVertexBuffer)
|
||
|
{
|
||
|
HRESULT createResult;
|
||
|
|
||
|
// Min acceptable buffer must be large enough for glyphs due to logic used in DrawBitmaps.
|
||
|
GCOMPILER_ASSERT(DefaultVertexBufferSize/8 >= GlyphBufferSize);
|
||
|
|
||
|
// Loop trying several vertex buffer sizes.
|
||
|
do
|
||
|
{
|
||
|
createResult = pDevice->CreateVertexBuffer(
|
||
|
VertexBufferSize, D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
|
||
|
0, D3DPOOL_DEFAULT, &pVertexBuffer.GetRawRef() NULL9);
|
||
|
|
||
|
// If failed, try smaller size while reasonable.
|
||
|
if (FAILED(createResult))
|
||
|
{
|
||
|
if (VertexBufferSize > DefaultVertexBufferSize/8)
|
||
|
VertexBufferSize = VertexBufferSize / 2;
|
||
|
else
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererD3Dx - Failed to create dynamic vertex buffer");
|
||
|
VertexBufferSize = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} while(FAILED(createResult));
|
||
|
}
|
||
|
|
||
|
if (!pIndexBuffer)
|
||
|
{
|
||
|
HRESULT createResult;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
createResult = pDevice->CreateIndexBuffer(
|
||
|
IndexBufferSize, D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,
|
||
|
D3DFMT_INDEX16, D3DPOOL_DEFAULT,
|
||
|
&pIndexBuffer.GetRawRef() NULL9);
|
||
|
|
||
|
// If failed, try smaller size while reasonable.
|
||
|
if (FAILED(createResult))
|
||
|
{
|
||
|
if (IndexBufferSize > DefaultIndexBufferSize/4)
|
||
|
IndexBufferSize = IndexBufferSize / 2;
|
||
|
else
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererD3Dx - Failed to create dynamic index buffer");
|
||
|
pVertexBuffer = 0; // Release VB.
|
||
|
IndexBufferSize = 0;
|
||
|
VertexBufferSize = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} while(FAILED(createResult));
|
||
|
}
|
||
|
|
||
|
// Initialize buffer pointers to the beginning.
|
||
|
NextIBOffset = 0;
|
||
|
NextVBOffset = 0;
|
||
|
VBDataInBuffer = 0;
|
||
|
IBDataInBuffer = 0;
|
||
|
VBDataOffset = 0;
|
||
|
IBDataOffset = 0;
|
||
|
|
||
|
VertexSizeInBuffer = 0;
|
||
|
|
||
|
RenderMethod = RM_None;
|
||
|
MaxTriangleCount = 0;
|
||
|
|
||
|
// After successful creation buffers are no longer lost.
|
||
|
LostDevice = 0;
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
void GDynamicVertexStream::ReleaseDynamicBuffers(bool lostDevice)
|
||
|
{
|
||
|
pVertexBuffer = 0;
|
||
|
pIndexBuffer = 0;
|
||
|
VertexBufferSize = 0;
|
||
|
IndexBufferSize = 0;
|
||
|
RenderMethod = RM_None;
|
||
|
MaxTriangleCount = 0;
|
||
|
|
||
|
LostDevice = lostDevice;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void GDynamicVertexStream::SetVertexData(const void* pvertices, int numVertices, VertexFormat vf)
|
||
|
{
|
||
|
pVertexData = pvertices;
|
||
|
VertexFmt = vf;
|
||
|
VertexCount = numVertices;
|
||
|
VBDataInBuffer = 0;
|
||
|
|
||
|
VertexSize = 2 * sizeof(SInt16);
|
||
|
switch(VertexFmt)
|
||
|
{
|
||
|
case GRenderer::Vertex_None: VertexSize = 0; break;
|
||
|
case GRenderer::Vertex_XY16iC32: VertexSize = sizeof(GRenderer::VertexXY16iC32); break;
|
||
|
case GRenderer::Vertex_XY16iCF32: VertexSize = sizeof(GRenderer::VertexXY16iCF32); break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GDynamicVertexStream::SetIndexData(const void* pindices, int numIndices, IndexFormat idxf)
|
||
|
{
|
||
|
pIndexData = pindices;
|
||
|
IndexCount = numIndices;
|
||
|
IBDataInBuffer = 0;
|
||
|
switch(idxf)
|
||
|
{
|
||
|
case GRenderer::Index_None: IndexFmt = D3DFMT_UNKNOWN; break;
|
||
|
case GRenderer::Index_16: IndexFmt = D3DFMT_INDEX16; break;
|
||
|
case GRenderer::Index_32: IndexFmt = D3DFMT_INDEX32; break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
bool GDynamicVertexStream::PrepareVertexData(const PrimitiveDesc &prim)
|
||
|
{
|
||
|
if (LostDevice)
|
||
|
return 0;
|
||
|
|
||
|
Primitive = prim;
|
||
|
|
||
|
// Simple heuristic for performance: If VBs are large, use indexed buffers;
|
||
|
// otherwise un-index and upload vertices manually. This keeps the Lock
|
||
|
// overhead lower, since we only have to lock one buffer instead of two
|
||
|
// for small objects.
|
||
|
if (VertexCount < 32)
|
||
|
{
|
||
|
MaxTriangleCount = VertexBufferSize / (VertexSize * 3);
|
||
|
RenderMethod = RM_NotIndexed;
|
||
|
}
|
||
|
|
||
|
else
|
||
|
{
|
||
|
// Upload vertex data if it is not there.
|
||
|
if (!VBDataInBuffer)
|
||
|
{
|
||
|
// If vertex buffer is not large enough, we must render without indexing.
|
||
|
if (VertexCount * VertexSize > VertexBufferSize)
|
||
|
{
|
||
|
// Will need to render 3 vertices at a time.
|
||
|
MaxTriangleCount = VertexBufferSize / (VertexSize * 3);
|
||
|
RenderMethod = RM_NotIndexed;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void * pbuffer = LockVertexBuffer(VertexCount, VertexSize);
|
||
|
if (pbuffer)
|
||
|
{
|
||
|
memcpy(pbuffer, pVertexData, VertexCount * VertexSize);
|
||
|
UnlockVertexBuffer();
|
||
|
VBDataInBuffer = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RenderMethod = RM_None;
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Upload index data.
|
||
|
if (!IBDataInBuffer)
|
||
|
{
|
||
|
UInt indexSize = (IndexFmt == D3DFMT_INDEX16) ? sizeof(UInt16) : sizeof(UInt32);
|
||
|
|
||
|
if (IndexCount * indexSize > IndexBufferSize)
|
||
|
{
|
||
|
MaxTriangleCount = IndexBufferSize / (indexSize * 3);
|
||
|
RenderMethod = RM_IndexedInChunks;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void * pbuffer = LockIndexBuffer(IndexCount, indexSize);
|
||
|
if (pbuffer)
|
||
|
{
|
||
|
// Need to know the right index buffer spot.
|
||
|
memcpy(pbuffer, pIndexData, IndexCount * indexSize);
|
||
|
UnlockIndexBuffer();
|
||
|
IBDataInBuffer = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RenderMethod = RM_None;
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RenderMethod = RM_Indexed;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
void GDynamicVertexStream::DrawTriangles()
|
||
|
{
|
||
|
if (RenderMethod == RM_Indexed)
|
||
|
{
|
||
|
// Draw the mesh with indexed buffers.
|
||
|
GASSERT(IndexFmt == D3DFMT_INDEX16);
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
pDevice->DrawIndexedPrimitive(
|
||
|
D3DPT_TRIANGLELIST,
|
||
|
Primitive.BaseVertexIndex, Primitive.MinVertexIndex, Primitive.NumVertices,
|
||
|
(IBDataOffset / sizeof(UInt16)) + Primitive.StartIndex, Primitive.TriangleCount );
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
pDevice->SetIndices(pIndexBuffer, Primitive.BaseVertexIndex + VBDataIndex);
|
||
|
pDevice->DrawIndexedPrimitive(
|
||
|
D3DPT_TRIANGLELIST,
|
||
|
Primitive.MinVertexIndex, Primitive.NumVertices,
|
||
|
(IBDataOffset / sizeof(UInt16)) + Primitive.StartIndex, Primitive.TriangleCount );
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
else if (RenderMethod == RM_NotIndexed)
|
||
|
{
|
||
|
// Vertex buffer could not fit, render in chunks with software indexing.
|
||
|
int triangles = 0;
|
||
|
|
||
|
// For now, InitVerticesFromIndex doesn't handle 32 bit buffers.
|
||
|
GASSERT(IndexFmt == D3DFMT_INDEX16);
|
||
|
|
||
|
while(triangles < Primitive.TriangleCount)
|
||
|
{
|
||
|
int batch = G_Min<int>(Primitive.TriangleCount - triangles, MaxTriangleCount);
|
||
|
void * pbuffer = LockVertexBuffer(batch * 3, VertexSize);
|
||
|
if (!pbuffer)
|
||
|
return;
|
||
|
|
||
|
// Copy this batches indices.
|
||
|
InitVerticesFromIndex(pbuffer, Primitive.BaseVertexIndex, VertexSize,
|
||
|
Primitive.StartIndex + (triangles * 3), batch);
|
||
|
UnlockVertexBuffer();
|
||
|
|
||
|
// Draw using uploaded data.
|
||
|
pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, GetStartIndex(), batch);
|
||
|
triangles += batch;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else if (RenderMethod == RM_IndexedInChunks)
|
||
|
{
|
||
|
// We have vertex buffer, but not index buffer.
|
||
|
int triangles = 0;
|
||
|
|
||
|
while(triangles < Primitive.TriangleCount)
|
||
|
{
|
||
|
int batch = G_Min<int>(Primitive.TriangleCount - triangles, MaxTriangleCount);
|
||
|
UInt indexSize = (IndexFmt == D3DFMT_INDEX16) ? sizeof(UInt16) : sizeof(UInt32);
|
||
|
void * pbuffer = LockIndexBuffer(batch * 3, indexSize);
|
||
|
if (!pbuffer)
|
||
|
return;
|
||
|
|
||
|
// Copy this indices for this batch.
|
||
|
memcpy( pbuffer,
|
||
|
((UByte*)pIndexData) + (Primitive.StartIndex +(triangles * 3)) * indexSize,
|
||
|
batch * 3 * indexSize );
|
||
|
UnlockIndexBuffer();
|
||
|
|
||
|
// Draw using uploaded data.
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
pDevice->DrawIndexedPrimitive(
|
||
|
D3DPT_TRIANGLELIST,
|
||
|
Primitive.BaseVertexIndex, Primitive.MinVertexIndex, Primitive.NumVertices,
|
||
|
(IBDataOffset / sizeof(UInt16)), batch);
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
pDevice->SetIndices(pIndexBuffer, Primitive.BaseVertexIndex + VBDataIndex);
|
||
|
pDevice->DrawIndexedPrimitive(
|
||
|
D3DPT_TRIANGLELIST,
|
||
|
Primitive.MinVertexIndex, Primitive.NumVertices,
|
||
|
(IBDataOffset / sizeof(UInt16)), batch);
|
||
|
#endif
|
||
|
|
||
|
triangles += batch;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// Lock / Unlock logic.
|
||
|
void* GDynamicVertexStream::LockVertexBuffer(UInt vertexCount, UInt vertexSize)
|
||
|
{
|
||
|
if (LostDevice)
|
||
|
return 0;
|
||
|
|
||
|
UInt size = vertexCount * vertexSize;
|
||
|
if ((size > VertexBufferSize) || !pVertexBuffer)
|
||
|
{
|
||
|
GASSERT(0);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
DWORD lockFlags;
|
||
|
void* pbuffer = 0;
|
||
|
UInt offset;
|
||
|
|
||
|
VBDataInBuffer = 0;
|
||
|
|
||
|
// Determine where in the buffer we go.
|
||
|
if (size + NextVBOffset + vertexSize < VertexBufferSize)
|
||
|
{
|
||
|
offset = NextVBOffset;
|
||
|
#if (GFC_D3D_VERSION == 8)
|
||
|
if (offset % vertexSize)
|
||
|
offset += vertexSize - (offset % vertexSize);
|
||
|
#endif
|
||
|
NextVBOffset = offset + size;
|
||
|
lockFlags = D3DLOCK_NOOVERWRITE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
offset = 0;
|
||
|
NextVBOffset = size;
|
||
|
lockFlags = D3DLOCK_DISCARD;
|
||
|
}
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
if (FAILED(pVertexBuffer->Lock(offset, size, (void**)&pbuffer, lockFlags)))
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
if (FAILED(pVertexBuffer->Lock(offset, size, (BYTE**)&pbuffer, lockFlags)))
|
||
|
#endif
|
||
|
return 0;
|
||
|
// Some drivers may return bad pointers here for dynamic buffers (i.e. old NVidia drivers)
|
||
|
if (::IsBadWritePtr(pbuffer, size))
|
||
|
{
|
||
|
static bool warningReported = 0;
|
||
|
GFC_DEBUG_WARNING(!warningReported,
|
||
|
"GD3DxRenderer::LockVertexData - Direct3D Lock returned bad pointer, function failed");
|
||
|
warningReported = 1;
|
||
|
pVertexBuffer->Unlock();
|
||
|
pbuffer = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
VBDataOffset = offset;
|
||
|
#if (GFC_D3D_VERSION == 8)
|
||
|
VBDataIndex = offset / vertexSize;
|
||
|
#endif
|
||
|
VertexSizeInBuffer = vertexSize;
|
||
|
return pbuffer;
|
||
|
}
|
||
|
|
||
|
|
||
|
void GDynamicVertexStream::UnlockVertexBuffer()
|
||
|
{
|
||
|
pVertexBuffer->Unlock();
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
// Set this buffer offset on a device.
|
||
|
pDevice->SetStreamSource(0, pVertexBuffer, VBDataOffset, VertexSizeInBuffer);
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
// GetStartIndex() is used instead of stream offsets
|
||
|
pDevice->SetStreamSource(0, pVertexBuffer, VertexSizeInBuffer);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
void* GDynamicVertexStream::LockIndexBuffer(UInt indexCount, UInt indexSize)
|
||
|
{
|
||
|
if (LostDevice)
|
||
|
return 0;
|
||
|
|
||
|
UInt size = indexCount * indexSize;
|
||
|
if ((size > IndexBufferSize) || !pIndexBuffer)
|
||
|
{
|
||
|
GASSERT(0);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
DWORD lockFlags;
|
||
|
void* pbuffer = 0;
|
||
|
UInt offset;
|
||
|
|
||
|
IBDataInBuffer = 0;
|
||
|
|
||
|
// Determine where in the buffer we go.
|
||
|
if ((IndexBufferSize - NextIBOffset) > size)
|
||
|
{
|
||
|
offset = NextIBOffset;
|
||
|
NextIBOffset = NextIBOffset + size;
|
||
|
lockFlags = D3DLOCK_NOOVERWRITE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
offset = 0;
|
||
|
NextIBOffset = size;
|
||
|
lockFlags = D3DLOCK_DISCARD;
|
||
|
}
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
if (FAILED(pIndexBuffer->Lock(offset, size, (void**)&pbuffer, lockFlags)))
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
if (FAILED(pIndexBuffer->Lock(offset, size, (BYTE**)&pbuffer, lockFlags)))
|
||
|
#endif
|
||
|
return 0;
|
||
|
if (::IsBadWritePtr(pbuffer, size))
|
||
|
{
|
||
|
pIndexBuffer->Unlock();
|
||
|
pbuffer = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
IBDataOffset = offset;
|
||
|
return pbuffer;
|
||
|
}
|
||
|
|
||
|
void GDynamicVertexStream::UnlockIndexBuffer()
|
||
|
{
|
||
|
pIndexBuffer->Unlock();
|
||
|
}
|
||
|
|
||
|
bool GDynamicVertexStream::InitVertexBufferData(int vertexIndex, int vertexCount)
|
||
|
{
|
||
|
GASSERT(UInt(vertexCount + vertexIndex) <= VertexCount);
|
||
|
|
||
|
void * pbuffer = LockVertexBuffer(vertexCount, VertexSize);
|
||
|
if (!pbuffer)
|
||
|
return 0;
|
||
|
memcpy(pbuffer, ((UByte*)pVertexData) + vertexIndex * VertexSize, vertexCount * VertexSize);
|
||
|
UnlockVertexBuffer();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Performs un-indexing and copy of data into the target vertex buffer.
|
||
|
void GDynamicVertexStream::InitVerticesFromIndex( void *pvertexDest, int baseVertexIndex, int vertexSize,
|
||
|
int startIndex, int triangleCount )
|
||
|
{
|
||
|
UInt16* pindices = ((UInt16*)pIndexData) + startIndex;
|
||
|
UByte* pvertices = ((UByte*)pVertexData) + baseVertexIndex * vertexSize;
|
||
|
UByte* pdest = (UByte*) pvertexDest;
|
||
|
// 32-bit pointer versions.
|
||
|
UInt32* pv32 = (UInt32*) pvertices;
|
||
|
UInt32* pd32 = (UInt32*) pdest;
|
||
|
|
||
|
|
||
|
GCOMPILER_ASSERT(sizeof(UInt32) == 4);
|
||
|
int i;
|
||
|
|
||
|
switch(vertexSize)
|
||
|
{
|
||
|
case 4:
|
||
|
|
||
|
for(i = 0; i< triangleCount; i++, pd32 += 3)
|
||
|
{
|
||
|
pd32[0] = pv32[*(pindices + 0)];
|
||
|
pd32[1] = pv32[*(pindices + 1)];
|
||
|
pd32[2] = pv32[*(pindices + 2)];
|
||
|
pindices += 3;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 8:
|
||
|
GCOMPILER_ASSERT(sizeof(VertexXY16iC32) == 8);
|
||
|
|
||
|
for(i = 0; i< triangleCount; i++, pd32 += 3 * 2)
|
||
|
{
|
||
|
pd32[0] = pv32[*pindices * 2];
|
||
|
pd32[1] = pv32[*pindices * 2 + 1];
|
||
|
pindices ++;
|
||
|
pd32[2] = pv32[*pindices * 2];
|
||
|
pd32[3] = pv32[*pindices * 2 + 1];
|
||
|
pindices ++;
|
||
|
pd32[4] = pv32[*pindices * 2];
|
||
|
pd32[5] = pv32[*pindices * 2 + 1];
|
||
|
pindices ++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 12:
|
||
|
GCOMPILER_ASSERT(sizeof(VertexXY16iCF32) == 12);
|
||
|
|
||
|
for(i = 0; i< triangleCount; i++, pd32 += 3 * 3)
|
||
|
{
|
||
|
pd32[0] = pv32[*pindices * 3];
|
||
|
pd32[1] = pv32[*pindices * 3 + 1];
|
||
|
pd32[2] = pv32[*pindices * 3 + 2];
|
||
|
pindices ++;
|
||
|
pd32[3] = pv32[*pindices * 3];
|
||
|
pd32[4] = pv32[*pindices * 3 + 1];
|
||
|
pd32[5] = pv32[*pindices * 3 + 2];
|
||
|
pindices ++;
|
||
|
pd32[6] = pv32[*pindices * 3];
|
||
|
pd32[7] = pv32[*pindices * 3 + 1];
|
||
|
pd32[8] = pv32[*pindices * 3 + 2];
|
||
|
pindices ++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
for(i = 0; i< triangleCount; i++, pdest += vertexSize*3)
|
||
|
{
|
||
|
memcpy(pdest, pvertices + *pindices * vertexSize, vertexSize);
|
||
|
pindices ++;
|
||
|
memcpy(pdest, pvertices + *pindices * vertexSize, vertexSize);
|
||
|
pindices ++;
|
||
|
memcpy(pdest, pvertices + *pindices * vertexSize, vertexSize);
|
||
|
pindices ++;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// ***** GRendererD3Dx Implementation
|
||
|
|
||
|
class GRendererD3DxImpl : public GRendererD3Dx
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
// Some renderer state.
|
||
|
bool ModeSet;
|
||
|
SInt RenderMode;
|
||
|
|
||
|
// This flag is set if pixel shader support is available.
|
||
|
bool UsePixelShaders;
|
||
|
bool UseYUVShaders;
|
||
|
SInt FiltersSupported; // 1= low end dynamic, 2= dynamic, 3= static
|
||
|
const char* PShaderProfile;
|
||
|
const char* VShaderProfile;
|
||
|
// Use BlendFuncSeparate
|
||
|
bool UseAcBlend;
|
||
|
// Non power of 2 texture support; 0=none, 1=without repeat, 2=full
|
||
|
SInt TexNonPower2;
|
||
|
|
||
|
// Shaders and declarations that are currently set.
|
||
|
VDeclType VDeclIndex;
|
||
|
VShaderType VShaderIndex;
|
||
|
|
||
|
// Current pixel shader index
|
||
|
PixelShaderType PShaderIndex;
|
||
|
int PShaderPass;
|
||
|
|
||
|
// Video Mode Configuration Flags (VMConfigFlags)
|
||
|
UInt32 VMCFlags;
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
// Created vertex declarations and shaders.
|
||
|
GPtr<IDirect3DVertexDeclaration9> VertexDecls[VD_Count];
|
||
|
GPtr<IDirect3DVertexShader9> VertexShaders[VS_Count];
|
||
|
|
||
|
// Allocated pixel shaders
|
||
|
GPtr<IDirect3DPixelShader9> PixelShaders[PS_Count];
|
||
|
GPtr<IDirect3DPixelShader9> StaticFilterShaders[FS2_Count];
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
DWORD VertexDecls[VD_Count];
|
||
|
DWORD VertexShaders[VS_Count];
|
||
|
DWORD PixelShaders[PS_Count];
|
||
|
#endif
|
||
|
|
||
|
// Direct3DDevice
|
||
|
IDirect3DDeviceX* pDevice;
|
||
|
|
||
|
// This flag indicates whether we've checked for stencil after BeginDisplay or not.
|
||
|
bool StencilChecked;
|
||
|
// This flag is stencil is available, after check.
|
||
|
bool StencilAvailable;
|
||
|
bool MultiBitStencil;
|
||
|
bool DepthBufferAvailable;
|
||
|
bool DrawingMask;
|
||
|
DWORD StencilCounter;
|
||
|
bool StencilEnabled;
|
||
|
// Increment/decreent ops we need for stencil.
|
||
|
D3DSTENCILOP StencilOpInc;
|
||
|
D3DSTENCILOP StencilOpDec;
|
||
|
|
||
|
// format for alpha textures - old cards don't support all formats
|
||
|
D3DFORMAT AlphaTextureFormat;
|
||
|
|
||
|
// Output size.
|
||
|
Float DisplayWidth;
|
||
|
Float DisplayHeight;
|
||
|
GRectF DisplayRect;
|
||
|
|
||
|
Matrix UserMatrix;
|
||
|
Matrix ViewportMatrix;
|
||
|
GViewport ViewRect;
|
||
|
Matrix CurrentMatrix;
|
||
|
Cxform CurrentCxform;
|
||
|
|
||
|
// Link list of all allocated textures
|
||
|
GRendererNode Textures;
|
||
|
GRendererNode RenderTargets;
|
||
|
mutable GLock TexturesLock;
|
||
|
|
||
|
|
||
|
// Vertex stream / dynamic buffers container.
|
||
|
GDynamicVertexStream VertexStream;
|
||
|
|
||
|
|
||
|
// Current sample mode
|
||
|
BitmapSampleMode SampleMode[2];
|
||
|
|
||
|
typedef GArrayConstPolicy<0, 4, true> NeverShrinkPolicy;
|
||
|
typedef GArrayLH<BlendType, GStat_Default_Mem, NeverShrinkPolicy> BlendModeStackType;
|
||
|
|
||
|
// Current blend mode
|
||
|
BlendType BlendMode;
|
||
|
BlendModeStackType BlendModeStack;
|
||
|
|
||
|
// Presentation parameters specified to configure the mode.
|
||
|
D3DPRESENT_PARAMETERS PresentParams;
|
||
|
HWND hWnd;
|
||
|
|
||
|
// Linked list used for buffer cache testing, otherwise holds no data.
|
||
|
CacheNode CacheList;
|
||
|
|
||
|
// Surface for updating textures
|
||
|
SInt TempW, TempH;
|
||
|
GPtr<IDirect3DTextureX> pTempTextureA, pTempTextureLA, pTempTextureRGBA4, pTempTextureRGBA8;
|
||
|
GPtr<IDirect3DSurfaceX> pTempSurfaceA, pTempSurfaceLA, pTempSurfaceRGBA4, pTempSurfaceRGBA8;
|
||
|
bool UseDynamicTex, UseManagedTex;
|
||
|
|
||
|
// resources to retain during tiling frames
|
||
|
GArrayLH<GPtr<GTexture> > FrameResources;
|
||
|
|
||
|
// all D3D calls should be done on the main thread, but textures can be released from
|
||
|
// different threads so we collect system resources and release them on the main thread
|
||
|
GArrayLH<IDirect3DResourceX*> ResourceReleasingQueue;
|
||
|
GLock ResourceReleasingQueueLock;
|
||
|
|
||
|
// this method is called from GTextureXXX destructor to put a system resource into releasing queue
|
||
|
void AddResourceForReleasing(IDirect3DResourceX* ptexture)
|
||
|
{
|
||
|
GASSERT(ptexture);
|
||
|
if (!ptexture) return;
|
||
|
GLock::Locker guard(&ResourceReleasingQueueLock);
|
||
|
ResourceReleasingQueue.PushBack(ptexture);
|
||
|
}
|
||
|
|
||
|
// this method is called from GetTexture, EndDisplay and destructor to actually release
|
||
|
// collected system resources
|
||
|
void ReleaseQueuedResources()
|
||
|
{
|
||
|
GLock::Locker guard(&ResourceReleasingQueueLock);
|
||
|
for (UInt i = 0; i < ResourceReleasingQueue.GetSize(); ++i)
|
||
|
{
|
||
|
IDirect3DResourceX* presource = ResourceReleasingQueue[i];
|
||
|
presource->Release();
|
||
|
}
|
||
|
ResourceReleasingQueue.Clear();
|
||
|
}
|
||
|
|
||
|
|
||
|
// Statistics
|
||
|
Stats RenderStats;
|
||
|
|
||
|
// Video memory
|
||
|
GMemoryStat TextureVMem;
|
||
|
GMemoryStat BufferVMem;
|
||
|
// Counts
|
||
|
GCounterStat TextureUploadCnt;
|
||
|
GCounterStat TextureUpdateCnt;
|
||
|
GCounterStat DPLineCnt;
|
||
|
GCounterStat DPTriangleCnt;
|
||
|
GCounterStat LineCnt;
|
||
|
GCounterStat TriangleCnt;
|
||
|
GCounterStat MaskCnt;
|
||
|
GCounterStat FilterCnt;
|
||
|
|
||
|
// render target
|
||
|
struct RTState
|
||
|
{
|
||
|
GRenderTargetD3D9Impl* pRT;
|
||
|
GMatrix2D ViewMatrix;
|
||
|
GMatrix3D ViewMatrix3D;
|
||
|
GMatrix3D PerspMatrix3D;
|
||
|
const GMatrix3D* pWorldMatrix3D;
|
||
|
GViewport ViewRect;
|
||
|
SInt RenderMode;
|
||
|
SInt StencilCounter;
|
||
|
bool StencilEnabled;
|
||
|
|
||
|
RTState() { pRT = 0; pWorldMatrix3D = 0; }
|
||
|
RTState(GRenderTargetD3D9Impl* prt, const GMatrix2D& vm,
|
||
|
const GMatrix3D& vm3d, const GMatrix3D &vp3d, const GMatrix3D* pw3d, const GViewport& vp, SInt rm, SInt sc, bool se)
|
||
|
: pRT(prt), ViewMatrix(vm), ViewMatrix3D(vm3d), PerspMatrix3D(vp3d), pWorldMatrix3D(pw3d), ViewRect(vp),
|
||
|
RenderMode(rm), StencilCounter(sc), StencilEnabled(se) { }
|
||
|
};
|
||
|
|
||
|
typedef GArrayLH<RTState, GStat_Default_Mem, NeverShrinkPolicy> RTStackType;
|
||
|
|
||
|
GRenderTargetD3D9Impl* pCurRenderTarget;
|
||
|
RTStackType RenderTargetStack;
|
||
|
GArrayLH<GPtr<GRenderTargetD3D9Impl> > TempRenderTargets;
|
||
|
GArrayLH<GPtr<GDepthBufferD3D9Impl> > TempStencilBuffers;
|
||
|
|
||
|
struct FilterVertexShader
|
||
|
{
|
||
|
GPtr<IDirect3DVertexShader9> pVShader;
|
||
|
GPtr<IDirect3DVertexDeclaration9> pVDecl;
|
||
|
};
|
||
|
|
||
|
struct FilterShader : public GNewOverrideBase<GStat_Default_Mem>
|
||
|
{
|
||
|
GPtr<IDirect3DPixelShader9> pShader;
|
||
|
|
||
|
UInt BoxTCs;
|
||
|
UInt BaseTCs;
|
||
|
UInt MaxTCs;
|
||
|
UInt Samples;
|
||
|
|
||
|
FilterVertexShader *pVShader;
|
||
|
};
|
||
|
|
||
|
typedef GHash<BlurFilterParams,FilterShader*> FilterShadersType;
|
||
|
FilterShadersType FilterShaders;
|
||
|
//UInt MaxTCs;
|
||
|
UInt MaxTextureOps;
|
||
|
UInt MaxAttributes;
|
||
|
//GPtr<IDirect3DVertexDeclaration9> FilterVertexDecl;
|
||
|
//GPtr<IDirect3DVertexShader9> FilterVertexShader;
|
||
|
FilterVertexShader FilterVShaders[16];
|
||
|
|
||
|
// 3D support
|
||
|
#ifndef GFC_NO_3D
|
||
|
// Sets the perspective matrix for drawing a 3D movieclip
|
||
|
virtual void SetPerspective3D(const GMatrix3D &projMatIn)
|
||
|
{
|
||
|
ProjMatrix3D = projMatIn;
|
||
|
MatricesChanged = true;
|
||
|
}
|
||
|
|
||
|
// Sets the view matrix for drawing a 3D movieclip
|
||
|
virtual void SetView3D(const GMatrix3D &viewMatIn)
|
||
|
{
|
||
|
ViewMatrix3D = viewMatIn;
|
||
|
MatricesChanged = true;
|
||
|
}
|
||
|
|
||
|
// Sets the world matrix for drawing a 3D movieclip
|
||
|
virtual void SetWorld3D(const GMatrix3D *pWorldMatIn)
|
||
|
{
|
||
|
pWorldMatrix3D = pWorldMatIn;
|
||
|
}
|
||
|
|
||
|
GMatrix3D ViewMatrix3D;
|
||
|
GMatrix3D ProjMatrix3D;
|
||
|
const GMatrix3D *pWorldMatrix3D; // can be NULL if not using 3D
|
||
|
|
||
|
bool MatricesChanged; // bool indicating whether we need to re-cache View, Proj, and User Matrices
|
||
|
GMatrix3D UserViewProjMatrix3D; // cached user * view * projection matrices as an optimization
|
||
|
#endif
|
||
|
GRendererD3DxImpl()
|
||
|
{
|
||
|
ModeSet = 0;
|
||
|
UsePixelShaders = 0;
|
||
|
UseDynamicTex = 0;
|
||
|
UseManagedTex = 0;
|
||
|
|
||
|
VMCFlags = 0;
|
||
|
|
||
|
StencilChecked = 0;
|
||
|
StencilAvailable = 0;
|
||
|
DepthBufferAvailable= 0;
|
||
|
MultiBitStencil = 0;
|
||
|
StencilCounter = 0;
|
||
|
// Increment/decreent ops; replace means not available (until mode config).
|
||
|
StencilOpInc = D3DSTENCILOP_REPLACE;
|
||
|
StencilOpDec = D3DSTENCILOP_REPLACE;
|
||
|
|
||
|
VDeclIndex = VD_None;
|
||
|
VShaderIndex = VS_None;
|
||
|
PShaderIndex = PS_None;
|
||
|
PShaderPass = 0;
|
||
|
|
||
|
SampleMode[0] = Sample_Linear;
|
||
|
SampleMode[1] = Sample_Linear;
|
||
|
|
||
|
pDevice = 0;
|
||
|
hWnd = 0;
|
||
|
BlendMode = Blend_None;
|
||
|
//BlendModeStack.SetSizePolicy(GArrayPolicy::Buffer_NoShrink); // Anachronism
|
||
|
|
||
|
RenderMode = 0;
|
||
|
TempW = 512;
|
||
|
TempH = 512;
|
||
|
AlphaTextureFormat = D3DFMT_A8;
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
pWorldMatrix3D = NULL;
|
||
|
MatricesChanged = false;
|
||
|
#endif
|
||
|
|
||
|
for (int i=0; i< VS_Count; i++)
|
||
|
VertexShaders[i] = 0;
|
||
|
for (int i=0; i< PS_Count; i++)
|
||
|
PixelShaders[i] = 0;
|
||
|
}
|
||
|
|
||
|
~GRendererD3DxImpl()
|
||
|
{
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
void Clear()
|
||
|
{
|
||
|
// Remove/notify all textures
|
||
|
{
|
||
|
GLock::Locker guard(&TexturesLock);
|
||
|
while (Textures.pFirst != &Textures)
|
||
|
((GTextureD3DxImpl*)Textures.pFirst)->RemoveFromRenderer();
|
||
|
|
||
|
while (RenderTargets.pFirst != &RenderTargets)
|
||
|
((GRenderTargetD3D9Impl*)RenderTargets.pFirst)->RemoveFromRenderer();
|
||
|
}
|
||
|
CacheList.ReleaseList();
|
||
|
|
||
|
if (ModeSet)
|
||
|
ResetVideoMode();
|
||
|
else
|
||
|
ReleaseQueuedResources();
|
||
|
}
|
||
|
|
||
|
void ReleaseResources()
|
||
|
{
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
// Helpers used to create vertex declarations and shaders.
|
||
|
bool CreateVertexDeclaration(GPtr<IDirect3DVertexDeclaration9> *pdeclPtr, const D3DVERTEXELEMENT9 *pvertexElements)
|
||
|
{
|
||
|
if (!*pdeclPtr)
|
||
|
{
|
||
|
if (pDevice->CreateVertexDeclaration(pvertexElements, &pdeclPtr->GetRawRef()) != S_OK)
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererD3Dx - failed to create vertex declaration");
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool CreateVertexShader(GPtr<IDirect3DVertexShader9> *pshaderPtr, const char* pshaderText)
|
||
|
{
|
||
|
if (!*pshaderPtr)
|
||
|
{
|
||
|
GPtr<ID3DXBuffer> pshader;
|
||
|
GPtr<ID3DXBuffer> pmsg;
|
||
|
HRESULT hr;
|
||
|
|
||
|
#ifdef GRENDERER_VSHADER_PROFILE
|
||
|
hr = D3DXCompileShader(pshaderText, (UInt)strlen(pshaderText),
|
||
|
NULL, NULL, "main", VShaderProfile, /*D3DXSHADER_DEBUG*/0, &pshader.GetRawRef(), &pmsg.GetRawRef(), NULL);
|
||
|
#else
|
||
|
hr = D3DXAssembleShader(pshaderText, (UInt)strlen(pshaderText),
|
||
|
NULL, NULL, D3DXSHADER_DEBUG, &pshader.GetRawRef(), NULL);
|
||
|
#endif
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
GFC_DEBUG_WARNING1(1, "GRendererD3Dx - VertexShader errors:\n %s ", pmsg ? pmsg->GetBufferPointer() : "" );
|
||
|
return 0;
|
||
|
}
|
||
|
if (!pshader ||
|
||
|
((hr = pDevice->CreateVertexShader((DWORD*)pshader->GetBufferPointer(), &pshaderPtr->GetRawRef())) != S_OK) )
|
||
|
{
|
||
|
GFC_DEBUG_WARNING1(1, "GRendererD3Dx - Can't create D3Dx vshader; error code = %d", hr);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
bool CreateVertexShader(DWORD *pshaderPtr, const char* pshaderText, DWORD *pDecl)
|
||
|
{
|
||
|
if (!*pshaderPtr)
|
||
|
{
|
||
|
GPtr<ID3DXBuffer> pshader;
|
||
|
GPtr<ID3DXBuffer> pmsg;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = D3DXAssembleShader(pshaderText, (UInt)strlen(pshaderText), 0, NULL, &pshader.GetRawRef(), &pmsg.GetRawRef());
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
GFC_DEBUG_WARNING1(1, "GRendererD3Dx - VertexShader errors:\n %s ", pmsg ? pmsg->GetBufferPointer() : "" );
|
||
|
return 0;
|
||
|
}
|
||
|
if (!pshader ||
|
||
|
((hr = pDevice->CreateVertexShader( pDecl, (DWORD*)pshader->GetBufferPointer(),
|
||
|
pshaderPtr, 0)) != S_OK) )
|
||
|
{
|
||
|
GFC_DEBUG_WARNING1(1, "GRendererD3Dx - Can't create D3Dx vshader; error code = %d", hr);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
bool CreatePixelShader(GPtr<IDirect3DPixelShader9> *pshaderPtr, const char* pshaderText)
|
||
|
{
|
||
|
if (!*pshaderPtr)
|
||
|
{
|
||
|
GPtr<ID3DXBuffer> pmsg;
|
||
|
GPtr<ID3DXBuffer> pshader;
|
||
|
HRESULT hr;
|
||
|
|
||
|
#ifdef GRENDERER_PSHADER_PROFILE
|
||
|
hr = D3DXCompileShader(pshaderText, (UInt)strlen(pshaderText),
|
||
|
NULL, NULL, "main", PShaderProfile, /*D3DXSHADER_DEBUG*/0, &pshader.GetRawRef(), &pmsg.GetRawRef(), NULL);
|
||
|
#else
|
||
|
hr = D3DXAssembleShader(pshaderText, (UInt)strlen(pshaderText),
|
||
|
NULL, NULL, D3DXSHADER_DEBUG, &pshader.GetRawRef(), &pmsg.GetRawRef());
|
||
|
#endif
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
GFC_DEBUG_WARNING2(1, "GRendererD3D9 - PixelShader errors:\n%s\n%s ", pshaderText, pmsg ? pmsg->GetBufferPointer() : "" );
|
||
|
return 0;
|
||
|
}
|
||
|
if (!pshader ||
|
||
|
((hr = pDevice->CreatePixelShader( (DWORD*)pshader->GetBufferPointer(),
|
||
|
&pshaderPtr->GetRawRef())) != S_OK) )
|
||
|
{
|
||
|
GFC_DEBUG_WARNING1(1, "GRendererD3D9 - Can't create D3D9 pshader; error code = %d", hr);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
bool CreatePixelShader(DWORD *pshaderPtr, const char* pshaderText)
|
||
|
{
|
||
|
if (!*pshaderPtr)
|
||
|
{
|
||
|
GPtr<ID3DXBuffer> pmsg;
|
||
|
GPtr<ID3DXBuffer> pshader;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = D3DXAssembleShader(pshaderText, (UInt)strlen(pshaderText), 0, NULL, &pshader.GetRawRef(), &pmsg.GetRawRef());
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
GFC_DEBUG_WARNING1(1, "GRendererD3Dx - PixelShader errors:\n %s ", pmsg ? pmsg->GetBufferPointer() : "" );
|
||
|
return 0;
|
||
|
}
|
||
|
if (!pshader ||
|
||
|
((hr = pDevice->CreatePixelShader( (DWORD*)pshader->GetBufferPointer(),
|
||
|
pshaderPtr)) != S_OK) )
|
||
|
{
|
||
|
GFC_DEBUG_WARNING1(1, "GRendererD3Dx - Can't create D3Dx pshader; error code = %d", hr);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// Initialize the shaders we use for SWF mesh rendering.
|
||
|
bool InitShaders(D3DCAPSx *caps)
|
||
|
{
|
||
|
bool success = 1;
|
||
|
UInt i;
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
UInt vstart = 0;
|
||
|
|
||
|
if ((caps->DeclTypes & D3DDTCAPS_UBYTE4N) == 0)
|
||
|
vstart = 1;
|
||
|
|
||
|
for (i = 1; i < VD_Count; i++)
|
||
|
if (!CreateVertexDeclaration(&VertexDecls[i], VertexDeclTypeTable[vstart*(VD_Count-1)+i-1]))
|
||
|
{
|
||
|
success = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
for (i = 1; i < VS_Count; i++)
|
||
|
if (!CreateVertexShader(&VertexShaders[i], VertexShaderTextTable[vstart*(VS_Count-1)+i-1]))
|
||
|
{
|
||
|
success = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
GUNUSED(caps);
|
||
|
for (i = 1; i < VS_Count; i++)
|
||
|
if (!CreateVertexShader(&VertexShaders[i], VertexShaderTextTable[(VS_Count-1)+i-1],
|
||
|
VertexDeclTable[VertexShaderDeclTable[i]]))
|
||
|
{
|
||
|
success = 0;
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// We only use pixel shaders conditionally if their support is available.
|
||
|
if (UsePixelShaders)
|
||
|
{
|
||
|
#if (GRENDERER_SHADER_VERSION == 0x0101) && !defined(GRENDERER_PSHADER_PROFILE)
|
||
|
for (i = 1; i < PS_CountSource; i++)
|
||
|
{
|
||
|
if (UseYUVShaders == 0 && i >= PS_TextTextureYUV && i <= PS_TextTextureYUVAMultiply)
|
||
|
{
|
||
|
PixelShaders[i] = 0;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (PixelShaderInitTable[i-1].pShader)
|
||
|
{
|
||
|
if (!CreatePixelShader(&PixelShaders[i], PixelShaderInitTable[i-1].pShader))
|
||
|
{
|
||
|
success = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (i < PS_CountAcSource)
|
||
|
{
|
||
|
char pSourceAc[768];
|
||
|
|
||
|
G_strcpy(pSourceAc, 768, PixelShaderInitTable[i-1].pShader);
|
||
|
G_strcat(pSourceAc, 768, "mul r0.rgb, r0, r0.a\n");
|
||
|
|
||
|
if (!CreatePixelShader(&PixelShaders[i+PS_AcOffset], pSourceAc))
|
||
|
{
|
||
|
success = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
for (i = 1; i < PS_Count; i++)
|
||
|
{
|
||
|
if (PixelShaderInitTable[i-1].pShader)
|
||
|
{
|
||
|
if (!CreatePixelShader(&PixelShaders[i], PixelShaderInitTable[i-1].pShader))
|
||
|
{
|
||
|
success = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (FiltersSupported >= 3)
|
||
|
{
|
||
|
for (int i = 0; i < FS2_FCMatrix; i++)
|
||
|
/*
|
||
|
if (FShaderSources2[i])
|
||
|
{
|
||
|
if (!CreatePixelShader(&StaticFilterShaders[i], FShaderSources2[i]))
|
||
|
{
|
||
|
success = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
if (FShaderBinaries2[i])
|
||
|
{
|
||
|
if (FAILED(pDevice->CreatePixelShader((const DWORD*) FShaderBinaries2[i], &StaticFilterShaders[i].GetRawRef())))
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererD3D9 - Can't create D3D9 pshader");
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!success)
|
||
|
{
|
||
|
ReleaseShaders();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ReleaseShaders()
|
||
|
{
|
||
|
UInt i;
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 8)
|
||
|
for (i=0; i< VS_Count; i++)
|
||
|
if (VertexShaders[i])
|
||
|
pDevice->DeleteVertexShader(VertexShaders[i]);
|
||
|
|
||
|
for (i=0; i< PS_Count; i++)
|
||
|
if (PixelShaders[i])
|
||
|
pDevice->DeletePixelShader(PixelShaders[i]);
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 9)
|
||
|
for (i=0; i< VD_Count; i++)
|
||
|
if (VertexDecls[i])
|
||
|
VertexDecls[i] = 0;
|
||
|
#endif
|
||
|
|
||
|
for (i=0; i< VS_Count; i++)
|
||
|
if (VertexShaders[i])
|
||
|
VertexShaders[i] = 0;
|
||
|
|
||
|
for (i=0; i< PS_Count; i++)
|
||
|
if (PixelShaders[i])
|
||
|
PixelShaders[i] = 0;
|
||
|
|
||
|
for (i=0; i< FS2_Count; i++)
|
||
|
StaticFilterShaders[i] = 0;
|
||
|
|
||
|
for (FilterShadersType::ConstIterator i = FilterShaders.Begin(); i != FilterShaders.End(); ++i)
|
||
|
{
|
||
|
FilterShader* pfs = i->Second;
|
||
|
delete pfs;
|
||
|
}
|
||
|
FilterShaders.Clear();
|
||
|
|
||
|
for (i=0; i< 16; i++)
|
||
|
{
|
||
|
FilterVShaders[i].pVDecl = 0;
|
||
|
FilterVShaders[i].pVShader = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Sets a shader to specified type.
|
||
|
void SetVertexDecl(VDeclType vd)
|
||
|
{
|
||
|
if (VDeclIndex != vd)
|
||
|
{
|
||
|
VDeclIndex = vd;
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
pDevice->SetVertexDeclaration(VertexDecls[vd]);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
void SetVertexShader(VShaderType vt)
|
||
|
{
|
||
|
if (VShaderIndex != vt)
|
||
|
{
|
||
|
GASSERT(VertexShaderDeclTable[vt] == VDeclIndex);
|
||
|
VShaderIndex = vt;
|
||
|
pDevice->SetVertexShader(VertexShaders[vt]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void ApplyTextureStageConstants(const TextureStageDesc* plist)
|
||
|
{
|
||
|
DWORD endingStage = 0;
|
||
|
|
||
|
if (plist)
|
||
|
{
|
||
|
while (plist->Stage != -1)
|
||
|
{
|
||
|
pDevice->SetTextureStageState(plist->Stage, plist->State, plist->Value);
|
||
|
if (plist->Stage >= endingStage)
|
||
|
endingStage = plist->Stage + 1;
|
||
|
plist++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (RenderMode & GViewport::View_AlphaComposite)
|
||
|
{
|
||
|
const TextureStageDesc* plist = pStates_TS_AlphaComposite;
|
||
|
|
||
|
while (plist->Stage != -1)
|
||
|
{
|
||
|
pDevice->SetTextureStageState(endingStage, plist->State, plist->Value);
|
||
|
plist++;
|
||
|
}
|
||
|
|
||
|
endingStage++;
|
||
|
}
|
||
|
|
||
|
// Disable other stages.
|
||
|
pDevice->SetTextureStageState(endingStage, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
||
|
pDevice->SetTextureStageState(endingStage, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Set shader to a device based on a constant
|
||
|
void SetPixelShader(PixelShaderType shaderType, int pass = 0)
|
||
|
{
|
||
|
if ((shaderType != PShaderIndex) || (PShaderPass != pass))
|
||
|
{
|
||
|
if (UsePixelShaders)
|
||
|
{
|
||
|
if (RenderMode & GViewport::View_AlphaComposite && !UseAcBlend)
|
||
|
shaderType = (PixelShaderType) (int(shaderType) + int(PS_AcOffset));
|
||
|
|
||
|
pDevice->SetPixelShader(PixelShaders[shaderType]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GASSERT(pass <= 1);
|
||
|
|
||
|
if (shaderType == PS_None)
|
||
|
ApplyTextureStageConstants(0);
|
||
|
else
|
||
|
{
|
||
|
if (pass == 0)
|
||
|
{
|
||
|
ApplyTextureStageConstants(PixelShaderInitTable[shaderType-1].pPass0Desc);
|
||
|
}
|
||
|
else // if (pass == 1)
|
||
|
{
|
||
|
ApplyTextureStageConstants(PixelShaderInitTable[shaderType-1].pPass1Desc);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PShaderIndex = shaderType;
|
||
|
PShaderPass = pass;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// Utility. Mutates *width, *height and *data to create the
|
||
|
// next mip level.
|
||
|
static void MakeNextMiplevel(int* width, int* height, UByte* data)
|
||
|
{
|
||
|
GASSERT(width);
|
||
|
GASSERT(height);
|
||
|
GASSERT(data);
|
||
|
GASSERT_ON_RENDERER_MIPMAP_GEN;
|
||
|
|
||
|
int newW = *width >> 1;
|
||
|
int newH = *height >> 1;
|
||
|
if (newW < 1) newW = 1;
|
||
|
if (newH < 1) newH = 1;
|
||
|
|
||
|
if (newW * 2 != *width || newH * 2 != *height)
|
||
|
{
|
||
|
// Image can't be shrunk Along (at least) one
|
||
|
// of its dimensions, so don't bother
|
||
|
// resampling. Technically we should, but
|
||
|
// it's pretty useless at this point. Just
|
||
|
// change the image dimensions and leave the
|
||
|
// existing pixels.
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Resample. Simple average 2x2 --> 1, in-place.
|
||
|
for (int j = 0; j < newH; j++)
|
||
|
{
|
||
|
UByte* out = ((UByte*) data) + j * newW;
|
||
|
UByte* in = ((UByte*) data) + (j << 1) * *width;
|
||
|
for (int i = 0; i < newW; i++)
|
||
|
{
|
||
|
int a = (*(in + 0) + *(in + 1) + *(in + 0 + *width) + *(in + 1 + *width));
|
||
|
*(out) = UByte(a >> 2);
|
||
|
out++;
|
||
|
in += 2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Munge parameters to reflect the shrunken image.
|
||
|
*width = newW;
|
||
|
*height = newH;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ApplySampleMode(int stageIndex, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps)
|
||
|
{
|
||
|
GUNUSED(useMipmaps);
|
||
|
|
||
|
// Set sampling
|
||
|
_D3DTEXTUREFILTERTYPE filter =
|
||
|
(SampleMode == Sample_Point) ? D3DTEXF_POINT : D3DTEXF_LINEAR;
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
if (WrapMode == Wrap_Clamp)
|
||
|
{
|
||
|
pDevice->SetSamplerState(stageIndex, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
|
||
|
pDevice->SetSamplerState(stageIndex, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GASSERT(WrapMode == Wrap_Repeat);
|
||
|
pDevice->SetSamplerState(stageIndex, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
|
||
|
pDevice->SetSamplerState(stageIndex, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
|
||
|
}
|
||
|
pDevice->SetSamplerState(stageIndex, D3DSAMP_MINFILTER, filter);
|
||
|
pDevice->SetSamplerState(stageIndex, D3DSAMP_MAGFILTER, filter);
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
if (WrapMode == Wrap_Clamp)
|
||
|
{
|
||
|
pDevice->SetTextureStageState(stageIndex, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
|
||
|
pDevice->SetTextureStageState(stageIndex, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GASSERT(WrapMode == Wrap_Repeat);
|
||
|
pDevice->SetTextureStageState(stageIndex, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP);
|
||
|
pDevice->SetTextureStageState(stageIndex, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP);
|
||
|
}
|
||
|
pDevice->SetTextureStageState(stageIndex, D3DTSS_MINFILTER, filter);
|
||
|
pDevice->SetTextureStageState(stageIndex, D3DTSS_MAGFILTER, filter);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
// Fill helper function:
|
||
|
// Applies fill texture by setting it to the specified stage, initializing samplers and vertex constants
|
||
|
void ApplyFillTexture(const FillTexture &fill, UInt stageIndex, UInt matrixVertexConstIndex)
|
||
|
{
|
||
|
GASSERT (fill.pTexture != 0);
|
||
|
if (fill.pTexture == 0) return; // avoid crash in release build
|
||
|
|
||
|
GTextureD3DxImpl* ptexture = ((GTextureD3DxImpl*)fill.pTexture);
|
||
|
ptexture->Bind(stageIndex, fill.WrapMode, fill.SampleMode, 0);
|
||
|
|
||
|
// Set up the bitmap matrix for texgen.
|
||
|
const Matrix& m = fill.TextureMatrix;
|
||
|
Float p[4] = { 0, 0, 0, 0 };
|
||
|
p[0] = m.M_[0][0];
|
||
|
p[1] = m.M_[0][1];
|
||
|
p[3] = m.M_[0][2];
|
||
|
pDevice->SetVertexShaderConstant(matrixVertexConstIndex, p, 1);
|
||
|
|
||
|
p[0] = m.M_[1][0];
|
||
|
p[1] = m.M_[1][1];
|
||
|
p[3] = m.M_[1][2];
|
||
|
pDevice->SetVertexShaderConstant(matrixVertexConstIndex + 1, p, 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
void ApplyPShaderCxform(const Cxform &cxform, UInt cxformPShaderConstIndex) const
|
||
|
{
|
||
|
if (UsePixelShaders)
|
||
|
{
|
||
|
const float mult = 1.0f / 255.0f;
|
||
|
|
||
|
float cxformData[4 * 2] =
|
||
|
{
|
||
|
cxform.M_[0][0], cxform.M_[1][0],
|
||
|
cxform.M_[2][0], cxform.M_[3][0],
|
||
|
// Cxform color is already pre-multiplied
|
||
|
cxform.M_[0][1] * mult, cxform.M_[1][1] * mult,
|
||
|
cxform.M_[2][1] * mult, cxform.M_[3][1] * mult
|
||
|
};
|
||
|
|
||
|
pDevice->SetPixelShaderConstant(cxformPShaderConstIndex, cxformData, 2);
|
||
|
}
|
||
|
|
||
|
else
|
||
|
{
|
||
|
// For fixed - function states we store Multiply into TEXTUREFACTOR.
|
||
|
// Add can not be supported correctly, although we try to 'fake' it with second pass.
|
||
|
D3DCOLOR color = D3DCOLOR_ARGB(
|
||
|
(UByte)(cxform.M_[3][0] * 255.0f),
|
||
|
(UByte)(cxform.M_[0][0] * 255.0f),
|
||
|
(UByte)(cxform.M_[1][0] * 255.0f),
|
||
|
(UByte)(cxform.M_[2][0] * 255.0f)
|
||
|
);
|
||
|
pDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ApplyTint100Cxform(const Cxform &cxform) const
|
||
|
{
|
||
|
D3DCOLOR color = D3DCOLOR_ARGB(
|
||
|
(UByte)(cxform.M_[3][0] * 255.0f),
|
||
|
(UByte)(cxform.M_[0][1]),
|
||
|
(UByte)(cxform.M_[1][1]),
|
||
|
(UByte)(cxform.M_[2][1])
|
||
|
);
|
||
|
pDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
|
||
|
}
|
||
|
|
||
|
class GFxFillStyle
|
||
|
{
|
||
|
public:
|
||
|
enum FillMode
|
||
|
{
|
||
|
FM_None,
|
||
|
FM_Color,
|
||
|
FM_Bitmap,
|
||
|
FM_Gouraud
|
||
|
};
|
||
|
|
||
|
FillMode Mode;
|
||
|
|
||
|
GouraudFillType GouraudType;
|
||
|
GColor Color;
|
||
|
|
||
|
Cxform BitmapColorTransform;
|
||
|
bool HasNonzeroAdditiveCxform;
|
||
|
bool IsTint100Cxform;
|
||
|
|
||
|
FillTexture Fill;
|
||
|
FillTexture Fill2;
|
||
|
|
||
|
|
||
|
GFxFillStyle()
|
||
|
{
|
||
|
Mode = FM_None;
|
||
|
GouraudType = GFill_Color;
|
||
|
Fill.pTexture = 0;
|
||
|
Fill2.pTexture = 0;
|
||
|
HasNonzeroAdditiveCxform = 0;
|
||
|
IsTint100Cxform = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Push our style into Direct3D
|
||
|
void Apply(GRendererD3DxImpl *prenderer) const
|
||
|
{
|
||
|
IDirect3DDeviceX* pdevice = prenderer->pDevice;
|
||
|
GASSERT(Mode != FM_None);
|
||
|
|
||
|
|
||
|
// Complex
|
||
|
prenderer->ApplyBlendMode(prenderer->BlendMode);
|
||
|
|
||
|
pdevice->SetRenderState(D3DRS_ALPHABLENDENABLE,
|
||
|
((Color.GetAlpha()== 0xFF) &&
|
||
|
(prenderer->BlendMode <= Blend_Normal) &&
|
||
|
(Mode != FM_Gouraud)) ? FALSE : TRUE);
|
||
|
|
||
|
|
||
|
// Non-Edge AA Rendering.
|
||
|
|
||
|
if (Mode == FM_Color)
|
||
|
{
|
||
|
// Solid color fills.
|
||
|
prenderer->SetPixelShader(PS_SolidColor);
|
||
|
prenderer->ApplyColor(Color);
|
||
|
}
|
||
|
|
||
|
else if (Mode == FM_Bitmap)
|
||
|
{
|
||
|
// Gradiend and texture fills.
|
||
|
GASSERT(Fill.pTexture != NULL);
|
||
|
|
||
|
prenderer->ApplyColor(Color);
|
||
|
|
||
|
if (Fill.pTexture == NULL)
|
||
|
{
|
||
|
// Just in case, for release build.
|
||
|
prenderer->SetPixelShader(PS_None);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pdevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||
|
|
||
|
if (!prenderer->UsePixelShaders && IsTint100Cxform)
|
||
|
{
|
||
|
if ((prenderer->BlendMode == Blend_Multiply) ||
|
||
|
(prenderer->BlendMode == Blend_Darken) )
|
||
|
prenderer->SetPixelShader(PS_TintTextureMultiply);
|
||
|
else
|
||
|
prenderer->SetPixelShader(PS_TintTexture);
|
||
|
|
||
|
prenderer->ApplyTint100Cxform(BitmapColorTransform);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ((prenderer->BlendMode == Blend_Multiply) ||
|
||
|
(prenderer->BlendMode == Blend_Darken) )
|
||
|
prenderer->SetPixelShader(PS_CxformTextureMultiply);
|
||
|
else
|
||
|
prenderer->SetPixelShader(PS_CxformTexture);
|
||
|
|
||
|
prenderer->ApplyPShaderCxform(BitmapColorTransform, 2);
|
||
|
}
|
||
|
|
||
|
// Set texture to stage 0; matrix to constants 4 and 5
|
||
|
prenderer->ApplyFillTexture(Fill, 0, 4);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Edge AA - relies on Gouraud shading and texture mixing
|
||
|
else if (Mode == FM_Gouraud)
|
||
|
{
|
||
|
|
||
|
PixelShaderType shader = PS_None;
|
||
|
|
||
|
// No texture: generate color-shaded triangles.
|
||
|
if (Fill.pTexture == NULL)
|
||
|
{
|
||
|
pdevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||
|
|
||
|
|
||
|
if (prenderer->VertexStream.GetVertexFormat() == Vertex_XY16iC32)
|
||
|
{
|
||
|
// Cxform Alpha Add can not be non-zero is this state because
|
||
|
// cxform blend equations can not work correctly.
|
||
|
// If we hit this assert, it means Vertex_XY16iCF32 should have been used.
|
||
|
//GASSERT (BitmapColorTransform.M_[3][1] < 1.0f);
|
||
|
|
||
|
shader = PS_CxformGauraudNoAddAlpha;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
shader = PS_CxformGauraud;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// We have a textured or multi-textured gouraud case.
|
||
|
else
|
||
|
{
|
||
|
pdevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||
|
|
||
|
// Set texture to stage 0; matrix to constants 4 and 5
|
||
|
prenderer->ApplyFillTexture(Fill, 0, 4);
|
||
|
|
||
|
if ((GouraudType == GFill_1TextureColor) ||
|
||
|
(GouraudType == GFill_1Texture))
|
||
|
{
|
||
|
shader = PS_CxformGauraudTexture;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
shader = PS_Cxform2Texture;
|
||
|
|
||
|
// Set second texture to stage 1; matrix to constants 6 and 7
|
||
|
prenderer->ApplyFillTexture(Fill2, 1, 6);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
if ((prenderer->BlendMode == Blend_Multiply) ||
|
||
|
(prenderer->BlendMode == Blend_Darken) )
|
||
|
{
|
||
|
shader = (PixelShaderType)(shader + (PS_CxformGauraudMultiply - PS_CxformGauraud));
|
||
|
|
||
|
// For indexing to work, these should hold:
|
||
|
GCOMPILER_ASSERT( (PS_Cxform2Texture - PS_CxformGauraud) ==
|
||
|
(PS_CxformMultiply2Texture - PS_CxformGauraudMultiply));
|
||
|
GCOMPILER_ASSERT( (PS_CxformGauraudMultiply - PS_CxformGauraud) ==
|
||
|
(PS_Cxform2Texture - PS_CxformGauraud + 1) );
|
||
|
}
|
||
|
prenderer->SetPixelShader(shader);
|
||
|
prenderer->ApplyPShaderCxform(BitmapColorTransform, 2);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// Return true if we need to do a second pass to make a valid color.
|
||
|
bool NeedsSecondPass(GRendererD3DxImpl *prenderer) const
|
||
|
{
|
||
|
if (prenderer->UsePixelShaders)
|
||
|
return 0;
|
||
|
if (Mode != FM_Bitmap && Mode != FM_Gouraud)
|
||
|
return 0;
|
||
|
|
||
|
// Second pass must be enabled.
|
||
|
if (!PixelShaderInitTable[prenderer->PShaderIndex-1].pPass1Desc)
|
||
|
return 0;
|
||
|
|
||
|
return HasNonzeroAdditiveCxform;
|
||
|
}
|
||
|
|
||
|
// Set D3D state for a necessary second pass.
|
||
|
void ApplySecondPass(GRendererD3DxImpl* prenderer) const
|
||
|
{
|
||
|
GASSERT(NeedsSecondPass(prenderer));
|
||
|
GASSERT(!prenderer->UsePixelShaders);
|
||
|
|
||
|
// Additive color. Already pre-multiplied by 255
|
||
|
D3DCOLOR color = D3DCOLOR_ARGB(
|
||
|
(UByte)BitmapColorTransform.M_[3][1],
|
||
|
(UByte)BitmapColorTransform.M_[0][1],
|
||
|
(UByte)BitmapColorTransform.M_[1][1],
|
||
|
(UByte)BitmapColorTransform.M_[2][1] );
|
||
|
|
||
|
prenderer->pDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
|
||
|
|
||
|
// Second pass shader.
|
||
|
prenderer->SetPixelShader(prenderer->PShaderIndex, 1);
|
||
|
|
||
|
// Color add, but multiply added color by alpha to cull non-blended pixels.
|
||
|
prenderer->pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||
|
prenderer->pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void Disable()
|
||
|
{
|
||
|
Mode = FM_None;
|
||
|
Fill.pTexture = 0;
|
||
|
}
|
||
|
void SetColor(GColor color)
|
||
|
{
|
||
|
Mode = FM_Color; Color = color;
|
||
|
}
|
||
|
|
||
|
void SetCxform(const Cxform& colorTransform)
|
||
|
{
|
||
|
BitmapColorTransform = colorTransform;
|
||
|
HasNonzeroAdditiveCxform = false;
|
||
|
IsTint100Cxform = false;
|
||
|
|
||
|
if ( BitmapColorTransform.M_[0][1] > 1.0f ||
|
||
|
BitmapColorTransform.M_[1][1] > 1.0f ||
|
||
|
BitmapColorTransform.M_[2][1] > 1.0f)
|
||
|
{
|
||
|
if (BitmapColorTransform.M_[0][0] == 0 && BitmapColorTransform.M_[1][0] == 0 &&
|
||
|
BitmapColorTransform.M_[2][0] == 0 && BitmapColorTransform.M_[3][1] == 0)
|
||
|
IsTint100Cxform = true;
|
||
|
else
|
||
|
HasNonzeroAdditiveCxform = true;
|
||
|
}
|
||
|
else if (BitmapColorTransform.M_[3][1] > 1.0f )
|
||
|
HasNonzeroAdditiveCxform = true;
|
||
|
}
|
||
|
|
||
|
void SetBitmap(const FillTexture* pft, const Cxform& colorTransform)
|
||
|
{
|
||
|
Mode = FM_Bitmap;
|
||
|
Fill = *pft;
|
||
|
Color = GColor(0xFFFFFFFF);
|
||
|
|
||
|
SetCxform(colorTransform);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Sets the interpolated color/texture fill style used for shapes with EdgeAA.
|
||
|
// The specified textures are applied to vertices {0, 1, 2} of each triangle based
|
||
|
// on factors of Complex vertex. Any or all subsequent pointers can be NULL, in which case
|
||
|
// texture is not applied and vertex colors used instead.
|
||
|
void SetGouraudFill(GouraudFillType gfill,
|
||
|
const FillTexture *ptexture0,
|
||
|
const FillTexture *ptexture1,
|
||
|
const FillTexture *ptexture2, const Cxform& colorTransform)
|
||
|
{
|
||
|
|
||
|
// Texture2 is not yet used.
|
||
|
if (ptexture0 || ptexture1 || ptexture2)
|
||
|
{
|
||
|
const FillTexture *p = ptexture0;
|
||
|
if (!p) p = ptexture1;
|
||
|
|
||
|
SetBitmap(p, colorTransform);
|
||
|
// Used in 2 texture mode
|
||
|
if (ptexture1)
|
||
|
Fill2 = *ptexture1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetCxform(colorTransform);
|
||
|
Fill.pTexture = 0;
|
||
|
}
|
||
|
|
||
|
Mode = GFxFillStyle::FM_Gouraud;
|
||
|
GouraudType = gfill;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool IsValid() const
|
||
|
{
|
||
|
return Mode != FM_None;
|
||
|
}
|
||
|
|
||
|
}; // class GFxFillStyle
|
||
|
|
||
|
|
||
|
|
||
|
// Style state.
|
||
|
enum StyleIndex
|
||
|
{
|
||
|
FILL_STYLE = 0,
|
||
|
LINE_STYLE,
|
||
|
STYLE_COUNT
|
||
|
};
|
||
|
GFxFillStyle CurrentStyles[STYLE_COUNT];
|
||
|
|
||
|
|
||
|
// Given an image, returns a Pointer to a GTexture struct
|
||
|
// that can later be passed to FillStyleX_bitmap(), to set a
|
||
|
// bitmap fill style.
|
||
|
GTextureD3Dx* CreateTexture()
|
||
|
{
|
||
|
ReleaseQueuedResources();
|
||
|
|
||
|
GLock::Locker guard(&TexturesLock);
|
||
|
return new GTextureD3DxImpl(this);
|
||
|
}
|
||
|
|
||
|
GTextureD3Dx* CreateTextureYUV()
|
||
|
{
|
||
|
if (!UseYUVShaders)
|
||
|
return NULL;
|
||
|
|
||
|
ReleaseQueuedResources();
|
||
|
|
||
|
GLock::Locker guard(&TexturesLock);
|
||
|
return new GTextureD3DxImplYUV(this);
|
||
|
}
|
||
|
|
||
|
GTextureD3Dx* CreateDepthStencilBuffer()
|
||
|
{
|
||
|
ReleaseQueuedResources();
|
||
|
|
||
|
GLock::Locker guard(&TexturesLock);
|
||
|
return new GDepthBufferD3D9Impl(this);
|
||
|
}
|
||
|
|
||
|
// Helper function to query renderer capabilities.
|
||
|
bool GetRenderCaps(RenderCaps *pcaps)
|
||
|
{
|
||
|
pcaps->CapBits = Cap_Index16 | Cap_FillGouraud | Cap_CanLoseData;
|
||
|
pcaps->BlendModes = (1<<Blend_None) | (1<<Blend_Normal) |
|
||
|
(1<<Blend_Multiply) | (1<<Blend_Lighten) | (1<<Blend_Darken) |
|
||
|
(1<<Blend_Add) | (1<<Blend_Subtract);
|
||
|
pcaps->VertexFormats= (1<<Vertex_None) | (1<<Vertex_XY16i) | (1<<Vertex_XY16iC32) | (1<<Vertex_XY16iCF32);
|
||
|
|
||
|
if (!ModeSet)
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererD3Dx::GetRenderCaps fails - video mode not set");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
D3DCAPSx caps;
|
||
|
pDevice->GetDeviceCaps(&caps);
|
||
|
// Not supported with software indexing (does not matter for GFxPlayer so far).
|
||
|
//if (caps.MaxVertexIndex > 0xFFFF)
|
||
|
// pcaps->CapBits |= Cap_Index32;
|
||
|
|
||
|
if (UsePixelShaders)
|
||
|
{
|
||
|
GASSERT((caps.PixelShaderVersion & 0xFFFF) >= 0x0101);
|
||
|
pcaps->CapBits |= Cap_CxformAdd;
|
||
|
pcaps->CapBits |= Cap_FillGouraudTex;
|
||
|
|
||
|
if (FiltersSupported)
|
||
|
{
|
||
|
pcaps->CapBits |= Cap_RenderTargets;
|
||
|
pcaps->CapBits |= Cap_Filter_Blurs | Cap_Filter_ColorMatrix;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (TexNonPower2 >= 1)
|
||
|
pcaps->CapBits |= Cap_TexNonPower2;
|
||
|
if (TexNonPower2 >= 2)
|
||
|
pcaps->CapBits |= Cap_TexNonPower2Wrap | Cap_TexNonPower2Mip;
|
||
|
|
||
|
if (caps.StencilCaps & (D3DSTENCILCAPS_INCR|D3DSTENCILCAPS_INCRSAT))
|
||
|
{
|
||
|
// Need to also consider current back-buffer surface format?
|
||
|
pcaps->CapBits |= Cap_NestedMasks;
|
||
|
}
|
||
|
|
||
|
pcaps->MaxTextureSize = G_Min(caps.MaxTextureWidth, caps.MaxTextureWidth);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void PushRenderTarget(const GRectF& frameRect, GRenderTarget* prt)
|
||
|
{
|
||
|
// push onto RT stack
|
||
|
RenderTargetStack.PushBack(RTState(pCurRenderTarget, ViewportMatrix,
|
||
|
#ifndef GFC_NO_3D
|
||
|
ViewMatrix3D, ProjMatrix3D, pWorldMatrix3D,
|
||
|
#else
|
||
|
GMatrix3D(), GMatrix3D(), 0,
|
||
|
#endif
|
||
|
ViewRect, RenderMode, StencilCounter, StencilEnabled));
|
||
|
pCurRenderTarget = (GRenderTargetD3D9Impl*)prt;
|
||
|
|
||
|
// set ViewportMatrix
|
||
|
float dx = frameRect.Width();
|
||
|
float dy = frameRect.Height();
|
||
|
if (dx < 1) { dx = 1; }
|
||
|
if (dy < 1) { dy = 1; }
|
||
|
|
||
|
// Adjust by -0.5 pixel to match DirectX pixel coverage rules.
|
||
|
Float xhalfPixelAdjust = (pCurRenderTarget->TargetWidth > 0) ? (1.0f / (Float) pCurRenderTarget->TargetWidth) : 0.0f;
|
||
|
Float yhalfPixelAdjust = (pCurRenderTarget->TargetHeight> 0) ? (1.0f / (Float) pCurRenderTarget->TargetHeight) : 0.0f;
|
||
|
|
||
|
ViewportMatrix.SetIdentity();
|
||
|
ViewportMatrix.M_[0][0] = 2.0f / dx;
|
||
|
ViewportMatrix.M_[1][1] = -2.0f / dy;
|
||
|
ViewportMatrix.M_[0][2] = -1.0f - ViewportMatrix.M_[0][0] * (frameRect.Left) - xhalfPixelAdjust;
|
||
|
ViewportMatrix.M_[1][2] = 1.0f - ViewportMatrix.M_[1][1] * (frameRect.Top) + yhalfPixelAdjust;
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
// set 3D view
|
||
|
GMatrix3D matView, matPersp;
|
||
|
MakeViewAndPersp3D(frameRect, matView, matPersp, DEFAULT_FLASH_FOV);
|
||
|
SetView3D(matView);
|
||
|
SetPerspective3D(matPersp);
|
||
|
SetWorld3D(0);
|
||
|
#endif
|
||
|
|
||
|
if (pCurRenderTarget->pTexture)
|
||
|
ViewRect = GViewport(pCurRenderTarget->pTexture->TexWidth, pCurRenderTarget->pTexture->TexHeight,
|
||
|
0,0,pCurRenderTarget->TargetWidth, pCurRenderTarget->TargetHeight, GViewport::View_RenderTextureAlpha);
|
||
|
else // Must be external render target, assuming viewport will be set by BeginDisplay.
|
||
|
ViewRect = GViewport(64,64,0,0,64,64, GViewport::View_RenderTextureAlpha);
|
||
|
|
||
|
RenderMode = GViewport::View_AlphaComposite;
|
||
|
|
||
|
// apply render target
|
||
|
// Set texture as render target
|
||
|
if (!FAILED(pDevice->SetRenderTarget(0, pCurRenderTarget->pRenderSurface)))
|
||
|
{
|
||
|
// Set stencil; this will disable it if not available.
|
||
|
pDevice->SetDepthStencilSurface(pCurRenderTarget->pStencilSurface);
|
||
|
}
|
||
|
if (!pCurRenderTarget->pStencilSurface)
|
||
|
pDevice->SetDepthStencilSurface(0);
|
||
|
|
||
|
pDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
|
||
|
|
||
|
D3DVIEWPORTx vp;
|
||
|
vp.X = 0;
|
||
|
vp.Y = 0;
|
||
|
vp.MinZ = 0.0f;
|
||
|
vp.MaxZ = 1.0f;
|
||
|
|
||
|
if (pCurRenderTarget->pTexture)
|
||
|
{
|
||
|
vp.Width = pCurRenderTarget->pTexture->TexWidth;
|
||
|
vp.Height = pCurRenderTarget->pTexture->TexHeight;
|
||
|
pDevice->SetViewport(&vp);
|
||
|
|
||
|
UInt32 Flags = D3DCLEAR_TARGET;
|
||
|
if (pCurRenderTarget->pStencilSurface)
|
||
|
Flags |= D3DCLEAR_STENCIL;
|
||
|
pDevice->Clear( 0, NULL, Flags, D3DCOLOR_ARGB(0,0,0,0), 1.0f, 0 );
|
||
|
}
|
||
|
|
||
|
vp.Width = pCurRenderTarget->TargetWidth;
|
||
|
vp.Height = pCurRenderTarget->TargetHeight;
|
||
|
pDevice->SetViewport(&vp);
|
||
|
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
StencilEnabled = 0;
|
||
|
if (StencilAvailable)
|
||
|
pDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
|
||
|
else if (DepthBufferAvailable)
|
||
|
{
|
||
|
pDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
|
||
|
pDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||
|
pDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void PopRenderTarget()
|
||
|
{
|
||
|
if (pCurRenderTarget->IsTemp)
|
||
|
pCurRenderTarget->pStencilTexture = 0;
|
||
|
|
||
|
RTState rts = RenderTargetStack.Back();
|
||
|
RenderTargetStack.PopBack();
|
||
|
pCurRenderTarget = rts.pRT;
|
||
|
ViewportMatrix = rts.ViewMatrix;
|
||
|
ViewRect = rts.ViewRect;
|
||
|
RenderMode = rts.RenderMode;
|
||
|
StencilEnabled = rts.StencilEnabled;
|
||
|
StencilCounter = rts.StencilCounter;
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
// restore 3D view matrix
|
||
|
SetView3D(rts.ViewMatrix3D);
|
||
|
SetPerspective3D(rts.PerspMatrix3D);
|
||
|
SetWorld3D(rts.pWorldMatrix3D);
|
||
|
#endif
|
||
|
|
||
|
if (!FAILED(pDevice->SetRenderTarget(0, pCurRenderTarget->pRenderSurface)))
|
||
|
{
|
||
|
// Set stencil; this will disable it if not available.
|
||
|
pDevice->SetDepthStencilSurface(pCurRenderTarget->pStencilSurface);
|
||
|
}
|
||
|
if (!pCurRenderTarget->pStencilSurface)
|
||
|
pDevice->SetDepthStencilSurface(0);
|
||
|
|
||
|
D3DVIEWPORTx vp;
|
||
|
vp.X = ViewRect.Left;
|
||
|
vp.Y = ViewRect.Top;
|
||
|
vp.Width = ViewRect.Width;
|
||
|
vp.Height = ViewRect.Height;
|
||
|
vp.MinZ = 0.0f;
|
||
|
vp.MaxZ = 1.0f;
|
||
|
pDevice->SetViewport(&vp);
|
||
|
|
||
|
pDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, (ViewRect.Flags & GViewport::View_UseScissorRect) != 0);
|
||
|
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
if (StencilEnabled && pCurRenderTarget->pStencilSurface)
|
||
|
{
|
||
|
pDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
|
||
|
EndSubmitMask();
|
||
|
}
|
||
|
else
|
||
|
DisableMask();
|
||
|
}
|
||
|
|
||
|
GTextureD3DxImpl* PushTempRenderTarget(const GRectF& frameRect, UInt inw, UInt inh, bool wantStencil)
|
||
|
{
|
||
|
GASSERT(DrawingMask == 0);
|
||
|
|
||
|
GRenderTargetD3D9Impl* pRT = 0;
|
||
|
SInt w = 1, h = 1;
|
||
|
bool needsinit = false;
|
||
|
|
||
|
for (UInt i = 0; i < TempRenderTargets.GetSize(); i++)
|
||
|
if (TempRenderTargets[i]->pTexture->GetRefCount() <= 1 &&
|
||
|
TempRenderTargets[i]->pTexture->TexWidth >= SInt(inw) &&
|
||
|
TempRenderTargets[i]->pTexture->TexHeight >= SInt(inh))
|
||
|
{
|
||
|
pRT = TempRenderTargets[i];
|
||
|
goto dostencil;
|
||
|
}
|
||
|
|
||
|
while (w < SInt(inw)) w <<= 1;
|
||
|
while (h < SInt(inh)) h <<= 1;
|
||
|
|
||
|
for (UInt i = 0; i < TempRenderTargets.GetSize(); i++)
|
||
|
if (TempRenderTargets[i]->pTexture->GetRefCount() <= 1)
|
||
|
{
|
||
|
pRT = TempRenderTargets[i];
|
||
|
needsinit = true;
|
||
|
goto dostencil;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
GTexture* prtt = CreateTexture();
|
||
|
pRT = (GRenderTargetD3D9Impl *)CreateRenderTarget();
|
||
|
pRT->IsTemp = true;
|
||
|
pRT->pTexture = (GTextureD3DxImpl*) prtt; // will be properly initialized later
|
||
|
TempRenderTargets.PushBack(*pRT);
|
||
|
prtt->Release();
|
||
|
needsinit = true;
|
||
|
}
|
||
|
dostencil:
|
||
|
GDepthBufferD3D9Impl* pDepthStencil = 0;
|
||
|
|
||
|
if (w < pRT->pTexture->TexWidth)
|
||
|
w = pRT->pTexture->TexWidth;
|
||
|
if (h < pRT->pTexture->TexHeight)
|
||
|
h = pRT->pTexture->TexHeight;
|
||
|
|
||
|
GASSERT(!pRT->pStencilTexture);
|
||
|
if (wantStencil && (pRT->pStencilTexture.GetPtr() == 0 || pRT->pStencilTexture->GetRefCount() > 1))
|
||
|
{
|
||
|
for (UInt i = 0; i < TempStencilBuffers.GetSize(); i++)
|
||
|
{
|
||
|
if (TempStencilBuffers[i]->GetRefCount() <= 1 &&
|
||
|
TempStencilBuffers[i]->TexWidth >= SInt(w) &&
|
||
|
TempStencilBuffers[i]->TexHeight >= SInt(h))
|
||
|
{
|
||
|
pDepthStencil = TempStencilBuffers[i];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!pDepthStencil)
|
||
|
{
|
||
|
for (UInt i = 0; i < TempStencilBuffers.GetSize(); i++)
|
||
|
if (TempStencilBuffers[i]->GetRefCount() <= 1)
|
||
|
{
|
||
|
pDepthStencil = TempStencilBuffers[i];
|
||
|
pDepthStencil->InitDynamicTexture(w, h, GImage::Image_DepthStencil, 0, GTexture::Usage_RenderTarget);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!pDepthStencil)
|
||
|
{
|
||
|
pDepthStencil = (GDepthBufferD3D9Impl*) CreateDepthStencilBuffer();
|
||
|
pDepthStencil->InitDynamicTexture(w, h, GImage::Image_DepthStencil, 0, GTexture::Usage_RenderTarget);
|
||
|
TempStencilBuffers.PushBack(*pDepthStencil);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!needsinit)
|
||
|
{
|
||
|
if (pRT->pStencilSurface)
|
||
|
pRT->pStencilSurface->Release();
|
||
|
pRT->pStencilTexture = pDepthStencil;
|
||
|
pRT->pStencilSurface = pDepthStencil->pDepthStencil;
|
||
|
pRT->pStencilSurface->AddRef();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (needsinit)
|
||
|
{
|
||
|
if (w != pRT->pTexture->TexWidth || h != pRT->pTexture->TexHeight)
|
||
|
pRT->pTexture->InitDynamicTexture(w, h, GImage::Image_ARGB_8888, 0, GTexture::Usage_RenderTarget);
|
||
|
|
||
|
// should use handlers instead
|
||
|
pRT->InitRenderTarget(pRT->pTexture, pDepthStencil, pDepthStencil);
|
||
|
}
|
||
|
|
||
|
pRT->TargetWidth = inw;
|
||
|
pRT->TargetHeight = inh;
|
||
|
PushRenderTarget(frameRect, pRT);
|
||
|
return pRT->pTexture;
|
||
|
}
|
||
|
|
||
|
void ReleaseTempRenderTargets(UInt keepArea)
|
||
|
{
|
||
|
GArray<GPtr<GRenderTargetD3D9Impl> > NewTempRenderTargets;
|
||
|
GArray<GPtr<GDepthBufferD3D9Impl> > NewTempStencilBuffers;
|
||
|
UInt stencilArea = keepArea;
|
||
|
|
||
|
for (UInt i = 0; i < TempRenderTargets.GetSize(); i++)
|
||
|
if (TempRenderTargets[i]->pTexture->GetRefCount() > 1 ||
|
||
|
UInt(TempRenderTargets[i]->pTexture->TexWidth * TempRenderTargets[i]->pTexture->TexHeight) <= keepArea)
|
||
|
{
|
||
|
NewTempRenderTargets.PushBack(TempRenderTargets[i]);
|
||
|
keepArea -= TempRenderTargets[i]->pTexture->TexWidth * TempRenderTargets[i]->pTexture->TexHeight;
|
||
|
}
|
||
|
|
||
|
TempRenderTargets.Clear();
|
||
|
TempRenderTargets.Append(NewTempRenderTargets.GetDataPtr(), NewTempRenderTargets.GetSize());
|
||
|
|
||
|
for (UInt i = 0; i < TempStencilBuffers.GetSize(); i++)
|
||
|
if (TempStencilBuffers[i]->GetRefCount() > 1 ||
|
||
|
UInt(TempStencilBuffers[i]->TexWidth * TempStencilBuffers[i]->TexHeight) <= stencilArea)
|
||
|
{
|
||
|
NewTempStencilBuffers.PushBack(TempStencilBuffers[i]);
|
||
|
stencilArea -= TempStencilBuffers[i]->TexWidth * TempStencilBuffers[i]->TexHeight;
|
||
|
}
|
||
|
|
||
|
TempStencilBuffers.Clear();
|
||
|
TempStencilBuffers.Append(NewTempStencilBuffers.GetDataPtr(), NewTempStencilBuffers.GetSize());
|
||
|
}
|
||
|
|
||
|
GRenderTargetD3D9Impl* CreateRenderTarget()
|
||
|
{
|
||
|
return new GRenderTargetD3D9Impl(this);
|
||
|
}
|
||
|
|
||
|
void SetDisplayRenderTarget(GRenderTarget *renderTarget, bool bSetState)
|
||
|
{
|
||
|
GASSERT(RenderTargetStack.GetSize() == 0);
|
||
|
pCurRenderTarget = (GRenderTargetD3D9Impl*)renderTarget;
|
||
|
if (bSetState && pDevice && pCurRenderTarget)
|
||
|
{
|
||
|
pDevice->SetRenderTarget(0, pCurRenderTarget->pRenderSurface);
|
||
|
pDevice->SetDepthStencilSurface(pCurRenderTarget->pStencilSurface);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FilterShader* GetBlurShader(const BlurFilterParams& params, bool LowEnd)
|
||
|
{
|
||
|
FilterShader** pfs = FilterShaders.Get(params);
|
||
|
if (pfs)
|
||
|
return *pfs;
|
||
|
|
||
|
GStringBuffer fsrc;
|
||
|
if (params.Mode & (Filter_Shadow|Filter_Blur))
|
||
|
{
|
||
|
Float SizeX = UInt(params.BlurX-1) * 0.5f;
|
||
|
Float SizeY = UInt(params.BlurY-1) * 0.5f;
|
||
|
UInt np = UInt((SizeX*2+1)*(SizeY*2+1));
|
||
|
|
||
|
UInt MaxTCs = 8;
|
||
|
UInt BaseTCs = 0;
|
||
|
if (params.Mode & Filter_Shadow)
|
||
|
BaseTCs++;
|
||
|
UInt BoxTCs = MaxTCs - BaseTCs;
|
||
|
if ((params.Mode & (Filter_Highlight|Filter_Shadow)) == (Filter_Highlight|Filter_Shadow))
|
||
|
{
|
||
|
BoxTCs >>= 1;
|
||
|
MaxTCs = BoxTCs*2 + BaseTCs;
|
||
|
}
|
||
|
if (BoxTCs > np)
|
||
|
{
|
||
|
BoxTCs = np;
|
||
|
MaxTCs = BoxTCs * (((params.Mode & (Filter_Highlight|Filter_Shadow)) == (Filter_Highlight|Filter_Shadow)) ? 2 : 1) + BaseTCs;
|
||
|
}
|
||
|
|
||
|
if (LowEnd && !FilterVShaders[MaxTCs].pVShader)
|
||
|
{
|
||
|
D3DVERTEXELEMENT9 VDecl[18];
|
||
|
memset(VDecl, 0, sizeof(VDecl));
|
||
|
VDecl[0].Type = D3DDECLTYPE_FLOAT2;
|
||
|
VDecl[0].Method = D3DDECLMETHOD_DEFAULT;
|
||
|
VDecl[0].Usage = D3DDECLUSAGE_POSITION;
|
||
|
|
||
|
GStringBuffer vsrc;
|
||
|
vsrc.AppendString(
|
||
|
"uniform float4x4 mvp : register(c0);\n"
|
||
|
"void main(float4 pos : POSITION,\n");
|
||
|
|
||
|
for (BYTE i = 0; i < MaxTCs; i++)
|
||
|
{
|
||
|
G_SPrintF(vsrc, " float2 intc%d : TEXCOORD%d,\n", i,i);
|
||
|
G_SPrintF(vsrc, " out float2 tc%d : TEXCOORD%d,\n", i,i);
|
||
|
|
||
|
VDecl[i+1].Offset = 8 + i*8;
|
||
|
VDecl[i+1].Type = D3DDECLTYPE_FLOAT2;
|
||
|
VDecl[i+1].Method = D3DDECLMETHOD_DEFAULT;
|
||
|
VDecl[i+1].Usage = D3DDECLUSAGE_TEXCOORD;
|
||
|
VDecl[i+1].UsageIndex = i;
|
||
|
}
|
||
|
VDecl[MaxTCs+1].Stream = 255;
|
||
|
VDecl[MaxTCs+1].Type = D3DDECLTYPE_UNUSED;
|
||
|
|
||
|
vsrc.AppendString(
|
||
|
" out float4 opos : POSITION)\n{\n"
|
||
|
" opos = mul(pos, mvp);\n");
|
||
|
for (UInt i = 0; i < MaxTCs; i++)
|
||
|
G_SPrintF(vsrc, " tc%d = intc%d;\n", i, i);
|
||
|
|
||
|
vsrc.AppendString("\n}");
|
||
|
if (!CreateVertexShader(&FilterVShaders[MaxTCs].pVShader, vsrc.ToCStr()))
|
||
|
return 0;
|
||
|
if (!CreateVertexDeclaration(&FilterVShaders[MaxTCs].pVDecl, VDecl))
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
fsrc.AppendString(
|
||
|
"sampler tex : register(s0);\n"
|
||
|
"float4 cxadd : register(c0);\n"
|
||
|
"float4 cxmul : register(c1);\n"
|
||
|
"float4 texscale : register(c2);\n");
|
||
|
|
||
|
if (params.Mode & Filter_Shadow)
|
||
|
{
|
||
|
fsrc.AppendString(
|
||
|
"float4 offset : register(c3);\n"
|
||
|
"float4 scolor : register(c4);\n"
|
||
|
"float4 srctexscale : register(c5);\n"
|
||
|
"sampler srctex : register(s1);\n");
|
||
|
|
||
|
if (params.Mode & Filter_Highlight)
|
||
|
fsrc.AppendString("float4 scolor2 : register(c6);\n");
|
||
|
}
|
||
|
|
||
|
if (!LowEnd)
|
||
|
G_SPrintF(fsrc, "static const float2 fsize = float2(%f,%f);\n", SizeX, SizeY);
|
||
|
|
||
|
fsrc.AppendString("void main(\n");
|
||
|
if (LowEnd)
|
||
|
{
|
||
|
for (UInt i = 0; i < MaxTCs; i++)
|
||
|
G_SPrintF(fsrc, "float2 tc%d : TEXCOORD%d,\n", i,i);
|
||
|
}
|
||
|
else
|
||
|
fsrc.AppendString("float2 tc : TEXCOORD,\n");
|
||
|
|
||
|
fsrc.AppendString("out float4 ocolor : COLOR)\n{\n");
|
||
|
|
||
|
if (LowEnd)
|
||
|
{
|
||
|
fsrc.AppendString(" float4 color = 0;\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fsrc.AppendString(
|
||
|
" float4 color = 0;\n"
|
||
|
" float2 i = float2(0,0);\n"
|
||
|
" for (i.x = -fsize.x; i.x <= fsize.x; i.x++)\n"
|
||
|
" for (i.y = -fsize.y; i.y <= fsize.y; i.y++)\n");
|
||
|
}
|
||
|
|
||
|
if (params.Mode & Filter_Shadow)
|
||
|
{
|
||
|
const char *color;
|
||
|
if (params.Mode & Filter_Highlight)
|
||
|
{
|
||
|
if (LowEnd)
|
||
|
{
|
||
|
for (UInt i = 0; i < BoxTCs; i++)
|
||
|
{
|
||
|
G_SPrintF(fsrc, " color.a += tex2D(tex, tc%d).a;\n", i*2);
|
||
|
G_SPrintF(fsrc, " color.r += tex2D(tex, tc%d).a;\n", i*2+1);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
fsrc.AppendString(" {\n"
|
||
|
" color.a += tex2D(tex, tc + (offset.xy + i) * texscale.xy).a;\n"
|
||
|
" color.r += tex2D(tex, tc - (offset.xy + i) * texscale.xy).a;\n }\n");
|
||
|
color = "(scolor * color.a + scolor2 * color.r)";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (LowEnd)
|
||
|
{
|
||
|
for (UInt i = 0; i < BoxTCs; i++)
|
||
|
G_SPrintF(fsrc, " color += tex2D(tex, tc%d);\n", i);
|
||
|
}
|
||
|
else
|
||
|
fsrc.AppendString(" color += tex2D(tex, tc + (offset.xy + i) * texscale.xy);\n");
|
||
|
color = "(scolor * color.a)";
|
||
|
}
|
||
|
|
||
|
G_SPrintF(fsrc, " color *= %f;\n", 1.0f/((SizeX*2+1)*(SizeY*2+1)));
|
||
|
|
||
|
if (params.Mode & Filter_HideObject)
|
||
|
fsrc.AppendString(" ocolor = (scolor * color.a);}\n");
|
||
|
else
|
||
|
{
|
||
|
if (LowEnd)
|
||
|
G_SPrintF(fsrc, " float4 base = tex2D(srctex, tc%d);\n", MaxTCs-1);
|
||
|
else
|
||
|
fsrc.AppendString(" float4 base = tex2D(srctex, tc * srctexscale);\n");
|
||
|
|
||
|
if (params.Mode & Filter_Inner)
|
||
|
{
|
||
|
if (params.Mode & Filter_Highlight)
|
||
|
{
|
||
|
fsrc.AppendString(" color.ar = saturate((1 - color.ar) - (1 - color.ra) * 0.5f);\n");
|
||
|
fsrc.AppendString(" color = (scolor * (color.a) + scolor2 * (color.r)\n"
|
||
|
" + base * (1 - color.a - color.r)) * base.a;\n");
|
||
|
}
|
||
|
else if (params.Mode & Filter_Knockout)
|
||
|
{
|
||
|
fsrc.AppendString(" color = scolor * (1-color.a) * base.a;\n");
|
||
|
}
|
||
|
else
|
||
|
fsrc.AppendString(" color = lerp(scolor, base, color.a) * base.a;\n");
|
||
|
|
||
|
fsrc.AppendString(" ocolor = color * cxmul + cxadd * color.a;\n}");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
G_SPrintF (fsrc, " color = %s * (1-base.a) + base;\n", color);
|
||
|
|
||
|
if (params.Mode & Filter_Knockout)
|
||
|
{
|
||
|
fsrc.AppendString(
|
||
|
" color *= (1 - base.a);\n"
|
||
|
" ocolor = color * cxmul + cxadd * color.a;\n}");
|
||
|
}
|
||
|
else
|
||
|
fsrc.AppendString(" ocolor = color * cxmul + cxadd * color.a;\n}");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (LowEnd)
|
||
|
{
|
||
|
for (UInt i = 0; i < BoxTCs; i++)
|
||
|
G_SPrintF(fsrc, " color += tex2D(tex, tc%d);\n", i);
|
||
|
}
|
||
|
else
|
||
|
fsrc.AppendString(" color += tex2D(tex, tc + i * texscale.xy);\n");
|
||
|
|
||
|
G_SPrintF(fsrc, " color = color * %f;\n", 1.0f/((SizeX*2+1)*(SizeY*2+1)));
|
||
|
fsrc.AppendString( " ocolor = color * cxmul + cxadd * color.a;\n}\n");
|
||
|
}
|
||
|
|
||
|
FilterShader* pfs = new FilterShader;
|
||
|
|
||
|
pfs->Samples = np;
|
||
|
pfs->BoxTCs = BoxTCs;
|
||
|
pfs->BaseTCs = BaseTCs;
|
||
|
pfs->MaxTCs = LowEnd ? MaxTCs : 0;
|
||
|
pfs->pVShader = &FilterVShaders[MaxTCs];
|
||
|
if (!CreatePixelShader(&pfs->pShader, fsrc.ToCStr()))
|
||
|
return 0;
|
||
|
|
||
|
FilterShaders.Add(params, pfs);
|
||
|
return pfs;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
UInt CheckFilterSupport(const BlurFilterParams& params)
|
||
|
{
|
||
|
if (!UsePixelShaders)
|
||
|
return FilterSupport_None;
|
||
|
|
||
|
UInt flags = FilterSupport_Ok;
|
||
|
if (params.Passes > 1 || (params.BlurX * params.BlurY > MaxTextureOps))
|
||
|
flags |= FilterSupport_Multipass;
|
||
|
|
||
|
return flags;
|
||
|
}
|
||
|
|
||
|
static inline void SetUniform(Float* uniforms, FragShaderType2 shader, FragShader2Uniform var, const Float *val, UInt size)
|
||
|
{
|
||
|
memcpy(uniforms + 4*FShaderUniforms[shader][var], val, size*sizeof(Float));
|
||
|
}
|
||
|
|
||
|
static inline void SetUniform(Float* uniforms, FragShaderType2 shader, FragShader2Uniform var, Float x, Float y=0, Float z=0, Float w=1)
|
||
|
{
|
||
|
uniforms[4*FShaderUniforms[shader][var] + 0] = x;
|
||
|
uniforms[4*FShaderUniforms[shader][var] + 1] = y;
|
||
|
uniforms[4*FShaderUniforms[shader][var] + 2] = z;
|
||
|
uniforms[4*FShaderUniforms[shader][var] + 3] = w;
|
||
|
}
|
||
|
|
||
|
void DrawBlurRect(GTexture* psrcin, const GRectF& insrcrect, const GRectF& indestrect, const BlurFilterParams& params, bool islast)
|
||
|
{
|
||
|
GUNUSED(islast);
|
||
|
GPtr<GTextureD3DxImpl> psrcinRef = (GTextureD3DxImpl*)psrcin;
|
||
|
GPtr<GTextureD3DxImpl> psrc = (GTextureD3DxImpl*)psrcin;
|
||
|
GRectF srcrect, destrect(-1,-1,1,1);
|
||
|
|
||
|
UInt n = params.Passes;
|
||
|
|
||
|
bool LowEnd = (FiltersSupported < 3 && (2 + params.BlurX > MaxTextureOps || 2 + params.BlurY > MaxTextureOps));
|
||
|
bool Prims = 0;
|
||
|
|
||
|
FilterShader * passes[3];
|
||
|
BlurFilterParams pass[3];
|
||
|
FragShaderType2 passis[3];
|
||
|
|
||
|
pass[0] = params;
|
||
|
pass[1] = params;
|
||
|
pass[2] = params;
|
||
|
|
||
|
if (FiltersSupported >= 3)
|
||
|
{
|
||
|
bool mul = (BlendMode == Blend_Multiply || BlendMode == Blend_Darken);
|
||
|
passis[0] = passis[1] = FS2_FBox2Blur;
|
||
|
passis[2] = mul ? FS2_FBox2BlurMul : FS2_FBox2Blur;
|
||
|
|
||
|
if (params.Mode & Filter_Shadow)
|
||
|
{
|
||
|
if (params.Mode & Filter_HideObject)
|
||
|
{
|
||
|
passis[2] = FS2_FBox2Shadowonly;
|
||
|
|
||
|
if (params.Mode & Filter_Highlight)
|
||
|
passis[2] = (FragShaderType2) (passis[2] + FS2_shadows_Highlight);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (params.Mode & Filter_Inner)
|
||
|
passis[2] = FS2_FBox2InnerShadow;
|
||
|
else
|
||
|
passis[2] = FS2_FBox2Shadow;
|
||
|
|
||
|
if (params.Mode & Filter_Knockout)
|
||
|
passis[2] = (FragShaderType2) (passis[2] + FS2_shadows_Knockout);
|
||
|
|
||
|
if (params.Mode & Filter_Highlight)
|
||
|
passis[2] = (FragShaderType2) (passis[2] + FS2_shadows_Highlight);
|
||
|
}
|
||
|
|
||
|
if (mul)
|
||
|
passis[2] = (FragShaderType2) (passis[2] + FS2_shadows_Mul);
|
||
|
}
|
||
|
|
||
|
if (params.BlurX * params.BlurY > 32)
|
||
|
{
|
||
|
n *= 2;
|
||
|
pass[0].BlurY = 1;
|
||
|
pass[1].BlurX = 1;
|
||
|
pass[2].BlurX = 1;
|
||
|
|
||
|
passis[0] = passis[1] = FS2_FBox1Blur;
|
||
|
if (passis[2] == FS2_FBox2Blur)
|
||
|
passis[2] = FS2_FBox1Blur;
|
||
|
else if (passis[2] == FS2_FBox2BlurMul)
|
||
|
passis[2] = FS2_FBox1BlurMul;
|
||
|
}
|
||
|
|
||
|
for (UInt i = 0; i < 3; i++)
|
||
|
if (!StaticFilterShaders[passis[i]])
|
||
|
return;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (params.BlurX * params.BlurY > MaxTextureOps)
|
||
|
{
|
||
|
n *= 2;
|
||
|
pass[0].Mode &= ~Filter_Shadow;
|
||
|
pass[0].Mode |= Filter_Blur;
|
||
|
pass[1].Mode &= ~Filter_Shadow;
|
||
|
pass[1].Mode |= Filter_Blur;
|
||
|
pass[0].BlurY = 1;
|
||
|
pass[1].BlurX = 1;
|
||
|
pass[2].BlurX = 1;
|
||
|
passes[0] = GetBlurShader(pass[0], LowEnd);
|
||
|
passes[1] = GetBlurShader(pass[1], LowEnd);
|
||
|
passes[2] = GetBlurShader(pass[2], LowEnd);
|
||
|
}
|
||
|
else if (params.Mode & Filter_Shadow)
|
||
|
{
|
||
|
pass[0].Mode &= ~Filter_Shadow;
|
||
|
pass[0].Mode |= Filter_Blur;
|
||
|
pass[1].Mode &= ~Filter_Shadow;
|
||
|
pass[1].Mode |= Filter_Blur;
|
||
|
|
||
|
passes[0] = passes[1] = GetBlurShader(pass[0], LowEnd);
|
||
|
passes[2] = GetBlurShader(params, LowEnd);
|
||
|
}
|
||
|
else
|
||
|
passes[0] = passes[1] = passes[2] = GetBlurShader(params, LowEnd);
|
||
|
|
||
|
if (!passes[0] || !passes[1] || !passes[2])
|
||
|
return;
|
||
|
|
||
|
LowEnd = (passes[0]->MaxTCs > 0);
|
||
|
|
||
|
if (LowEnd && (passes[2]->BoxTCs < pass[2].BlurX*pass[2].BlurY || BlendMode > Blend_Normal))
|
||
|
{
|
||
|
n++;
|
||
|
Prims = 1;
|
||
|
pass[2].BlurX = pass[2].BlurY = 1;
|
||
|
passes[2] = GetBlurShader(pass[2], LowEnd);
|
||
|
}
|
||
|
if (LowEnd)
|
||
|
pass[0].Offset.x = pass[0].Offset.y = pass[1].Offset.x = pass[1].Offset.y = 0;
|
||
|
}
|
||
|
|
||
|
UInt bufWidth = (UInt)ceilf(insrcrect.Width());
|
||
|
UInt bufHeight = (UInt)ceilf(insrcrect.Height());
|
||
|
UInt last = n-1;
|
||
|
|
||
|
if (LowEnd)
|
||
|
{
|
||
|
VDeclIndex = VD_None;
|
||
|
VShaderIndex = VS_None;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetVertexDecl(VD_Glyph);
|
||
|
SetVertexShader(VS_Glyph);
|
||
|
}
|
||
|
PShaderIndex = (PixelShaderType)~0;
|
||
|
|
||
|
for (UInt i = 0; i < n; i++)
|
||
|
{
|
||
|
UInt passi = (i == last) ? 2 : (i&1);
|
||
|
const BlurFilterParams& pparams = pass[passi];
|
||
|
const FilterShader *pShader = passes[passi];
|
||
|
|
||
|
if (FiltersSupported >= 3)
|
||
|
pDevice->SetPixelShader(StaticFilterShaders[passis[passi]]);
|
||
|
else
|
||
|
pDevice->SetPixelShader(pShader->pShader);
|
||
|
|
||
|
GTextureD3DxImpl* pnextsrc;
|
||
|
if (i != n - 1)
|
||
|
{
|
||
|
pnextsrc = PushTempRenderTarget(GRectF(-1,-1,1,1), bufWidth, bufHeight, 0);
|
||
|
ApplyMatrix(GMatrix2D::Identity);
|
||
|
destrect = GRectF(-1,-1,1,1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pnextsrc = 0;
|
||
|
ApplyMatrix(CurrentMatrix);
|
||
|
destrect = indestrect;
|
||
|
}
|
||
|
|
||
|
srcrect = GRectF(insrcrect.Left * 1.0f/psrc->TexWidth, insrcrect.Top * 1.0f/psrc->TexHeight,
|
||
|
insrcrect.Right * 1.0f/psrc->TexWidth, insrcrect.Bottom * 1.0f/psrc->TexHeight);
|
||
|
|
||
|
if (Prims && i < last)
|
||
|
{
|
||
|
pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||
|
pDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
||
|
pDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
|
||
|
pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
|
||
|
pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
|
||
|
}
|
||
|
else if (i < last)
|
||
|
{
|
||
|
pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||
|
pDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
||
|
pDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
|
||
|
pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
|
||
|
pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ApplyBlendMode(BlendMode, true, true);
|
||
|
pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||
|
}
|
||
|
|
||
|
const float mult = 1.0f / 255.0f;
|
||
|
|
||
|
if (i == n - 1)
|
||
|
{
|
||
|
float cxformData[4 * 2] =
|
||
|
{
|
||
|
params.cxform.M_[0][1] * mult * params.cxform.M_[3][0],
|
||
|
params.cxform.M_[1][1] * mult * params.cxform.M_[3][0],
|
||
|
params.cxform.M_[2][1] * mult * params.cxform.M_[3][0],
|
||
|
params.cxform.M_[3][1] * mult,
|
||
|
|
||
|
params.cxform.M_[0][0] * params.cxform.M_[3][0],
|
||
|
params.cxform.M_[1][0] * params.cxform.M_[3][0],
|
||
|
params.cxform.M_[2][0] * params.cxform.M_[3][0],
|
||
|
params.cxform.M_[3][0]
|
||
|
};
|
||
|
pDevice->SetPixelShaderConstantF(0, cxformData, 2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const float cxformData[] = {0,0,0,0,1,1,1,1};
|
||
|
pDevice->SetPixelShaderConstantF(0, cxformData, 2);
|
||
|
}
|
||
|
|
||
|
if (FiltersSupported >= 3)
|
||
|
{
|
||
|
Float uniforms[32];
|
||
|
|
||
|
Float SizeX = UInt(pparams.BlurX-1) * 0.5f;
|
||
|
Float SizeY = UInt(pparams.BlurY-1) * 0.5f;
|
||
|
|
||
|
if (passis[passi] == FS2_FBox1Blur || passis[passi] == FS2_FBox1BlurMul)
|
||
|
{
|
||
|
const float fsize[] = {pparams.BlurX > 1 ? SizeX : SizeY, 0, 0, 1.0f/((SizeX*2+1)*(SizeY*2+1))};
|
||
|
SetUniform(uniforms, passis[passi], FSU_fsize, fsize, 4);
|
||
|
|
||
|
SetUniform(uniforms, passis[passi], FSU_texscale, pparams.BlurX > 1 ? 1.0f/psrc->TexWidth : 0, pparams.BlurY > 1 ? 1.0f/psrc->TexHeight : 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const float fsize[] = {SizeX, SizeY, 0, 1.0f/((SizeX*2+1)*(SizeY*2+1))};
|
||
|
SetUniform(uniforms, passis[passi], FSU_fsize, fsize, 4);
|
||
|
SetUniform(uniforms, passis[passi], FSU_texscale, 1.0f/psrc->TexWidth, 1.0f/psrc->TexHeight);
|
||
|
}
|
||
|
|
||
|
if (FShaderUniforms[passis[passi]][FSU_offset] >= 0)
|
||
|
{
|
||
|
SetUniform(uniforms, passis[passi], FSU_offset, -params.Offset.x, -params.Offset.y);
|
||
|
SetUniform(uniforms, passis[passi], FSU_srctexscale, psrc->TexWidth/Float(psrcinRef->TexWidth), psrc->TexHeight/Float(psrcinRef->TexHeight));
|
||
|
}
|
||
|
|
||
|
if (FShaderUniforms[passis[passi]][FSU_scolor] >= 0)
|
||
|
{
|
||
|
SetUniform(uniforms, passis[passi], FSU_scolor,
|
||
|
params.Color.GetRed() * mult, params.Color.GetGreen() * mult, params.Color.GetBlue() * mult, params.Color.GetAlpha() * mult);
|
||
|
|
||
|
if (FShaderUniforms[passis[passi]][FSU_scolor2] >= 0)
|
||
|
SetUniform(uniforms, passis[passi], FSU_scolor2,
|
||
|
params.Color2.GetRed() * mult, params.Color2.GetGreen() * mult, params.Color2.GetBlue() * mult, params.Color2.GetAlpha() * mult);
|
||
|
}
|
||
|
|
||
|
pDevice->SetPixelShaderConstantF(2, uniforms+8, 6);
|
||
|
psrc->Bind(FShaderUniforms[passis[passi]][FSU_tex], Wrap_Clamp, Sample_Linear, false);
|
||
|
if (FShaderUniforms[passis[passi]][FSU_srctex] >= 0)
|
||
|
((GTextureD3DxImpl*)psrcin)->Bind(FShaderUniforms[passis[passi]][FSU_srctex], Wrap_Clamp, Sample_Linear, false);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const float texconsts[] =
|
||
|
{
|
||
|
1.0f/psrc->TexWidth, 1.0f/psrc->TexHeight, 0,1,
|
||
|
-params.Offset.x, -params.Offset.y, 0,1,
|
||
|
params.Color.GetRed() * mult, params.Color.GetGreen() * mult, params.Color.GetBlue() * mult, params.Color.GetAlpha() * mult,
|
||
|
psrc->TexWidth/Float(psrcinRef->TexWidth), psrc->TexHeight/Float(psrcinRef->TexHeight), 0,1,
|
||
|
params.Color2.GetRed() * mult, params.Color2.GetGreen() * mult, params.Color2.GetBlue() * mult, params.Color2.GetAlpha() * mult
|
||
|
};
|
||
|
|
||
|
pDevice->SetPixelShaderConstantF(2, texconsts, 5);
|
||
|
psrc->Bind(0, Wrap_Clamp, Sample_Linear, 0);
|
||
|
psrcinRef->Bind(1, Wrap_Clamp, Sample_Linear, 0);
|
||
|
}
|
||
|
|
||
|
if (LowEnd)
|
||
|
{
|
||
|
Float SizeX = UInt(pparams.BlurX-1) * 0.5f;
|
||
|
Float SizeY = UInt(pparams.BlurY-1) * 0.5f;
|
||
|
UInt np = UInt((SizeX*2+1)*(SizeY*2+1));
|
||
|
UInt count = (np + pShader->BoxTCs - 1) / pShader->BoxTCs;
|
||
|
//UInt ntexcoords = pShader->BoxTCs + (pparams.Mode & Filter_Shadow ? 1 : 0);
|
||
|
|
||
|
pDevice->SetVertexDeclaration(pShader->pVShader->pVDecl);
|
||
|
pDevice->SetVertexShader(pShader->pVShader->pVShader);
|
||
|
|
||
|
const Float vertices[] = {destrect.Left, destrect.Top, srcrect.Left, srcrect.Top,
|
||
|
destrect.Right, destrect.Top, srcrect.Right, srcrect.Top,
|
||
|
destrect.Left, destrect.Bottom, srcrect.Left, srcrect.Bottom,
|
||
|
destrect.Left, destrect.Bottom, srcrect.Left, srcrect.Bottom,
|
||
|
destrect.Right, destrect.Top, srcrect.Right, srcrect.Top,
|
||
|
destrect.Right, destrect.Bottom, srcrect.Right, srcrect.Bottom};
|
||
|
|
||
|
Float* pbuffer = (Float*)
|
||
|
VertexStream.LockVertexBuffer(count*6, (pShader->MaxTCs + 1) * 2*sizeof(Float));
|
||
|
UInt vi = 0;
|
||
|
|
||
|
Float x = -SizeX, y = -SizeY;
|
||
|
for (UInt p = 0; p < count; p++)
|
||
|
{
|
||
|
Float xv[16], yv[16];
|
||
|
for (UInt tc = 0; tc < pShader->BoxTCs; tc++)
|
||
|
if (y <= SizeY)
|
||
|
{
|
||
|
xv[tc] = (x - pparams.Offset.x) * 1.0f/psrc->TexWidth;
|
||
|
yv[tc] = (y - pparams.Offset.y) * 1.0f/psrc->TexHeight;
|
||
|
x++;
|
||
|
if (x > SizeX)
|
||
|
{
|
||
|
x = -SizeX;
|
||
|
y++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
xv[tc] = yv[tc] = 1e10;
|
||
|
|
||
|
for (UInt j = 0; j < 6; j++)
|
||
|
{
|
||
|
pbuffer[vi++] = vertices[j*4];
|
||
|
pbuffer[vi++] = vertices[j*4+1];
|
||
|
for (UInt tc = 0; tc < pShader->BoxTCs; tc++)
|
||
|
{
|
||
|
pbuffer[vi++] = xv[tc] < 1e9 ? (vertices[j*4+2] + xv[tc]) : 0;
|
||
|
pbuffer[vi++] = yv[tc] < 1e9 ? (vertices[j*4+3] + yv[tc]) : 0;
|
||
|
if ((pparams.Mode & (Filter_Highlight|Filter_Shadow)) == (Filter_Highlight|Filter_Shadow))
|
||
|
{
|
||
|
pbuffer[vi++] = xv[tc] < 1e9 ? (vertices[j*4+2] - xv[tc]) : 0;
|
||
|
pbuffer[vi++] = yv[tc] < 1e9 ? (vertices[j*4+3] - yv[tc]) : 0;
|
||
|
}
|
||
|
}
|
||
|
if (pparams.Mode & Filter_Shadow)
|
||
|
{
|
||
|
pbuffer[vi++] = vertices[j*4+2] * psrc->TexWidth/Float(psrcinRef->TexWidth);
|
||
|
pbuffer[vi++] = vertices[j*4+3] * psrc->TexHeight/Float(psrcinRef->TexHeight);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
VertexStream.UnlockVertexBuffer();
|
||
|
pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, VertexStream.GetStartIndex(), count*2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GColor w;
|
||
|
GGlyphVertex strip[4] =
|
||
|
{
|
||
|
{ destrect.Left, destrect.Top, srcrect.Left, srcrect.Top, w},
|
||
|
{ destrect.Right, destrect.Top, srcrect.Right, srcrect.Top, w},
|
||
|
{ destrect.Left, destrect.Bottom, srcrect.Left, srcrect.Bottom, w},
|
||
|
{ destrect.Right, destrect.Bottom, srcrect.Right, srcrect.Bottom, w}
|
||
|
};
|
||
|
|
||
|
// Copy vertices to dynamic buffer and draw.
|
||
|
void *pbuffer = VertexStream.LockVertexBuffer(4, sizeof(GGlyphVertex));
|
||
|
if (pbuffer)
|
||
|
{
|
||
|
memcpy(pbuffer, &strip[0], 4 * sizeof(GGlyphVertex));
|
||
|
VertexStream.UnlockVertexBuffer();
|
||
|
pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, VertexStream.GetStartIndex(), 2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (i != n - 1)
|
||
|
{
|
||
|
PopRenderTarget();
|
||
|
psrc = pnextsrc;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pDevice->SetTexture(0, NULL);
|
||
|
pDevice->SetTexture(1, NULL);
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
FilterCnt.AddCount(n);
|
||
|
RenderStats.Filters += n;
|
||
|
}
|
||
|
|
||
|
void DrawColorMatrixRect(GTexture* psrcin, const GRectF& insrcrect, const GRectF& destrect, const Float *matrix, bool islast)
|
||
|
{
|
||
|
GUNUSED(islast);
|
||
|
GTextureD3DxImpl* psrc = (GTextureD3DxImpl*) psrcin;
|
||
|
if ((BlendMode == Blend_Multiply) ||
|
||
|
(BlendMode == Blend_Darken) )
|
||
|
SetPixelShader(PS_CmatrixTextureMultiply);
|
||
|
else
|
||
|
SetPixelShader(PS_CmatrixTexture);
|
||
|
SetVertexDecl(VD_Glyph);
|
||
|
SetVertexShader(VS_Glyph);
|
||
|
|
||
|
GRectF srcrect = GRectF(insrcrect.Left * 1.0f/psrc->TexWidth, insrcrect.Top * 1.0f/psrc->TexHeight,
|
||
|
insrcrect.Right * 1.0f/psrc->TexWidth, insrcrect.Bottom * 1.0f/psrc->TexHeight);
|
||
|
|
||
|
ApplyMatrix(CurrentMatrix);
|
||
|
psrc->Bind(0, Wrap_Clamp, Sample_Linear, 0);
|
||
|
|
||
|
pDevice->SetPixelShaderConstant(0, matrix, 4);
|
||
|
pDevice->SetPixelShaderConstant(4, matrix+16, 1);
|
||
|
|
||
|
ApplyBlendMode(BlendMode, false, true);
|
||
|
|
||
|
GColor w(0xffffffff);
|
||
|
GGlyphVertex strip[4] =
|
||
|
{
|
||
|
{ destrect.Left, destrect.Top, srcrect.Left, srcrect.Top, w},
|
||
|
{ destrect.Right, destrect.Top, srcrect.Right, srcrect.Top, w},
|
||
|
{ destrect.Left, destrect.Bottom, srcrect.Left, srcrect.Bottom, w},
|
||
|
{ destrect.Right, destrect.Bottom, srcrect.Right, srcrect.Bottom, w}
|
||
|
};
|
||
|
|
||
|
// Copy vertices to dynamic buffer and draw.
|
||
|
void *pbuffer = VertexStream.LockVertexBuffer(4, sizeof(GGlyphVertex));
|
||
|
if (pbuffer)
|
||
|
{
|
||
|
memcpy(pbuffer, &strip[0], 4 * sizeof(GGlyphVertex));
|
||
|
VertexStream.UnlockVertexBuffer();
|
||
|
pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, VertexStream.GetStartIndex(), 2);
|
||
|
}
|
||
|
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
}
|
||
|
|
||
|
// Set up to render a full frame from a movie and fills the
|
||
|
// background. Sets up necessary transforms, to scale the
|
||
|
// movie to fit within the given dimensions. Call
|
||
|
// EndDisplay() when you're done.
|
||
|
//
|
||
|
// The Rectangle (viewport.Left, viewport.Top, viewport.Left +
|
||
|
// viewportWidth, viewport.Top + viewportHeight) defines the
|
||
|
// window coordinates taken up by the movie.
|
||
|
//
|
||
|
// The Rectangle (x0, y0, x1, y1) defines the pixel
|
||
|
// coordinates of the movie that correspond to the viewport
|
||
|
// bounds.
|
||
|
void BeginDisplay(
|
||
|
GColor backgroundColor, const GViewport &vpin,
|
||
|
Float x0, Float x1, Float y0, Float y1)
|
||
|
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererD3Dx::BeginDisplay failed - video mode not set");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
RenderMode = (/*vpin.Flags &*/ GViewport::View_AlphaComposite);
|
||
|
|
||
|
DisplayWidth = fabsf(x1 - x0);
|
||
|
DisplayHeight = fabsf(y1 - y0);
|
||
|
DisplayRect = GRectF(x0,y0,x1,y1);
|
||
|
|
||
|
// Need to get surface size, so that we can clamp viewport
|
||
|
D3DSURFACE_DESC surfaceDesc;
|
||
|
surfaceDesc.Width = vpin.Width;
|
||
|
surfaceDesc.Height= vpin.Height;
|
||
|
{
|
||
|
GPtr<IDirect3DSurfaceX> psurface;
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
pDevice->GetRenderTarget(0, &psurface.GetRawRef());
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
pDevice->GetRenderTarget(&psurface.GetRawRef());
|
||
|
#endif
|
||
|
if (psurface)
|
||
|
psurface->GetDesc(&surfaceDesc);
|
||
|
}
|
||
|
|
||
|
// Matrix to map from SWF Movie (TWIPs) coords to
|
||
|
// viewport coordinates.
|
||
|
float dx = x1 - x0;
|
||
|
float dy = y1 - y0;
|
||
|
if (dx < 1) { dx = 1; }
|
||
|
if (dy < 1) { dy = 1; }
|
||
|
|
||
|
|
||
|
float clipX0 = x0;
|
||
|
float clipX1 = x1;
|
||
|
float clipY0 = y0;
|
||
|
float clipY1 = y1;
|
||
|
|
||
|
// In some cases destination source coordinates can be outside D3D viewport.
|
||
|
// D3D will not allow that; however, it is useful to support.
|
||
|
// So if this happens, clamp the viewport and re-calculate source values.
|
||
|
GViewport viewport(vpin);
|
||
|
int viewportX0_save = viewport.Left;
|
||
|
int viewportY0_save = viewport.Top;
|
||
|
int viewportW_save = viewport.Width;
|
||
|
int viewportH_save = viewport.Height;
|
||
|
|
||
|
if (viewport.Left < 0)
|
||
|
{
|
||
|
clipX0 = x0 + ((-viewport.Left) * dx) / (float) viewport.Width;
|
||
|
if ((-viewport.Left) >= viewport.Width)
|
||
|
viewport.Width = 0;
|
||
|
else
|
||
|
viewport.Width += viewport.Left;
|
||
|
viewport.Left = 0;
|
||
|
}
|
||
|
if (viewportX0_save + viewportW_save > (int) surfaceDesc.Width)
|
||
|
{
|
||
|
clipX1 = x0 + ((surfaceDesc.Width - viewportX0_save) * dx) / (float) viewportW_save;
|
||
|
viewport.Width = surfaceDesc.Width - viewport.Left;
|
||
|
}
|
||
|
|
||
|
if (viewport.Top < 0)
|
||
|
{
|
||
|
clipY0 = y0 + ((-viewport.Top) * dy) / (float) viewport.Height;
|
||
|
if ((-viewport.Top) >= viewport.Height)
|
||
|
viewport.Height = 0;
|
||
|
else
|
||
|
viewport.Height += viewport.Top;
|
||
|
viewport.Top = 0;
|
||
|
}
|
||
|
if (viewportY0_save + viewportH_save > (int) surfaceDesc.Height)
|
||
|
{
|
||
|
clipY1 = y0 + ((surfaceDesc.Height - viewportY0_save) * dy) / (float) viewportH_save;
|
||
|
viewport.Height = surfaceDesc.Height - viewport.Top;
|
||
|
}
|
||
|
dx = clipX1 - clipX0;
|
||
|
dy = clipY1 - clipY0;
|
||
|
|
||
|
|
||
|
// Viewport.
|
||
|
D3DVIEWPORTx vp;
|
||
|
|
||
|
vp.MinZ = 0.0f;
|
||
|
#ifndef GFC_NO_3D
|
||
|
vp.MaxZ = 1.0f;
|
||
|
#endif
|
||
|
if (viewport.Flags & GViewport::View_UseScissorRect)
|
||
|
{
|
||
|
int scissorX0_save = viewport.ScissorLeft;
|
||
|
int scissorY0_save = viewport.ScissorTop;
|
||
|
|
||
|
if (viewport.ScissorLeft < viewport.Left) viewport.ScissorLeft = viewport.Left;
|
||
|
if (viewport.ScissorTop < viewport.Top) viewport.ScissorTop = viewport.Top;
|
||
|
viewport.ScissorWidth -= (viewport.ScissorLeft - scissorX0_save);
|
||
|
viewport.ScissorHeight -= (viewport.ScissorTop - scissorY0_save);
|
||
|
if (viewport.ScissorLeft + viewport.ScissorWidth > viewport.Left + viewport.Width)
|
||
|
viewport.ScissorWidth = viewport.Left + viewport.Width - viewport.ScissorLeft;
|
||
|
if (viewport.ScissorTop + viewport.ScissorHeight > viewport.Top + viewport.Height)
|
||
|
viewport.ScissorHeight = viewport.Top + viewport.Height - viewport.ScissorTop;
|
||
|
|
||
|
vp.X = viewport.ScissorLeft;
|
||
|
vp.Y = viewport.ScissorTop;
|
||
|
vp.Width = viewport.ScissorWidth;
|
||
|
vp.Height = viewport.ScissorHeight;
|
||
|
|
||
|
clipX0 = clipX0 + dx / viewport.Width * (viewport.ScissorLeft - viewport.Left);
|
||
|
clipY0 = clipY0 + dy / viewport.Height * (viewport.ScissorTop - viewport.Top);
|
||
|
dx = dx / viewport.Width * viewport.ScissorWidth;
|
||
|
dy = dy / viewport.Height * viewport.ScissorHeight;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
vp.X = viewport.Left;
|
||
|
vp.Y = viewport.Top;
|
||
|
vp.Width = viewport.Width;
|
||
|
vp.Height = viewport.Height;
|
||
|
}
|
||
|
pDevice->SetViewport(&vp);
|
||
|
|
||
|
ViewportMatrix.SetIdentity();
|
||
|
ViewportMatrix.M_[0][0] = 2.0f / dx;
|
||
|
ViewportMatrix.M_[1][1] = -2.0f / dy;
|
||
|
|
||
|
ViewRect = viewport;
|
||
|
|
||
|
// Adjust by -0.5 pixel to match DirectX pixel coverage rules.
|
||
|
Float xhalfPixelAdjust = (vp.Width > 0) ? (1.0f / (Float) vp.Width) : 0.0f;
|
||
|
Float yhalfPixelAdjust = (vp.Height> 0) ? (1.0f / (Float) vp.Height) : 0.0f;
|
||
|
|
||
|
// MA: it does not seem necessary to subtract viewport.
|
||
|
// Need to work through details of viewport cutting, there still seems to
|
||
|
// be a 1-pixel issue at edges. Could that be due to edge fill rules ?
|
||
|
ViewportMatrix.M_[0][2] = -1.0f - ViewportMatrix.M_[0][0] * (clipX0) - xhalfPixelAdjust;
|
||
|
ViewportMatrix.M_[1][2] = 1.0f - ViewportMatrix.M_[1][1] * (clipY0) + yhalfPixelAdjust;
|
||
|
|
||
|
ViewportMatrix.Prepend(UserMatrix);
|
||
|
|
||
|
// Blending render states.
|
||
|
BlendModeStack.Clear();
|
||
|
BlendModeStack.Reserve(16);
|
||
|
BlendMode = Blend_None;
|
||
|
pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
|
||
|
// Not necessary of not alpha testing:
|
||
|
//pDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
|
||
|
//pDevice->SetRenderState(D3DRS_ALPHAREF, 0x00);
|
||
|
pDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); // Important!
|
||
|
|
||
|
union
|
||
|
{
|
||
|
float fbias;
|
||
|
DWORD d;
|
||
|
} bias;
|
||
|
bias.fbias = -0.5f;
|
||
|
|
||
|
// Must reset both stages since ApplySampleMode modifies both.
|
||
|
SampleMode[0] = Sample_Linear;
|
||
|
SampleMode[1] = Sample_Linear;
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
pDevice->SetRenderState(D3DRS_SCISSORTESTENABLE,FALSE);
|
||
|
|
||
|
pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||
|
pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||
|
pDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
|
||
|
pDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||
|
pDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||
|
pDevice->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
|
||
|
pDevice->SetSamplerState(0, D3DSAMP_MIPMAPLODBIAS, bias.d );
|
||
|
|
||
|
pDevice->SetSamplerState(0, D3DSAMP_ELEMENTINDEX, 0);
|
||
|
pDevice->SetSamplerState(1, D3DSAMP_ELEMENTINDEX, 0);
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
pDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
|
||
|
pDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
|
||
|
pDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);
|
||
|
pDevice->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
|
||
|
pDevice->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
|
||
|
pDevice->SetTextureStageState(1, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);
|
||
|
pDevice->SetTextureStageState(0, D3DTSS_MIPMAPLODBIAS, bias.d );
|
||
|
#endif
|
||
|
|
||
|
// Textures off by default.
|
||
|
pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
||
|
|
||
|
// No ZWRITE by default
|
||
|
pDevice->SetRenderState(D3DRS_ZWRITEENABLE, 0);
|
||
|
pDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||
|
// Turn off D3D lighting, since we are providing our own vertex colors
|
||
|
pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
|
||
|
|
||
|
// Clear more states..
|
||
|
pDevice->SetRenderState(D3DRS_FOGENABLE, FALSE );
|
||
|
pDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
|
||
|
#ifndef GFC_NO_3D
|
||
|
pDevice->SetRenderState(D3DRS_CLIPPING, 0);
|
||
|
#endif
|
||
|
pDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
|
||
|
// pDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
|
||
|
// pDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
|
||
|
|
||
|
pDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN |
|
||
|
D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA);
|
||
|
|
||
|
// Need to clear textures to avoid potential warnings.
|
||
|
pDevice->SetTexture(0, 0);
|
||
|
pDevice->SetTexture(1, 0);
|
||
|
pDevice->SetTexture(2, 0); // Can't set texture
|
||
|
pDevice->SetTexture(3, 0);
|
||
|
// Texture stage clears not necessary, as SetPixelShader does so.
|
||
|
// pDevice->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
||
|
// pDevice->SetTextureStageState(2, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
||
|
// Coord index 0 -> 0, 1 -> 1
|
||
|
pDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
|
||
|
pDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
|
||
|
pDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
|
||
|
pDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
|
||
|
|
||
|
|
||
|
// Turn of back-face culling.
|
||
|
pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||
|
pDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
|
||
|
|
||
|
// Start the scene
|
||
|
if (!(VMCFlags&VMConfig_NoSceneCalls))
|
||
|
pDevice->BeginScene();
|
||
|
|
||
|
// Vertex format.
|
||
|
// Set None so that shader is forced to be set and then set to default: strip.
|
||
|
VDeclIndex = VD_None;
|
||
|
VShaderIndex = VS_None;
|
||
|
PShaderIndex = PS_None;
|
||
|
SetVertexDecl(VD_Strip);
|
||
|
SetVertexShader(VS_Strip);
|
||
|
// Start with solid shader.
|
||
|
SetPixelShader(PS_SolidColor);
|
||
|
|
||
|
// Configure vertex/index buffers.
|
||
|
VertexStream.BeginDisplay();
|
||
|
|
||
|
// Init test for depth-stencil presence.
|
||
|
StencilChecked = 0;
|
||
|
StencilAvailable= 0;
|
||
|
MultiBitStencil = 0;
|
||
|
DepthBufferAvailable = 0;
|
||
|
|
||
|
StencilCounter = 0;
|
||
|
DrawingMask = 0;
|
||
|
StencilEnabled = 0;
|
||
|
|
||
|
// Clear the background, if background color has alpha > 0.
|
||
|
if (backgroundColor.GetAlpha() > 0)
|
||
|
{
|
||
|
// Draw a big quad.
|
||
|
ApplyColor(backgroundColor);
|
||
|
SetMatrix(Matrix::Identity);
|
||
|
#ifndef GFC_NO_3D
|
||
|
SetWorld3D(NULL);
|
||
|
#endif
|
||
|
ApplyMatrix(CurrentMatrix);
|
||
|
|
||
|
pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, (backgroundColor.GetAlpha()== 0xFF) ? FALSE : TRUE);
|
||
|
|
||
|
// The and x/y matrix are scaled by 20 twips already, so it
|
||
|
// should ok to just convert these values into integers.
|
||
|
struct Vertex
|
||
|
{
|
||
|
SInt16 x, y;
|
||
|
};
|
||
|
|
||
|
Vertex strip[4] =
|
||
|
{
|
||
|
{ (SInt16)x0, (SInt16)y0 },
|
||
|
{ (SInt16)x1, (SInt16)y0 },
|
||
|
{ (SInt16)x0, (SInt16)y1 },
|
||
|
{ (SInt16)x1, (SInt16)y1 }
|
||
|
};
|
||
|
|
||
|
// Copy vertices to dynamic buffer and draw.
|
||
|
void *pbuffer = VertexStream.LockVertexBuffer(4, sizeof(Vertex));
|
||
|
if (pbuffer)
|
||
|
{
|
||
|
memcpy(pbuffer, &strip[0], 4 * sizeof(Vertex));
|
||
|
VertexStream.UnlockVertexBuffer();
|
||
|
pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, VertexStream.GetStartIndex(), 2);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Clean up after rendering a frame. Client program is still
|
||
|
// responsible for calling Present() or glSwapBuffers()
|
||
|
void EndDisplay()
|
||
|
{
|
||
|
// End Scene
|
||
|
if (pDevice)
|
||
|
{
|
||
|
SetPixelShader(PS_None);
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
pDevice->SetVertexShader(0);
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
pDevice->SetVertexShader(D3DFVF_XYZ);
|
||
|
#endif
|
||
|
pDevice->SetTexture(0,0);
|
||
|
|
||
|
if (!(VMCFlags&VMConfig_NoSceneCalls))
|
||
|
pDevice->EndScene();
|
||
|
|
||
|
GFC_DEBUG_WARNING(StencilCounter > 0, "GRenderer::EndDisplay - BeginSubmitMask/DisableSubmitMask mismatch");
|
||
|
}
|
||
|
ReleaseQueuedResources();
|
||
|
}
|
||
|
|
||
|
|
||
|
// Set the current transform for mesh & line-strip rendering.
|
||
|
void SetMatrix(const Matrix& m)
|
||
|
{
|
||
|
CurrentMatrix = m;
|
||
|
}
|
||
|
|
||
|
void SetUserMatrix(const Matrix& m)
|
||
|
{
|
||
|
UserMatrix = m;
|
||
|
#ifndef GFC_NO_3D
|
||
|
MatricesChanged = true;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
// Set the current color transform for mesh & line-strip rendering.
|
||
|
void SetCxform(const Cxform& cx)
|
||
|
{
|
||
|
CurrentCxform = cx;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Structure describing color combines applied for a given blend mode.
|
||
|
struct BlendModeDesc
|
||
|
{
|
||
|
D3DBLENDOP BlendOp;
|
||
|
D3DBLEND SrcArg, DestArg;
|
||
|
};
|
||
|
|
||
|
struct BlendModeDescAlpha
|
||
|
{
|
||
|
D3DBLENDOP BlendOp;
|
||
|
D3DBLEND SrcArg, DestArg;
|
||
|
D3DBLEND SrcAlphaArg, DestAlphaArg;
|
||
|
};
|
||
|
|
||
|
void ApplyBlendMode(BlendType mode, bool forceAc = 0, bool sourceAc = 0)
|
||
|
{
|
||
|
static BlendModeDesc modes[15] =
|
||
|
{
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA }, // None
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA }, // Normal
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA }, // Layer
|
||
|
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_ZERO }, // Multiply
|
||
|
// (For multiply, should src be pre-multiplied by its inverse alpha?)
|
||
|
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA }, // Screen *??
|
||
|
|
||
|
{ D3DBLENDOP_MAX, D3DBLEND_SRCALPHA, D3DBLEND_ONE }, // Lighten
|
||
|
{ D3DBLENDOP_MIN, D3DBLEND_SRCALPHA, D3DBLEND_ONE }, // Darken
|
||
|
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA }, // Difference *??
|
||
|
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ONE }, // Add
|
||
|
{ D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_ONE }, // Subtract
|
||
|
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA }, // Invert *??
|
||
|
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE }, // Alpha *??
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE }, // Erase *?? What color do we erase to?
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA }, // Overlay *??
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA }, // HardLight *??
|
||
|
};
|
||
|
|
||
|
static BlendModeDescAlpha acmodes[15] =
|
||
|
{
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, D3DBLEND_ONE, D3DBLEND_INVSRCALPHA }, // None
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, D3DBLEND_ONE, D3DBLEND_INVSRCALPHA }, // Normal
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, D3DBLEND_ONE, D3DBLEND_INVSRCALPHA }, // Layer
|
||
|
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_ZERO, D3DBLEND_DESTCOLOR, D3DBLEND_ZERO }, // Multiply
|
||
|
// (For multiply, should src be pre-multiplied by its inverse alpha?)
|
||
|
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, D3DBLEND_ONE, D3DBLEND_INVSRCALPHA }, // Screen *??
|
||
|
|
||
|
{ D3DBLENDOP_MAX, D3DBLEND_SRCALPHA, D3DBLEND_ONE, D3DBLEND_SRCALPHA, D3DBLEND_ONE }, // Lighten
|
||
|
{ D3DBLENDOP_MIN, D3DBLEND_SRCALPHA, D3DBLEND_ONE, D3DBLEND_SRCALPHA, D3DBLEND_ONE }, // Darken
|
||
|
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, D3DBLEND_ONE, D3DBLEND_INVSRCALPHA }, // Difference *??
|
||
|
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ONE, D3DBLEND_ZERO, D3DBLEND_ONE }, // Add
|
||
|
{ D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_ONE, D3DBLEND_ZERO, D3DBLEND_ONE }, // Subtract
|
||
|
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, D3DBLEND_ONE, D3DBLEND_INVSRCALPHA }, // Invert *??
|
||
|
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO, D3DBLEND_ONE, D3DBLEND_ONE }, // Alpha *??
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO, D3DBLEND_ONE, D3DBLEND_ONE }, // Erase *??
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, D3DBLEND_ONE, D3DBLEND_INVSRCALPHA }, // Overlay *??
|
||
|
{ D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, D3DBLEND_ONE, D3DBLEND_INVSRCALPHA }, // Hardlight *??
|
||
|
};
|
||
|
|
||
|
if (!pDevice)
|
||
|
return;
|
||
|
|
||
|
// For debug build
|
||
|
GASSERT(((UInt) mode) < 15);
|
||
|
// For release
|
||
|
if (((UInt) mode) >= 15)
|
||
|
mode = Blend_None;
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
if (UseAcBlend)
|
||
|
{
|
||
|
if ((RenderMode & GViewport::View_AlphaComposite) || forceAc)
|
||
|
{
|
||
|
pDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
|
||
|
pDevice->SetRenderState(D3DRS_BLENDOP, acmodes[mode].BlendOp);
|
||
|
pDevice->SetRenderState(D3DRS_BLENDOPALPHA, acmodes[mode].BlendOp);
|
||
|
if (sourceAc && acmodes[mode].SrcArg == D3DBLEND_SRCALPHA)
|
||
|
pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
|
||
|
else
|
||
|
pDevice->SetRenderState(D3DRS_SRCBLEND, acmodes[mode].SrcArg);
|
||
|
pDevice->SetRenderState(D3DRS_DESTBLEND, acmodes[mode].DestArg);
|
||
|
pDevice->SetRenderState(D3DRS_SRCBLENDALPHA, acmodes[mode].SrcAlphaArg);
|
||
|
pDevice->SetRenderState(D3DRS_DESTBLENDALPHA, acmodes[mode].DestAlphaArg);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pDevice->SetRenderState(D3DRS_BLENDOP, modes[mode].BlendOp);
|
||
|
pDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
|
||
|
if (sourceAc && modes[mode].SrcArg == D3DBLEND_SRCALPHA)
|
||
|
pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
|
||
|
else
|
||
|
pDevice->SetRenderState(D3DRS_SRCBLEND, modes[mode].SrcArg);
|
||
|
pDevice->SetRenderState(D3DRS_DESTBLEND, modes[mode].DestArg);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
{
|
||
|
if ((RenderMode & GViewport::View_AlphaComposite) || forceAc)
|
||
|
{
|
||
|
pDevice->SetRenderState(D3DRS_BLENDOP, acmodes[mode].BlendOp);
|
||
|
if (sourceAc && acmodes[mode].SrcArg == D3DBLEND_SRCALPHA)
|
||
|
pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
|
||
|
else
|
||
|
pDevice->SetRenderState(D3DRS_SRCBLEND, acmodes[mode].SrcArg);
|
||
|
pDevice->SetRenderState(D3DRS_DESTBLEND, acmodes[mode].DestArg);
|
||
|
|
||
|
if (!DrawingMask)
|
||
|
{
|
||
|
if (mode == Blend_Add)
|
||
|
pDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN |
|
||
|
D3DCOLORWRITEENABLE_BLUE);
|
||
|
else
|
||
|
pDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN |
|
||
|
D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pDevice->SetRenderState(D3DRS_BLENDOP, modes[mode].BlendOp);
|
||
|
if (sourceAc && modes[mode].SrcArg == D3DBLEND_SRCALPHA)
|
||
|
pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
|
||
|
else
|
||
|
pDevice->SetRenderState(D3DRS_SRCBLEND, modes[mode].SrcArg);
|
||
|
pDevice->SetRenderState(D3DRS_DESTBLEND, modes[mode].DestArg);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// Pushes a Blend mode onto renderer.
|
||
|
virtual void PushBlendMode(BlendType mode)
|
||
|
{
|
||
|
// Blend modes need to be applied cumulatively, ideally through an extra RT texture.
|
||
|
// If the nested clip has a "Multiply" effect, and its parent has an "Add", the result
|
||
|
// of Multiply should be written to a buffer, and then used in Add.
|
||
|
|
||
|
// For now we only simulate it on one level -> we apply the last effect on top of stack.
|
||
|
// (Note that the current "top" element is BlendMode, it is not actually stored on stack).
|
||
|
// Although incorrect, this will at least ensure that parent's specified effect
|
||
|
// will be applied to children.
|
||
|
|
||
|
BlendModeStack.PushBack(BlendMode);
|
||
|
|
||
|
if ((mode > Blend_Layer) && (BlendMode != mode))
|
||
|
{
|
||
|
BlendMode = mode;
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Pops a blend mode, restoring it to the previous one.
|
||
|
virtual void PopBlendMode()
|
||
|
{
|
||
|
if (BlendModeStack.GetSize() != 0)
|
||
|
{
|
||
|
// Find the next top interesting mode.
|
||
|
BlendType newBlendMode = Blend_None;
|
||
|
|
||
|
for (SInt i = (SInt)BlendModeStack.GetSize()-1; i>=0; i--)
|
||
|
if (BlendModeStack[i] > Blend_Layer)
|
||
|
{
|
||
|
newBlendMode = BlendModeStack[i];
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
BlendModeStack.PopBack();
|
||
|
|
||
|
if (newBlendMode != BlendMode)
|
||
|
{
|
||
|
BlendMode = newBlendMode;
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Stack was empty..
|
||
|
GFC_DEBUG_WARNING(1, "GRendererD3Dx::PopBlendMode - blend mode stack is empty");
|
||
|
}
|
||
|
|
||
|
// multiply current GRenderer::Matrix with d3d GRenderer::Matrix
|
||
|
void ApplyMatrix(const Matrix& matIn)
|
||
|
{
|
||
|
#ifdef GFC_NO_3D
|
||
|
bool use3D = false;
|
||
|
#else
|
||
|
bool use3D = (pWorldMatrix3D != NULL);
|
||
|
#endif
|
||
|
if (!use3D)
|
||
|
{
|
||
|
Matrix m(ViewportMatrix);
|
||
|
m.Prepend(matIn);
|
||
|
|
||
|
float mrows[4][4];
|
||
|
|
||
|
mrows[0][0] = m.M_[0][0];
|
||
|
mrows[0][1] = m.M_[0][1];
|
||
|
mrows[0][2] = 0;
|
||
|
mrows[0][3] = m.M_[0][2];
|
||
|
|
||
|
mrows[1][0] = m.M_[1][0];
|
||
|
mrows[1][1] = m.M_[1][1];
|
||
|
mrows[1][2] = 0;
|
||
|
mrows[1][3] = m.M_[1][2];
|
||
|
|
||
|
mrows[2][0] = 0;
|
||
|
mrows[2][1] = 0;
|
||
|
mrows[2][2] = 1.0f;
|
||
|
mrows[2][3] = 0;
|
||
|
|
||
|
mrows[3][0] = 0;
|
||
|
mrows[3][1] = 0;
|
||
|
mrows[3][2] = 0;
|
||
|
mrows[3][3] = 1.0f;
|
||
|
|
||
|
pDevice->SetVertexShaderConstant(0, &mrows[0][0], 4);
|
||
|
}
|
||
|
#ifndef GFC_NO_3D
|
||
|
else
|
||
|
{
|
||
|
GMatrix3D matIn3D(matIn);
|
||
|
|
||
|
if (MatricesChanged)
|
||
|
{ // cache the view * projection calculation
|
||
|
GMatrix3D userMatrix3D(UserMatrix);
|
||
|
userMatrix3D.Append(ViewMatrix3D);
|
||
|
userMatrix3D.Append(ProjMatrix3D);
|
||
|
UserViewProjMatrix3D = userMatrix3D;
|
||
|
|
||
|
if (RenderTargetStack.GetSize())
|
||
|
Adjust3DMatrixForRT(UserViewProjMatrix3D, ProjMatrix3D, RenderTargetStack[0].ViewMatrix, ViewportMatrix);
|
||
|
|
||
|
MatricesChanged = false;
|
||
|
}
|
||
|
GMatrix3D outMat = matIn3D;
|
||
|
outMat.Append(*pWorldMatrix3D);
|
||
|
outMat.Append(UserViewProjMatrix3D);
|
||
|
|
||
|
outMat.Transpose(); // VS expects this transposed
|
||
|
pDevice->SetVertexShaderConstant(0, outMat.GetAsFloatArray(), 4);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
// Set the given color.
|
||
|
void ApplyColor(GColor c)
|
||
|
{
|
||
|
if (UsePixelShaders)
|
||
|
{
|
||
|
const float mult = 1.0f / 255.0f;
|
||
|
const float alpha = c.GetAlpha() * mult;
|
||
|
// Set color.
|
||
|
float rgba[4] =
|
||
|
{
|
||
|
c.GetRed() * mult, c.GetGreen() * mult,
|
||
|
c.GetBlue() * mult, alpha
|
||
|
};
|
||
|
|
||
|
if ((BlendMode == Blend_Multiply) ||
|
||
|
(BlendMode == Blend_Darken))
|
||
|
{
|
||
|
rgba[0] = gflerp(1.0f, rgba[0], alpha);
|
||
|
rgba[1] = gflerp(1.0f, rgba[1], alpha);
|
||
|
rgba[2] = gflerp(1.0f, rgba[2], alpha);
|
||
|
}
|
||
|
|
||
|
pDevice->SetPixelShaderConstant(0, rgba, 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// With no shaders, color goes into a texture factor constant.
|
||
|
pDevice->SetRenderState(D3DRS_TEXTUREFACTOR, c.Raw);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Don't fill on the {0 == left, 1 == right} side of a path.
|
||
|
void FillStyleDisable()
|
||
|
{
|
||
|
CurrentStyles[FILL_STYLE].Disable();
|
||
|
}
|
||
|
|
||
|
// Don't draw a line on this path.
|
||
|
void LineStyleDisable()
|
||
|
{
|
||
|
CurrentStyles[LINE_STYLE].Disable();
|
||
|
}
|
||
|
|
||
|
|
||
|
// Set fill style for the left interior of the shape. If
|
||
|
// enable is false, turn off fill for the left interior.
|
||
|
void FillStyleColor(GColor color)
|
||
|
{
|
||
|
CurrentStyles[FILL_STYLE].SetColor(CurrentCxform.Transform(color));
|
||
|
}
|
||
|
|
||
|
// Set the line style of the shape. If enable is false, turn
|
||
|
// off lines for following curve segments.
|
||
|
void LineStyleColor(GColor color)
|
||
|
{
|
||
|
CurrentStyles[LINE_STYLE].SetColor(CurrentCxform.Transform(color));
|
||
|
}
|
||
|
|
||
|
void FillStyleBitmap(const FillTexture *pfill)
|
||
|
{
|
||
|
CurrentStyles[FILL_STYLE].SetBitmap(pfill, CurrentCxform);
|
||
|
}
|
||
|
|
||
|
// Sets the interpolated color/texture fill style used for shapes with EdgeAA.
|
||
|
void FillStyleGouraud(GouraudFillType gfill,
|
||
|
const FillTexture *ptexture0,
|
||
|
const FillTexture *ptexture1,
|
||
|
const FillTexture *ptexture2)
|
||
|
{
|
||
|
CurrentStyles[FILL_STYLE].SetGouraudFill(gfill, ptexture0, ptexture1, ptexture2, CurrentCxform);
|
||
|
}
|
||
|
|
||
|
|
||
|
void SetVertexData(const void* pvertices, int numVertices, VertexFormat vf, CacheProvider *pcache)
|
||
|
{
|
||
|
// Dynamic buffer stream update.
|
||
|
VertexStream.SetVertexData(pvertices, numVertices, vf);
|
||
|
|
||
|
// Test cache buffer management support.
|
||
|
CacheList.VerifyCachedData( this, pcache, CacheNode::Buffer_Vertex, (pvertices!=0),
|
||
|
numVertices, (((pvertices!=0)&&numVertices) ? *((SInt16*)pvertices) : 0) );
|
||
|
}
|
||
|
|
||
|
void SetIndexData(const void* pindices, int numIndices, IndexFormat idxf, CacheProvider *pcache)
|
||
|
{
|
||
|
VertexStream.SetIndexData(pindices, numIndices, idxf);
|
||
|
|
||
|
// Test cache buffer management support.
|
||
|
CacheList.VerifyCachedData( this, pcache, CacheNode::Buffer_Index, (pindices!=0),
|
||
|
numIndices, (((pindices!=0)&&numIndices) ? *((UInt16*)pindices) : 0) );
|
||
|
}
|
||
|
|
||
|
void ReleaseCachedData(CachedData *pdata, CachedDataType type)
|
||
|
{
|
||
|
// Releases cached data that was allocated from the cache providers.
|
||
|
CacheList.ReleaseCachedData(pdata, type);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void DrawIndexedTriList(int baseVertexIndex,
|
||
|
int minVertexIndex, int numVertices,
|
||
|
int startIndex, int triangleCount)
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
return;
|
||
|
// Must have vertex data.
|
||
|
if (!VertexStream.HasVertexData() || !VertexStream.HasIndexData() ||
|
||
|
(VertexStream.GetD3DIndexFormat() == D3DFMT_UNKNOWN))
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(!VertexStream.HasVertexData(), "GRendererD3Dx::DrawIndexedTriList failed, vertex data not specified");
|
||
|
GFC_DEBUG_WARNING(!VertexStream.HasIndexData(), "GRendererD3Dx::DrawIndexedTriList failed, index data not specified");
|
||
|
GFC_DEBUG_WARNING((VertexStream.GetD3DIndexFormat() == D3DFMT_UNKNOWN),
|
||
|
"GRendererD3Dx::DrawIndexedTriList failed, index buffer format not specified");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
bool isGouraud = (CurrentStyles[FILL_STYLE].Mode == GFxFillStyle::FM_Gouraud);
|
||
|
VertexFormat vfmt = VertexStream.GetVertexFormat();
|
||
|
|
||
|
// Ensure we have the right vertex size.
|
||
|
// MA: Should we loosen some rules to allow for other decl/shader combinations?
|
||
|
|
||
|
if (isGouraud)
|
||
|
{
|
||
|
if (vfmt == Vertex_XY16iC32)
|
||
|
{
|
||
|
SetVertexDecl(VD_XY16iC32);
|
||
|
SetVertexShader(VS_XY16iC32);
|
||
|
}
|
||
|
else if (vfmt == Vertex_XY16iCF32)
|
||
|
{
|
||
|
SetVertexDecl(VD_XY16iCF32);
|
||
|
|
||
|
if (CurrentStyles[FILL_STYLE].GouraudType != GFill_2Texture)
|
||
|
SetVertexShader(VS_XY16iCF32);
|
||
|
else
|
||
|
SetVertexShader(VS_XY16iCF32_T2);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GASSERT(vfmt == Vertex_XY16i);
|
||
|
SetVertexDecl(VD_Strip);
|
||
|
SetVertexShader(VS_Strip);
|
||
|
}
|
||
|
|
||
|
// Set up current style.
|
||
|
CurrentStyles[FILL_STYLE].Apply(this);
|
||
|
ApplyMatrix(CurrentMatrix);
|
||
|
|
||
|
// Upload data to buffers and draw.
|
||
|
GDynamicVertexStream::PrimitiveDesc prim(baseVertexIndex, minVertexIndex, numVertices, startIndex, triangleCount);
|
||
|
if (!VertexStream.PrepareVertexData(prim))
|
||
|
return;
|
||
|
|
||
|
VertexStream.DrawTriangles();
|
||
|
RenderStats.Triangles += triangleCount;
|
||
|
RenderStats.Primitives++;
|
||
|
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
TriangleCnt.AddCount(triangleCount);
|
||
|
|
||
|
// Second pass might be necessary for some effects on older HW.
|
||
|
if (CurrentStyles[FILL_STYLE].NeedsSecondPass(this))
|
||
|
{
|
||
|
CurrentStyles[FILL_STYLE].ApplySecondPass(this);
|
||
|
|
||
|
VertexStream.DrawTriangles();
|
||
|
RenderStats.Triangles += triangleCount;
|
||
|
RenderStats.Primitives++;
|
||
|
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
TriangleCnt.AddCount(triangleCount);
|
||
|
//CurrentStyles[FILL_STYLE].CleanupSecondPass(this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Draw the line strip formed by the sequence of points.
|
||
|
void DrawLineStrip(int baseVertexIndex, int lineCount)
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
return;
|
||
|
if (!VertexStream.HasVertexData()) // Must have vertex data.
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererD3Dx::DrawLineStrip failed, vertex data not specified");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// MA: Should loosen some rules to allow for other decl/shader combinations?
|
||
|
GASSERT(VertexStream.GetVertexFormat() == Vertex_XY16i);
|
||
|
SetVertexDecl(VD_Strip);
|
||
|
SetVertexShader(VS_Strip);
|
||
|
|
||
|
// Set up current style.
|
||
|
CurrentStyles[LINE_STYLE].Apply(this);
|
||
|
|
||
|
ApplyMatrix(CurrentMatrix);
|
||
|
|
||
|
if (!VertexStream.InitVertexBufferData(baseVertexIndex, lineCount + 1))
|
||
|
return;
|
||
|
pDevice->DrawPrimitive(D3DPT_LINESTRIP, VertexStream.GetStartIndex(), lineCount);
|
||
|
|
||
|
RenderStats.Lines += lineCount;
|
||
|
RenderStats.Primitives++;
|
||
|
|
||
|
DPLineCnt.AddCount(1);
|
||
|
LineCnt.AddCount(lineCount);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// Draw a set of rectangles textured with the given bitmap, with the given color.
|
||
|
// Apply given transform; ignore any currently set transforms.
|
||
|
//
|
||
|
// Intended for textured glyph rendering.
|
||
|
void DrawBitmaps(BitmapDesc* pbitmapList, int listSize, int startIndex, int count,
|
||
|
const GTexture* pti, const Matrix& m,
|
||
|
CacheProvider *pcache)
|
||
|
{
|
||
|
if (!ModeSet || !pbitmapList || !pti)
|
||
|
return;
|
||
|
|
||
|
GTextureD3DxImpl* ptexture = (GTextureD3DxImpl*)pti;
|
||
|
// Texture must be valid for rendering
|
||
|
if (!ptexture->pD3DTexture && !ptexture->CallRecreate())
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererD3Dx::DrawBitmaps failed, empty texture specified/could not recreate texture");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Test cache buffer management support.
|
||
|
// Optimized implementation could use this spot to set vertex buffer and/or initialize offset in it.
|
||
|
// Note that since bitmap lists are usually short, it would be a good idea to combine many of them
|
||
|
// into one buffer, instead of creating individual buffers for each pbitmapList data instance.
|
||
|
CacheList.VerifyCachedData( this, pcache, CacheNode::Buffer_BitmapList, (pbitmapList!=0),
|
||
|
listSize, (((pbitmapList!=0)&&listSize) ? ((SInt)pbitmapList->Coords.Left) : 0) );
|
||
|
|
||
|
|
||
|
// Complex
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
|
||
|
pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||
|
|
||
|
// Set texture.
|
||
|
bool IsAlpha = 0;
|
||
|
|
||
|
if (ptexture->IsYUVTexture() == 2)
|
||
|
{
|
||
|
if (BlendMode == Blend_Multiply || BlendMode == Blend_Darken)
|
||
|
SetPixelShader(PS_TextTextureYUVAMultiply);
|
||
|
else
|
||
|
SetPixelShader(PS_TextTextureYUVA);
|
||
|
}
|
||
|
else if (ptexture->IsYUVTexture() == 1)
|
||
|
{
|
||
|
if (BlendMode == Blend_Multiply || BlendMode == Blend_Darken)
|
||
|
SetPixelShader(PS_TextTextureYUVMultiply);
|
||
|
else
|
||
|
SetPixelShader(PS_TextTextureYUV);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
IsAlpha = (ptexture->TextureFormat == D3DFMT_A8 || ptexture->TextureFormat == D3DFMT_A8L8 || ptexture->TextureFormat == D3DFMT_A4R4G4B4);
|
||
|
|
||
|
if (IsAlpha)
|
||
|
SetPixelShader(PS_TextTextureAlpha);
|
||
|
else if (BlendMode == Blend_Multiply || BlendMode == Blend_Darken)
|
||
|
SetPixelShader(PS_TextTextureColorMultiply);
|
||
|
else
|
||
|
SetPixelShader(PS_TextTextureColor);
|
||
|
}
|
||
|
|
||
|
ptexture->Bind(0, Wrap_Clamp, Sample_Linear, 0 == ptexture->IsYUVTexture());
|
||
|
|
||
|
// Switch to non-texgen shader.
|
||
|
SetVertexDecl(VD_Glyph);
|
||
|
SetVertexShader(VS_Glyph);
|
||
|
|
||
|
if (UsePixelShaders)
|
||
|
ApplyPShaderCxform(CurrentCxform, 2);
|
||
|
|
||
|
ApplyMatrix(m);
|
||
|
|
||
|
int ibitmap = 0, ivertex = 0;
|
||
|
GCOMPILER_ASSERT((GDynamicVertexStream::GlyphBufferVertexCount%6) == 0);
|
||
|
|
||
|
Cxform cxformm(CurrentCxform);
|
||
|
if (!IsAlpha)
|
||
|
cxformm.M_[0][1] = cxformm.M_[1][1] = cxformm.M_[2][1] = cxformm.M_[3][1] = 0;
|
||
|
D3DCOLOR Pass2Color = 0;
|
||
|
bool Use2Passes = 0;
|
||
|
|
||
|
if (!UsePixelShaders && !IsAlpha && (CurrentCxform.M_[0][1] > 0 || CurrentCxform.M_[1][1] > 0 ||
|
||
|
CurrentCxform.M_[2][1] > 0 || CurrentCxform.M_[3][1] > 0))
|
||
|
{
|
||
|
Pass2Color = D3DCOLOR_ARGB(
|
||
|
(UByte)CurrentCxform.M_[3][1],
|
||
|
(UByte)CurrentCxform.M_[0][1],
|
||
|
(UByte)CurrentCxform.M_[1][1],
|
||
|
(UByte)CurrentCxform.M_[2][1] );
|
||
|
Use2Passes = 1;
|
||
|
}
|
||
|
|
||
|
while (ibitmap < count)
|
||
|
{
|
||
|
// Lock the vertex buffer for glyphs.
|
||
|
int vertexCount = G_Min<int>((count-ibitmap) * 6, GDynamicVertexStream::GlyphBufferVertexCount);
|
||
|
void * pbuffer = VertexStream.LockVertexBuffer(vertexCount, sizeof(GGlyphVertex));
|
||
|
if (!pbuffer)
|
||
|
return;
|
||
|
|
||
|
if (UsePixelShaders)
|
||
|
for(ivertex = 0; (ivertex < vertexCount) && (ibitmap<count); ibitmap++, ivertex+= 6)
|
||
|
{
|
||
|
BitmapDesc & bd = pbitmapList[ibitmap + startIndex];
|
||
|
GGlyphVertex* pv = ((GGlyphVertex*)pbuffer) + ivertex;
|
||
|
|
||
|
// Triangle 1.
|
||
|
pv[0].SetVertex2D(bd.Coords.Left, bd.Coords.Top, bd.TextureCoords.Left, bd.TextureCoords.Top, bd.Color);
|
||
|
pv[1].SetVertex2D(bd.Coords.Right, bd.Coords.Top, bd.TextureCoords.Right, bd.TextureCoords.Top, bd.Color);
|
||
|
pv[2].SetVertex2D(bd.Coords.Left, bd.Coords.Bottom, bd.TextureCoords.Left, bd.TextureCoords.Bottom, bd.Color);
|
||
|
// Triangle 2.
|
||
|
pv[3].SetVertex2D(bd.Coords.Left, bd.Coords.Bottom, bd.TextureCoords.Left, bd.TextureCoords.Bottom, bd.Color);
|
||
|
pv[4].SetVertex2D(bd.Coords.Right, bd.Coords.Top, bd.TextureCoords.Right, bd.TextureCoords.Top, bd.Color);
|
||
|
pv[5].SetVertex2D(bd.Coords.Right, bd.Coords.Bottom,bd.TextureCoords.Right, bd.TextureCoords.Bottom, bd.Color);
|
||
|
}
|
||
|
else
|
||
|
for(ivertex = 0; (ivertex < vertexCount) && (ibitmap<count); ibitmap++, ivertex+= 6)
|
||
|
{
|
||
|
BitmapDesc & bd = pbitmapList[ibitmap + startIndex];
|
||
|
GGlyphVertex* pv = ((GGlyphVertex*)pbuffer) + ivertex;
|
||
|
GColor Color = cxformm.Transform(bd.Color);
|
||
|
|
||
|
// Triangle 1.
|
||
|
pv[0].SetVertex2D(bd.Coords.Left, bd.Coords.Top, bd.TextureCoords.Left, bd.TextureCoords.Top, Color);
|
||
|
pv[1].SetVertex2D(bd.Coords.Right, bd.Coords.Top, bd.TextureCoords.Right, bd.TextureCoords.Top, Color);
|
||
|
pv[2].SetVertex2D(bd.Coords.Left, bd.Coords.Bottom, bd.TextureCoords.Left, bd.TextureCoords.Bottom, Color);
|
||
|
// Triangle 2.
|
||
|
pv[3].SetVertex2D(bd.Coords.Left, bd.Coords.Bottom, bd.TextureCoords.Left, bd.TextureCoords.Bottom, Color);
|
||
|
pv[4].SetVertex2D(bd.Coords.Right, bd.Coords.Top, bd.TextureCoords.Right, bd.TextureCoords.Top, Color);
|
||
|
pv[5].SetVertex2D(bd.Coords.Right, bd.Coords.Bottom,bd.TextureCoords.Right, bd.TextureCoords.Bottom, Color);
|
||
|
}
|
||
|
|
||
|
VertexStream.UnlockVertexBuffer();
|
||
|
|
||
|
// Draw the generated triangles.
|
||
|
if (ivertex)
|
||
|
{
|
||
|
pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, VertexStream.GetStartIndex(), ivertex / 3);
|
||
|
RenderStats.Primitives++;
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
|
||
|
if (Use2Passes)
|
||
|
{
|
||
|
pDevice->SetRenderState(D3DRS_TEXTUREFACTOR, Pass2Color);
|
||
|
SetPixelShader(PShaderIndex, 1);
|
||
|
|
||
|
pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||
|
pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
|
||
|
|
||
|
pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, VertexStream.GetStartIndex(), ivertex / 3);
|
||
|
RenderStats.Primitives++;
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
if (BlendMode == Blend_Multiply || BlendMode == Blend_Darken)
|
||
|
SetPixelShader(PS_TextTextureColorMultiply);
|
||
|
else
|
||
|
SetPixelShader(PS_TextTextureColor);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
RenderStats.Triangles += count * 2;
|
||
|
TriangleCnt.AddCount(count * 2);
|
||
|
}
|
||
|
|
||
|
|
||
|
void BeginSubmitMask(SubmitMaskMode maskMode)
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
return;
|
||
|
|
||
|
DrawingMask = 1;
|
||
|
|
||
|
if (!StencilAvailable && !DepthBufferAvailable)
|
||
|
{
|
||
|
if (!StencilChecked)
|
||
|
{
|
||
|
// Test for depth-stencil presence.
|
||
|
IDirect3DSurfaceX *pdepthStencilSurface = 0;
|
||
|
pDevice->GetDepthStencilSurface(&pdepthStencilSurface);
|
||
|
if (pdepthStencilSurface)
|
||
|
{
|
||
|
D3DSURFACE_DESC sd;
|
||
|
pdepthStencilSurface->GetDesc(&sd);
|
||
|
|
||
|
switch(sd.Format)
|
||
|
{
|
||
|
case D3DFMT_D24S8:
|
||
|
case D3DFMT_D24X4S4:
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
case D3DFMT_D24FS8:
|
||
|
#endif
|
||
|
MultiBitStencil = 1;
|
||
|
case D3DFMT_D15S1:
|
||
|
StencilAvailable = 1;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pdepthStencilSurface->Release();
|
||
|
pdepthStencilSurface = 0;
|
||
|
DepthBufferAvailable = 1;
|
||
|
}
|
||
|
else
|
||
|
StencilAvailable = 0;
|
||
|
|
||
|
StencilChecked = 1;
|
||
|
}
|
||
|
|
||
|
if (!StencilAvailable && !DepthBufferAvailable)
|
||
|
{
|
||
|
#ifdef GFC_BUILD_DEBUG
|
||
|
static bool StencilWarned = 0;
|
||
|
if (!StencilWarned)
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererD3Dx::BeginSubmitMask used, but stencil is not available");
|
||
|
StencilWarned = 1;
|
||
|
}
|
||
|
#endif
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (StencilAvailable)
|
||
|
{
|
||
|
pDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILMASK, 0xFF);
|
||
|
|
||
|
pDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);
|
||
|
|
||
|
// Check that we have appropriate stencil functionality for nested masks.
|
||
|
bool canIncDec = (MultiBitStencil && (StencilOpInc != D3DSTENCILOP_REPLACE));
|
||
|
|
||
|
switch(maskMode)
|
||
|
{
|
||
|
case Mask_Clear:
|
||
|
pDevice->Clear(0, 0, D3DCLEAR_STENCIL, 0, 0.0f, 0);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILREF, 1);
|
||
|
StencilCounter = 1;
|
||
|
break;
|
||
|
|
||
|
case Mask_Increment:
|
||
|
// Increment only if we support it.
|
||
|
if (canIncDec)
|
||
|
{
|
||
|
pDevice->SetRenderState(D3DRS_STENCILREF, StencilCounter);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILPASS, StencilOpInc);
|
||
|
StencilCounter++;
|
||
|
}
|
||
|
else
|
||
|
{ // If not supported, no change.
|
||
|
pDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case Mask_Decrement:
|
||
|
if (canIncDec)
|
||
|
{
|
||
|
pDevice->SetRenderState(D3DRS_STENCILREF, StencilCounter);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILPASS, StencilOpDec);
|
||
|
StencilCounter--;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else if (DepthBufferAvailable)
|
||
|
{
|
||
|
// Clear the Z-buffer
|
||
|
if (maskMode == Mask_Clear)
|
||
|
{
|
||
|
pDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0, 1.0f, 0);
|
||
|
|
||
|
// Set the correct render states in order to not modify the color buffer
|
||
|
// but write the default Z-value everywhere. According to the shader code: should be 0.
|
||
|
pDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA);
|
||
|
pDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
|
||
|
pDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
|
||
|
pDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// No color write. Incr/Decr not supported.
|
||
|
pDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
|
||
|
pDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
|
||
|
pDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||
|
}
|
||
|
}
|
||
|
RenderStats.Masks++;
|
||
|
MaskCnt.AddCount(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Defines all D3Dx color channels for D3DRS_COLORWRITEENABLE
|
||
|
#define D3DCOLORWRITEENABLE_ALL D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_RED | \
|
||
|
D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN
|
||
|
|
||
|
void EndSubmitMask()
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
return;
|
||
|
|
||
|
DrawingMask = 0;
|
||
|
StencilEnabled = 1;
|
||
|
pDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALL);
|
||
|
|
||
|
if (StencilAvailable)
|
||
|
{
|
||
|
|
||
|
// We draw only where the (stencil == StencilCounter), i.e. where the latest mask was drawn.
|
||
|
// However, we don't change the stencil buffer
|
||
|
pDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
|
||
|
// Stencil counter.
|
||
|
pDevice->SetRenderState(D3DRS_STENCILREF, StencilCounter);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILMASK, 0xFF);
|
||
|
|
||
|
}
|
||
|
else if (DepthBufferAvailable)
|
||
|
{
|
||
|
// Disable the Z-write and write only where the mask had written
|
||
|
pDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
|
||
|
pDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
|
||
|
pDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void DisableMask()
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
return;
|
||
|
|
||
|
StencilEnabled = 0;
|
||
|
pDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALL);
|
||
|
|
||
|
if (StencilAvailable)
|
||
|
{
|
||
|
StencilCounter = 0;
|
||
|
pDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
|
||
|
}
|
||
|
else if (DepthBufferAvailable)
|
||
|
{
|
||
|
// Disable the Z-write and write only where the mask had written
|
||
|
pDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
|
||
|
pDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||
|
pDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
virtual void GetRenderStats(Stats *pstats, bool resetStats)
|
||
|
{
|
||
|
if (pstats)
|
||
|
memcpy(pstats, &RenderStats, sizeof(Stats));
|
||
|
if (resetStats)
|
||
|
RenderStats.Clear();
|
||
|
}
|
||
|
|
||
|
// StatBag statistics
|
||
|
virtual void GetStats(GStatBag* pbag, bool reset)
|
||
|
{
|
||
|
if (pbag)
|
||
|
{
|
||
|
pbag->Add(GStatRender_Texture_VMem, &TextureVMem);
|
||
|
pbag->Add(GStatRender_Buffer_VMem, &BufferVMem);
|
||
|
|
||
|
pbag->Add(GStatRender_TextureUpload_Cnt, &TextureUploadCnt);
|
||
|
pbag->Add(GStatRender_TextureUpdate_Cnt, &TextureUpdateCnt);
|
||
|
|
||
|
pbag->Add(GStatRender_DP_Line_Cnt, &DPLineCnt);
|
||
|
pbag->Add(GStatRender_DP_Triangle_Cnt, &DPTriangleCnt);
|
||
|
pbag->Add(GStatRender_Line_Cnt, &LineCnt);
|
||
|
pbag->Add(GStatRender_Triangle_Cnt, &TriangleCnt);
|
||
|
pbag->Add(GStatRender_Mask_Cnt, &MaskCnt);
|
||
|
pbag->Add(GStatRender_Filter_Cnt, &FilterCnt);
|
||
|
}
|
||
|
|
||
|
if (reset)
|
||
|
{
|
||
|
TextureUploadCnt.Reset();
|
||
|
TextureUpdateCnt.Reset();
|
||
|
|
||
|
DPLineCnt.Reset();
|
||
|
DPTriangleCnt.Reset();
|
||
|
LineCnt.Reset();
|
||
|
TriangleCnt.Reset();
|
||
|
MaskCnt.Reset();
|
||
|
FilterCnt.Reset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// GRendererD3Dx interface implementation
|
||
|
|
||
|
virtual bool SetDependentVideoMode(
|
||
|
LPDIRECT3DDEVICEx pd3dDevice,
|
||
|
D3DPRESENT_PARAMETERS* ppresentParams,
|
||
|
UInt32 vmConfigFlags,
|
||
|
HWND hwnd)
|
||
|
{
|
||
|
if (!pd3dDevice || !ppresentParams)
|
||
|
return 0;
|
||
|
|
||
|
// TODO: Need to check device caps ?
|
||
|
pDevice = pd3dDevice;
|
||
|
pDevice->AddRef();
|
||
|
|
||
|
UsePixelShaders = 0;
|
||
|
UseYUVShaders = 0;
|
||
|
TexNonPower2 = 0;
|
||
|
FiltersSupported = 0;
|
||
|
|
||
|
// Detect if we can use shaders.
|
||
|
D3DCAPSx caps;
|
||
|
pDevice->GetDeviceCaps(&caps);
|
||
|
|
||
|
if (0 == (caps.TextureCaps & D3DPTEXTURECAPS_POW2))
|
||
|
{
|
||
|
if (0 == (caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL))
|
||
|
TexNonPower2 = 2;
|
||
|
else
|
||
|
TexNonPower2 = 1;
|
||
|
}
|
||
|
|
||
|
if ((caps.PixelShaderVersion & 0xFFFF) >= GRENDERER_SHADER_VERSION)
|
||
|
UsePixelShaders = 1;
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 8)
|
||
|
if ((caps.PixelShaderVersion & 0xFFFF) >= 0x0104 && (caps.MaxPixelShaderValue >= 4))
|
||
|
UseYUVShaders = 1;
|
||
|
#else
|
||
|
if ((caps.PixelShaderVersion & 0xFFFF) >= 0x0104 && (caps.PixelShader1xMaxValue >= 4))
|
||
|
UseYUVShaders = 1;
|
||
|
|
||
|
if ((caps.PixelShaderVersion & 0xFFFF) >= 0x300)
|
||
|
{
|
||
|
FiltersSupported = 3;
|
||
|
MaxTextureOps = 32;
|
||
|
PShaderProfile = "ps_3_0";
|
||
|
VShaderProfile = "vs_3_0";
|
||
|
}
|
||
|
else if ((caps.PixelShaderVersion & 0xFFFF) >= 0x201)
|
||
|
{
|
||
|
FiltersSupported = 2;
|
||
|
MaxTextureOps = 16;
|
||
|
PShaderProfile = "ps_2_a";
|
||
|
VShaderProfile = "vs_2_a";
|
||
|
}
|
||
|
else if ((caps.PixelShaderVersion & 0xFFFF) >= 0x200)
|
||
|
{
|
||
|
FiltersSupported = 1;
|
||
|
MaxTextureOps = 8;
|
||
|
PShaderProfile = "ps_2_0";
|
||
|
VShaderProfile = "vs_2_0";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PShaderProfile = GRENDERER_PSHADER_PROFILE;
|
||
|
VShaderProfile = GRENDERER_VSHADER_PROFILE;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
VMCFlags = vmConfigFlags;
|
||
|
|
||
|
if ((caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && (VMCFlags & VMConfig_UseDynamicTex))
|
||
|
UseDynamicTex = 1;
|
||
|
else
|
||
|
UseDynamicTex = 0;
|
||
|
if (VMCFlags & VMConfig_UseManagedTex)
|
||
|
UseManagedTex = 1;
|
||
|
else
|
||
|
UseManagedTex = 0;
|
||
|
|
||
|
AlphaTextureFormat = D3DFMT_A8;
|
||
|
|
||
|
GPtr<IDirect3DTextureX> pTestTexture;
|
||
|
HRESULT result = pDevice->CreateTexture(1,1,1,0,D3DFMT_A8,
|
||
|
UseManagedTex ? D3DPOOL_MANAGED : D3DPOOL_DEFAULT,
|
||
|
&pTestTexture.GetRawRef() NULL9);
|
||
|
if (result != S_OK)
|
||
|
UseYUVShaders = 0;
|
||
|
|
||
|
// Detect stencil op.
|
||
|
if (caps.StencilCaps & D3DSTENCILCAPS_INCR)
|
||
|
{
|
||
|
StencilOpInc = D3DSTENCILOP_INCR;
|
||
|
StencilOpDec = D3DSTENCILOP_DECR;
|
||
|
}
|
||
|
else if (caps.StencilCaps & D3DSTENCILCAPS_INCRSAT)
|
||
|
{
|
||
|
StencilOpInc = D3DSTENCILOP_INCRSAT;
|
||
|
StencilOpDec = D3DSTENCILOP_DECRSAT;
|
||
|
}
|
||
|
else
|
||
|
{ // Stencil ops not available.
|
||
|
StencilOpInc = D3DSTENCILOP_REPLACE;
|
||
|
StencilOpDec = D3DSTENCILOP_REPLACE;
|
||
|
}
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
UseAcBlend = (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) != 0;
|
||
|
#else
|
||
|
UseAcBlend = 0;
|
||
|
#endif
|
||
|
|
||
|
if (!InitShaders(&caps) || !VertexStream.Initialize(pd3dDevice))
|
||
|
{
|
||
|
ReleaseShaders();
|
||
|
pDevice->Release();
|
||
|
pDevice = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
memcpy(&PresentParams, ppresentParams, sizeof(D3DPRESENT_PARAMETERS));
|
||
|
hWnd = hwnd;
|
||
|
|
||
|
ModeSet = 1;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// Returns back to original mode (cleanup)
|
||
|
virtual bool ResetVideoMode()
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
return 1;
|
||
|
|
||
|
ReleaseQueuedResources();
|
||
|
|
||
|
// Release texture resources.
|
||
|
{
|
||
|
GLock::Locker guard(&TexturesLock);
|
||
|
|
||
|
GTextureD3DxImpl* ptexture = (GTextureD3DxImpl*)Textures.pFirst;
|
||
|
while (ptexture && ptexture != &Textures)
|
||
|
{
|
||
|
// Save next pointer, since ptexture->Release() after CallHandlers
|
||
|
// can potentially destroy the texture if user released in in the handler.
|
||
|
GTextureD3DxImpl* pnext = (GTextureD3DxImpl*)ptexture->pNext;
|
||
|
|
||
|
// Save texture in case CallHandlers clear them out.
|
||
|
if (ptexture->AddRef_NotZero())
|
||
|
{
|
||
|
if (!ptexture->IsManaged)
|
||
|
{
|
||
|
ptexture->ReleaseTexture();
|
||
|
ptexture->CallHandlers(GTexture::ChangeHandler::Event_DataLost);
|
||
|
}
|
||
|
ptexture->Release();
|
||
|
}
|
||
|
|
||
|
ptexture = pnext;
|
||
|
}
|
||
|
|
||
|
GRenderTargetD3D9Impl* pRT = (GRenderTargetD3D9Impl*)RenderTargets.pFirst;
|
||
|
while (pRT && pRT != &RenderTargets)
|
||
|
{
|
||
|
GRenderTargetD3D9Impl* pnext = (GRenderTargetD3D9Impl*)pRT->pNext;
|
||
|
if (pRT->AddRef_NotZero())
|
||
|
{
|
||
|
if (pRT->pRenderSurface)
|
||
|
{
|
||
|
pRT->ReleaseResources();
|
||
|
pRT->CallHandlers(GTexture::ChangeHandler::Event_DataLost);
|
||
|
}
|
||
|
pRT->Release();
|
||
|
}
|
||
|
|
||
|
pRT = pnext;
|
||
|
}
|
||
|
|
||
|
// This must be done last because it will delay actual release of d3d resources, which will not work
|
||
|
TempRenderTargets.Clear();
|
||
|
TempStencilBuffers.Clear();
|
||
|
}
|
||
|
|
||
|
VertexStream.Reset();
|
||
|
|
||
|
pTempSurfaceA = pTempSurfaceLA = pTempSurfaceRGBA4 = pTempSurfaceRGBA8 = 0;
|
||
|
pTempTextureA = pTempTextureLA = pTempTextureRGBA4 = pTempTextureRGBA8 = 0;
|
||
|
|
||
|
ReleaseShaders();
|
||
|
pDevice->Release();
|
||
|
pDevice = 0;
|
||
|
hWnd = 0;
|
||
|
|
||
|
ModeSet = 0;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
virtual DisplayStatus CheckDisplayStatus() const
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
return DisplayStatus_NoModeSet;
|
||
|
|
||
|
HRESULT cooperativeLevel = pDevice->TestCooperativeLevel();
|
||
|
if (cooperativeLevel == D3D_OK)
|
||
|
return DisplayStatus_Ok;
|
||
|
|
||
|
// Ensure that textures are released.
|
||
|
pDevice->SetTexture(0, 0);
|
||
|
|
||
|
// Release texture resources.
|
||
|
{ GLock::Locker guard(&TexturesLock);
|
||
|
|
||
|
GTextureD3DxImpl* ptexture = (GTextureD3DxImpl*)Textures.pFirst;
|
||
|
while (ptexture != &Textures)
|
||
|
{
|
||
|
// Save next ahead of time because CallHandles can delete the texture.
|
||
|
GTextureD3DxImpl* pnext = (GTextureD3DxImpl*)ptexture->pNext;
|
||
|
if (ptexture->AddRef_NotZero())
|
||
|
{
|
||
|
if (ptexture->pD3DTexture && !ptexture->IsManaged)
|
||
|
{
|
||
|
ptexture->pD3DTexture->Release();
|
||
|
ptexture->pD3DTexture = 0;
|
||
|
ptexture->CallHandlers(GTexture::ChangeHandler::Event_DataLost);
|
||
|
}
|
||
|
else if (ptexture->TextureFormat == D3DFMT_D24S8)
|
||
|
{
|
||
|
GDepthBufferD3D9Impl* pdepth = (GDepthBufferD3D9Impl*)ptexture;
|
||
|
pdepth->ReleaseTexture();
|
||
|
}
|
||
|
ptexture->Release();
|
||
|
}
|
||
|
ptexture = pnext;
|
||
|
}
|
||
|
|
||
|
GRenderTargetD3D9Impl* pRT = (GRenderTargetD3D9Impl*)RenderTargets.pFirst;
|
||
|
while (pRT && pRT != &RenderTargets)
|
||
|
{
|
||
|
GRenderTargetD3D9Impl* pnext = (GRenderTargetD3D9Impl*)pRT->pNext;
|
||
|
if (pRT->AddRef_NotZero())
|
||
|
{
|
||
|
if (pRT->pRenderSurface)
|
||
|
{
|
||
|
pRT->ReleaseResources();
|
||
|
pRT->CallHandlers(GTexture::ChangeHandler::Event_DataLost);
|
||
|
}
|
||
|
pRT->Release();
|
||
|
}
|
||
|
|
||
|
pRT = pnext;
|
||
|
}
|
||
|
|
||
|
// This must be done last because it will delay actual release of d3d resources, which will not work
|
||
|
const_cast<GArrayLH<GPtr<GRenderTargetD3D9Impl> >&> (TempRenderTargets).Clear();
|
||
|
const_cast<GArrayLH<GPtr<GDepthBufferD3D9Impl> >&> (TempStencilBuffers).Clear();
|
||
|
}
|
||
|
// Release vertex buffers (pass LostDevice flag).
|
||
|
// TBD: CheckDisplayStatus() probably should not be const.
|
||
|
const_cast<GDynamicVertexStream&>(VertexStream).ReleaseDynamicBuffers(1);
|
||
|
|
||
|
if (cooperativeLevel == D3DERR_DEVICENOTRESET)
|
||
|
return DisplayStatus_NeedsReset;
|
||
|
|
||
|
//else: (cooperativeLevel == D3DERR_DEVICELOST)
|
||
|
return DisplayStatus_Unavailable;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Direct3D9 Access
|
||
|
// Return various Dirext3D related information
|
||
|
virtual LPDIRECT3Dx GetDirect3D() const
|
||
|
{
|
||
|
LPDIRECT3Dx pd3d = 0;
|
||
|
if (pDevice)
|
||
|
pDevice->GetDirect3D(&pd3d);
|
||
|
return pd3d;
|
||
|
}
|
||
|
virtual LPDIRECT3DDEVICEx GetDirect3DDevice() const
|
||
|
{
|
||
|
return pDevice;
|
||
|
}
|
||
|
virtual bool GetDirect3DPresentParameters(D3DPRESENT_PARAMETERS* ppresentParams) const
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
return 0;
|
||
|
memcpy(ppresentParams, &PresentParams, sizeof(D3DPRESENT_PARAMETERS));
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
}; // class GRendererD3DxImpl
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// ***** GTextureD3Dx implementation
|
||
|
|
||
|
|
||
|
GTextureD3DxImpl::GTextureD3DxImpl(GRendererD3DxImpl *prenderer)
|
||
|
: GTextureD3Dx(&prenderer->Textures)
|
||
|
{
|
||
|
pRenderer = prenderer;
|
||
|
pD3DTexture = 0;
|
||
|
IsManaged = 0;
|
||
|
TexWidth = TexHeight = 0;
|
||
|
TextureFormat = D3DFMT_UNKNOWN;
|
||
|
}
|
||
|
|
||
|
GTextureD3DxImpl::~GTextureD3DxImpl()
|
||
|
{
|
||
|
if (pD3DTexture)
|
||
|
{
|
||
|
GASSERT(pRenderer);
|
||
|
if (pRenderer)
|
||
|
pRenderer->AddResourceForReleasing(pD3DTexture);
|
||
|
else
|
||
|
// it should never happen
|
||
|
pD3DTexture->Release();
|
||
|
}
|
||
|
if (!pRenderer)
|
||
|
return;
|
||
|
GLock::Locker guard(&pRenderer->TexturesLock);
|
||
|
if (pFirst)
|
||
|
RemoveNode();
|
||
|
}
|
||
|
|
||
|
// Obtains the renderer that create TextureInfo
|
||
|
GRenderer* GTextureD3DxImpl::GetRenderer() const
|
||
|
{ return pRenderer; }
|
||
|
bool GTextureD3DxImpl::IsDataValid() const
|
||
|
{ return (pD3DTexture != 0); }
|
||
|
|
||
|
|
||
|
// Remove texture from renderer, notifies renderer destruction
|
||
|
void GTextureD3DxImpl::RemoveFromRenderer()
|
||
|
{
|
||
|
// Clear pRenderer so that CallHandlers passes null
|
||
|
// renderer as an internal argument for Event_RendererReleased.
|
||
|
pRenderer = 0;
|
||
|
|
||
|
// Texture could be in the process of being killed on another
|
||
|
// thread (if its destructor is being called but hasn't had a chance
|
||
|
// to clean us out from the list); if that is the case we can not
|
||
|
// call AddRef to revive the object.
|
||
|
if (AddRef_NotZero())
|
||
|
{
|
||
|
ReleaseTexture();
|
||
|
CallHandlers(ChangeHandler::Event_RendererReleased);
|
||
|
if (pNext) // We may have been released by user.
|
||
|
RemoveNode();
|
||
|
Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (pNext) // We may have been released by user.
|
||
|
RemoveNode();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GTextureD3DxImpl::ReleaseTexture()
|
||
|
{
|
||
|
if (pD3DTexture)
|
||
|
{
|
||
|
pD3DTexture->Release();
|
||
|
pD3DTexture = 0;
|
||
|
}
|
||
|
TextureFormat = D3DFMT_UNKNOWN;
|
||
|
IsManaged = 0;
|
||
|
}
|
||
|
|
||
|
// Creates a D3D texture of the specified dest dimensions, from a
|
||
|
// resampled version of the given src image. Does a bilinear
|
||
|
// resampling to create the dest image.
|
||
|
// Source can be 4,3, or 1 bytes/pixel. Destination is either 1 or 4 bytes/pixel.
|
||
|
static void SoftwareResample(
|
||
|
UByte* pDst, int dstWidth, int dstHeight, int dstPitch,
|
||
|
UByte* pSrc, int srcWidth, int srcHeight, int srcPitch,
|
||
|
int bytesPerPixel )
|
||
|
{
|
||
|
switch(bytesPerPixel)
|
||
|
{
|
||
|
case 4:
|
||
|
GRenderer::ResizeImage(pDst, dstWidth, dstHeight, dstPitch,
|
||
|
pSrc, srcWidth, srcHeight, srcPitch,
|
||
|
GRenderer::ResizeRgbaToRgba);
|
||
|
break;
|
||
|
|
||
|
case 3:
|
||
|
GRenderer::ResizeImage(pDst, dstWidth, dstHeight, dstPitch,
|
||
|
pSrc, srcWidth, srcHeight, srcPitch,
|
||
|
GRenderer::ResizeRgbToRgba);
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
GRenderer::ResizeImage(pDst, dstWidth, dstHeight, dstPitch,
|
||
|
pSrc, srcWidth, srcHeight, srcPitch,
|
||
|
GRenderer::ResizeGray);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool GTextureD3DxImpl::InitTexture(IDirect3DTextureX *ptex, bool managed)
|
||
|
{
|
||
|
if (!pRenderer || !pRenderer->pDevice)
|
||
|
return 0;
|
||
|
|
||
|
ReleaseTexture();
|
||
|
if (ptex)
|
||
|
{
|
||
|
D3DSURFACE_DESC desc;
|
||
|
ptex->GetLevelDesc(0, &desc);
|
||
|
TexWidth = desc.Width;
|
||
|
TexHeight = desc.Height;
|
||
|
pD3DTexture = ptex;
|
||
|
ptex->AddRef();
|
||
|
IsManaged = managed;
|
||
|
}
|
||
|
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// NOTE: This function destroys pim's data in the process of making mipmaps.
|
||
|
bool GTextureD3DxImpl::InitTexture(GImageBase* pim, UInt usage)
|
||
|
{
|
||
|
if (!pRenderer || !pRenderer->pDevice)
|
||
|
return 0;
|
||
|
|
||
|
pRenderer->TextureUploadCnt.AddCount(1);
|
||
|
|
||
|
// Delete old data
|
||
|
ReleaseTexture();
|
||
|
if (!pim || !pim->pData)
|
||
|
{
|
||
|
// Kill texture
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// Determine format
|
||
|
UInt bytesPerPixel = 0;
|
||
|
|
||
|
if (pim->Format == GImage::Image_ARGB_8888)
|
||
|
{
|
||
|
bytesPerPixel = 4;
|
||
|
TextureFormat = D3DFMT_A8R8G8B8;
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_RGB_888)
|
||
|
{
|
||
|
bytesPerPixel = 3;
|
||
|
TextureFormat = D3DFMT_A8R8G8B8;
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_A_8)
|
||
|
{
|
||
|
bytesPerPixel = 1;
|
||
|
TextureFormat = pRenderer->AlphaTextureFormat;
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_DXT1)
|
||
|
{
|
||
|
TextureFormat = D3DFMT_DXT1;
|
||
|
bytesPerPixel = 1;
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_DXT3)
|
||
|
{
|
||
|
TextureFormat = D3DFMT_DXT3;
|
||
|
bytesPerPixel = 1;
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_DXT5)
|
||
|
{
|
||
|
TextureFormat = D3DFMT_DXT5;
|
||
|
bytesPerPixel = 1;
|
||
|
}
|
||
|
else
|
||
|
{ // Unsupported format
|
||
|
GASSERT(0);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
IsManaged = pRenderer->UseManagedTex || (usage & Usage_Map);
|
||
|
|
||
|
UInt w = pim->Width;
|
||
|
UInt h = pim->Height;
|
||
|
|
||
|
if (pRenderer->TexNonPower2 < ((usage & Usage_Wrap) ? 2 : 1))
|
||
|
{
|
||
|
w = 1; while (w < pim->Width) { w <<= 1; }
|
||
|
h = 1; while (h < pim->Height) { h <<= 1; }
|
||
|
}
|
||
|
|
||
|
TexWidth = w;
|
||
|
TexHeight = h;
|
||
|
|
||
|
UInt levelsNeeded;
|
||
|
if (pim->IsDataCompressed() || pim->MipMapCount > 1)
|
||
|
levelsNeeded = G_Max<UInt>(1, pim->MipMapCount);
|
||
|
else
|
||
|
{
|
||
|
levelsNeeded = 1;
|
||
|
UInt mipw = w, miph = h;
|
||
|
while (mipw > 1 || miph > 1)
|
||
|
{
|
||
|
mipw >>= 1;
|
||
|
miph >>= 1;
|
||
|
levelsNeeded++;
|
||
|
}
|
||
|
}
|
||
|
GPtr<GImage> presampleImage;
|
||
|
|
||
|
// Set the actual data.
|
||
|
if (!pim->IsDataCompressed() && (w != pim->Width || h != pim->Height ||
|
||
|
pim->Format == GImage::Image_RGB_888
|
||
|
#if (GFC_D3D_VERSION == 8)
|
||
|
|| pim->Format == GImage::Image_ARGB_8888
|
||
|
#endif
|
||
|
))
|
||
|
{
|
||
|
GASSERT_ON_RENDERER_RESAMPLING;
|
||
|
|
||
|
// Resample the image to new size
|
||
|
if (presampleImage = *new GImage(
|
||
|
((pim->Format == GImage::Image_RGB_888) ? GImage::Image_ARGB_8888 : pim->Format), w, h))
|
||
|
{
|
||
|
if (w != pim->Width || h != pim->Height)
|
||
|
{
|
||
|
// Resample will store an extra Alpha byte for RGB_888 -> RGBA_8888
|
||
|
SoftwareResample(presampleImage->pData, w, h, presampleImage->Pitch,
|
||
|
pim->pData, pim->Width, pim->Height, pim->Pitch, bytesPerPixel);
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 8)
|
||
|
for (UInt y = 0; y < h; y++)
|
||
|
{
|
||
|
UInt32* pdest = (UInt32*) presampleImage->GetScanline(y);
|
||
|
for (UInt x = 0; x < w; x++)
|
||
|
pdest[x] = (pdest[x] & 0xff00ff00) | ((pdest[x] & 0xff) << 16) | ((pdest[x] >> 16) & 0xff);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_RGB_888)
|
||
|
{
|
||
|
// Need to insert a dummy alpha byte in the image data, for D3DXLoadSurfaceFromMemory.
|
||
|
for (UInt y = 0; y < h; y++)
|
||
|
{
|
||
|
UByte* scanline = pim->GetScanline(y);
|
||
|
UByte* pdest = presampleImage->GetScanline(y);
|
||
|
for (UInt x = 0; x < w; x++)
|
||
|
{
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
pdest[x * 4 + 0] = scanline[x * 3 + 0]; // red
|
||
|
pdest[x * 4 + 1] = scanline[x * 3 + 1]; // green
|
||
|
pdest[x * 4 + 2] = scanline[x * 3 + 2]; // blue
|
||
|
#else
|
||
|
pdest[x * 4 + 2] = scanline[x * 3 + 0]; // red
|
||
|
pdest[x * 4 + 1] = scanline[x * 3 + 1]; // green
|
||
|
pdest[x * 4 + 0] = scanline[x * 3 + 2]; // blue
|
||
|
#endif
|
||
|
pdest[x * 4 + 3] = 255; // alpha
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#if (GFC_D3D_VERSION == 8)
|
||
|
else if (pim->Format == GImage::Image_ARGB_8888)
|
||
|
{
|
||
|
for (UInt y = 0; y < h; y++)
|
||
|
{
|
||
|
UInt32* pdest = (UInt32*) presampleImage->GetScanline(y);
|
||
|
UInt32* psrc = (UInt32*) pim->GetScanline(y);
|
||
|
for (UInt x = 0; x < w; x++)
|
||
|
pdest[x] = (psrc[x] & 0xff00ff00) | ((psrc[x] & 0xff) << 16) | ((psrc[x] >> 16) & 0xff);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
if (pim->MipMapCount > 1)
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererD3Dx - Existing mipmap levels have been skipped due to resampling");
|
||
|
levelsNeeded = 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Create the texture.
|
||
|
// For now, only generate mipmaps for alpha textures.
|
||
|
// MA: For some reason we need to specify levelsNeeded-1, otherwise
|
||
|
// surface accesses may crash (when running with Gamebryo).
|
||
|
// So, 256x256 texture seems to have levelCount of 8 (not 9).
|
||
|
if (pim->MipMapCount <= 1 && bytesPerPixel != 1)
|
||
|
levelsNeeded = 1;
|
||
|
else
|
||
|
levelsNeeded = G_Max(1u, levelsNeeded - 1);
|
||
|
//levelsNeeded = G_Max(1u, (bytesPerPixel == 1) ? UInt(levelsNeeded - 1) : 1u);
|
||
|
|
||
|
td3d9_retry_create_texture:
|
||
|
HRESULT result = pRenderer->pDevice->CreateTexture(
|
||
|
w, h,
|
||
|
levelsNeeded,
|
||
|
0, // XBox: D3DUSAGE_BORDERSOURCE_TEXTURE
|
||
|
TextureFormat,
|
||
|
IsManaged ? D3DPOOL_MANAGED : D3DPOOL_DEFAULT,
|
||
|
&pD3DTexture NULL9);
|
||
|
if (result != S_OK)
|
||
|
{
|
||
|
// If texture format A8 failed, try another format
|
||
|
// Workaround for some Nvidia drivers
|
||
|
if (TextureFormat == D3DFMT_A8)
|
||
|
{
|
||
|
TextureFormat = pRenderer->AlphaTextureFormat = D3DFMT_A8L8;
|
||
|
goto td3d9_retry_create_texture;
|
||
|
}
|
||
|
else if (TextureFormat == D3DFMT_A8L8)
|
||
|
{
|
||
|
TextureFormat = pRenderer->AlphaTextureFormat = D3DFMT_A4R4G4B4; // Geforce4 MX
|
||
|
goto td3d9_retry_create_texture;
|
||
|
}
|
||
|
|
||
|
GFC_DEBUG_ERROR(1, "GTextureD3Dx - Can't create texture");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (pim->IsDataCompressed() || pim->MipMapCount > 1)
|
||
|
{
|
||
|
IDirect3DSurfaceX* psurface = NULL;
|
||
|
UInt level;
|
||
|
GImageBase* psourceImage= presampleImage ? presampleImage.GetPtr() : pim;
|
||
|
RECT sourceRect = { 0,0, w,h};
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
D3DFORMAT sourceSurfaceFormat = (TextureFormat == D3DFMT_A8R8G8B8) ? D3DFMT_A8B8G8R8 : TextureFormat;
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
D3DFORMAT sourceSurfaceFormat = TextureFormat;
|
||
|
#endif
|
||
|
|
||
|
for(level = 0; level < levelsNeeded; level++)
|
||
|
{
|
||
|
// Load all levels...
|
||
|
if (pD3DTexture->GetSurfaceLevel(level, &psurface) != S_OK)
|
||
|
{
|
||
|
pD3DTexture->Release();
|
||
|
pD3DTexture = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
GASSERT(psurface);
|
||
|
|
||
|
UInt mipW, mipH;
|
||
|
const UByte* pmipData = psourceImage->GetMipMapLevelData(level, &mipW, &mipH);
|
||
|
|
||
|
sourceRect.right = mipW;
|
||
|
sourceRect.bottom = mipH;
|
||
|
|
||
|
result = D3DXLoadSurfaceFromMemory(
|
||
|
psurface, NULL, NULL,
|
||
|
pmipData,
|
||
|
sourceSurfaceFormat, // NOTE: format order conversion from GL
|
||
|
(pim->IsDataCompressed()) ?
|
||
|
GImageBase::GetMipMapLevelSize(psourceImage->Format, mipW, 1) :
|
||
|
GImageBase::GetPitch(psourceImage->Format, mipW),
|
||
|
NULL,
|
||
|
&sourceRect,
|
||
|
D3DX_DEFAULT, 0);
|
||
|
psurface->Release();
|
||
|
psurface = 0;
|
||
|
|
||
|
if (result != S_OK)
|
||
|
{
|
||
|
GFC_DEBUG_ERROR1(1, "GTextureD3Dx - Can't load surface from memory, result = %d", result);
|
||
|
pD3DTexture->Release();
|
||
|
pD3DTexture = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Will need a buffer for destructive mipmap generation
|
||
|
if ((bytesPerPixel == 1) && (levelsNeeded >1) && !presampleImage)
|
||
|
{
|
||
|
GASSERT_ON_RENDERER_MIPMAP_GEN;
|
||
|
|
||
|
// A bit hacky, needs to be more general
|
||
|
presampleImage = *GImage::CreateImage(pim->Format, pim->Width, pim->Height);
|
||
|
GASSERT(pim->Pitch == presampleImage->Pitch);
|
||
|
memcpy(presampleImage->pData, pim->pData, pim->Height * pim->Pitch);
|
||
|
}
|
||
|
|
||
|
IDirect3DSurfaceX* psurface = NULL;
|
||
|
UInt level;
|
||
|
GImageBase* psourceImage= presampleImage ? presampleImage.GetPtr() : pim;
|
||
|
RECT sourceRect = { 0,0, w,h};
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
D3DFORMAT sourceSurfaceFormat = (bytesPerPixel == 1) ? D3DFMT_A8 : D3DFMT_A8B8G8R8;
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
D3DFORMAT sourceSurfaceFormat = (bytesPerPixel == 1) ? D3DFMT_A8 : D3DFMT_A8R8G8B8;
|
||
|
#endif
|
||
|
|
||
|
for(level = 0; level<levelsNeeded; level++)
|
||
|
{
|
||
|
// Load all levels...
|
||
|
if (pD3DTexture->GetSurfaceLevel(level, &psurface) != S_OK)
|
||
|
{
|
||
|
pD3DTexture->Release();
|
||
|
pD3DTexture = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
GASSERT(psurface);
|
||
|
|
||
|
result = D3DXLoadSurfaceFromMemory(
|
||
|
psurface, NULL, NULL,
|
||
|
psourceImage->pData,
|
||
|
sourceSurfaceFormat, // NOTE: format order conversion from GL
|
||
|
(bytesPerPixel == 1) ? sourceRect.right : psourceImage->Pitch,
|
||
|
NULL,
|
||
|
&sourceRect,
|
||
|
D3DX_DEFAULT, 0);
|
||
|
psurface->Release();
|
||
|
psurface = 0;
|
||
|
|
||
|
if (result != S_OK)
|
||
|
{
|
||
|
GFC_DEBUG_ERROR1(1, "GTextureD3Dx - Can't load surface from memory, result = %d", result);
|
||
|
pD3DTexture->Release();
|
||
|
pD3DTexture = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// For Alpha-only images, we might need to generate the next mipmap level.
|
||
|
if (level< (levelsNeeded-1))
|
||
|
{
|
||
|
if (psourceImage == pim)
|
||
|
{
|
||
|
presampleImage = new GImage(*pim);
|
||
|
psourceImage = presampleImage.GetPtr();
|
||
|
}
|
||
|
GCOMPILER_ASSERT(sizeof(sourceRect.right) == sizeof(int));
|
||
|
GRendererD3DxImpl::MakeNextMiplevel((int*) &sourceRect.right, (int*) &sourceRect.bottom,
|
||
|
psourceImage->pData);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool GTextureD3DxImpl::InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage)
|
||
|
{
|
||
|
if (!pRenderer || !pRenderer->pDevice)
|
||
|
return 0;
|
||
|
|
||
|
ReleaseTexture();
|
||
|
|
||
|
if (format == GImage::Image_ARGB_8888)
|
||
|
TextureFormat = D3DFMT_A8R8G8B8;
|
||
|
else if (format == GImage::Image_RGB_888)
|
||
|
TextureFormat = D3DFMT_A8R8G8B8;
|
||
|
else if (format == GImage::Image_A_8)
|
||
|
TextureFormat = pRenderer->AlphaTextureFormat;
|
||
|
else
|
||
|
{ // Unsupported format
|
||
|
GASSERT(0);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
TexWidth = width;
|
||
|
TexHeight = height;
|
||
|
IsManaged = pRenderer->UseManagedTex || (usage & Usage_Map);
|
||
|
Mipmaps = mipmaps;
|
||
|
|
||
|
td3d9_retry_create_texture:
|
||
|
HRESULT result = pRenderer->pDevice->CreateTexture(width, height, mipmaps+1,
|
||
|
((usage & Usage_RenderTarget) ? D3DUSAGE_RENDERTARGET :
|
||
|
((pRenderer->UseDynamicTex && !IsManaged) ? D3DUSAGE_DYNAMIC : 0)),
|
||
|
TextureFormat,
|
||
|
IsManaged ? D3DPOOL_MANAGED : D3DPOOL_DEFAULT, &pD3DTexture NULL9);
|
||
|
if (result != S_OK)
|
||
|
{
|
||
|
// If texture format A8 failed, try another format
|
||
|
// Workaround for some Nvidia drivers
|
||
|
if (TextureFormat == D3DFMT_A8)
|
||
|
{
|
||
|
TextureFormat = pRenderer->AlphaTextureFormat = D3DFMT_A8L8;
|
||
|
goto td3d9_retry_create_texture;
|
||
|
}
|
||
|
else if (TextureFormat == D3DFMT_A8L8)
|
||
|
{
|
||
|
TextureFormat = pRenderer->AlphaTextureFormat = D3DFMT_A4R4G4B4; // Geforce4 MX
|
||
|
goto td3d9_retry_create_texture;
|
||
|
}
|
||
|
|
||
|
GFC_DEBUG_ERROR(1, "GTextureD3Dx - Can't create texture");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void GTextureD3DxImpl::Update(int level, int n, const UpdateRect *rects, const GImageBase *pim)
|
||
|
{
|
||
|
UInt bytesPerPixel = 0;
|
||
|
IDirect3DSurfaceX *ptempsurface;
|
||
|
|
||
|
pRenderer->TextureUpdateCnt.AddCount(1);
|
||
|
|
||
|
if (pim->Format == GImage::Image_ARGB_8888)
|
||
|
{
|
||
|
bytesPerPixel = 4;
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_RGB_888)
|
||
|
{
|
||
|
bytesPerPixel = 3;
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_A_8)
|
||
|
{
|
||
|
bytesPerPixel = 1;
|
||
|
}
|
||
|
else
|
||
|
GASSERT(0);
|
||
|
|
||
|
if (!pD3DTexture && !CallRecreate())
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GTextureD3Dx::Update failed, could not recreate texture");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (pRenderer->UseDynamicTex || IsManaged)
|
||
|
{
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
GRect<int> rect = rects[i].src;
|
||
|
GPoint<int> dest = rects[i].dest;
|
||
|
|
||
|
D3DLOCKED_RECT lr;
|
||
|
RECT destr;
|
||
|
|
||
|
destr.left = dest.x;
|
||
|
destr.bottom = dest.y + rect.Height();
|
||
|
destr.right = dest.x + rect.Width();
|
||
|
destr.top = dest.y;
|
||
|
|
||
|
if (FAILED( pD3DTexture->LockRect(level, &lr, &destr, 0) ))
|
||
|
return;
|
||
|
|
||
|
UByte *pdest = (UByte*)lr.pBits;
|
||
|
|
||
|
for (int j = 0; j < rect.Height(); j++)
|
||
|
memcpy(pdest + j * lr.Pitch,
|
||
|
pim->GetScanline(j + rect.Top) + bytesPerPixel * rect.Left,
|
||
|
rect.Width() * bytesPerPixel);
|
||
|
|
||
|
pD3DTexture->UnlockRect(level);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
else if (TextureFormat == D3DFMT_A8)
|
||
|
{
|
||
|
if (!pRenderer->pTempTextureA)
|
||
|
{
|
||
|
pRenderer->pDevice->CreateTexture(pRenderer->TempW, pRenderer->TempH,
|
||
|
1, 0, D3DFMT_A8, D3DPOOL_SYSTEMMEM, &pRenderer->pTempTextureA.GetRawRef() NULL9);
|
||
|
pRenderer->pTempTextureA->GetSurfaceLevel(0, &pRenderer->pTempSurfaceA.GetRawRef());
|
||
|
}
|
||
|
ptempsurface = pRenderer->pTempSurfaceA;
|
||
|
}
|
||
|
else if (TextureFormat == D3DFMT_A8L8)
|
||
|
{
|
||
|
if (!pRenderer->pTempTextureLA)
|
||
|
{
|
||
|
pRenderer->pDevice->CreateTexture(pRenderer->TempW, pRenderer->TempH,
|
||
|
1, 0, D3DFMT_A8L8, D3DPOOL_SYSTEMMEM, &pRenderer->pTempTextureLA.GetRawRef() NULL9);
|
||
|
pRenderer->pTempTextureLA->GetSurfaceLevel(0, &pRenderer->pTempSurfaceLA.GetRawRef());
|
||
|
}
|
||
|
ptempsurface = pRenderer->pTempSurfaceLA;
|
||
|
}
|
||
|
else if (TextureFormat == D3DFMT_A4R4G4B4)
|
||
|
{
|
||
|
if (!pRenderer->pTempTextureRGBA4)
|
||
|
{
|
||
|
pRenderer->pDevice->CreateTexture(pRenderer->TempW, pRenderer->TempH,
|
||
|
1, 0, D3DFMT_A4R4G4B4, D3DPOOL_SYSTEMMEM, &pRenderer->pTempTextureRGBA4.GetRawRef() NULL9);
|
||
|
pRenderer->pTempTextureRGBA4->GetSurfaceLevel(0, &pRenderer->pTempSurfaceRGBA4.GetRawRef());
|
||
|
}
|
||
|
ptempsurface = pRenderer->pTempSurfaceRGBA4;
|
||
|
}
|
||
|
else if (TextureFormat == D3DFMT_A8R8G8B8)
|
||
|
{
|
||
|
if (!pRenderer->pTempTextureRGBA8)
|
||
|
{
|
||
|
pRenderer->pDevice->CreateTexture(pRenderer->TempW, pRenderer->TempH,
|
||
|
1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pRenderer->pTempTextureRGBA8.GetRawRef() NULL9);
|
||
|
pRenderer->pTempTextureRGBA8->GetSurfaceLevel(0, &pRenderer->pTempSurfaceRGBA8.GetRawRef());
|
||
|
}
|
||
|
ptempsurface = pRenderer->pTempSurfaceRGBA8;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GASSERT(0);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
IDirect3DSurfaceX *psurface;
|
||
|
|
||
|
if (pD3DTexture->GetSurfaceLevel(level, &psurface) != S_OK)
|
||
|
return;
|
||
|
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
GRect<int> rect = rects[i].src;
|
||
|
GPoint<int> dest = rects[i].dest;
|
||
|
|
||
|
for(int x = rect.Left; x<rect.Right; x+= pRenderer->TempW)
|
||
|
for(int y = rect.Top; y<rect.Bottom; y+= pRenderer->TempH)
|
||
|
{
|
||
|
GRect<int> sourceRect(x, y, x + pRenderer->TempW, y + pRenderer->TempH);
|
||
|
if (sourceRect.Right > rect.Right)
|
||
|
sourceRect.Right = rect.Right;
|
||
|
if (sourceRect.Bottom > rect.Bottom)
|
||
|
sourceRect.Bottom = rect.Bottom;
|
||
|
|
||
|
// ** First, copy the section to the system buffer
|
||
|
D3DLOCKED_RECT lr;
|
||
|
GSize<int> size = sourceRect.Size();
|
||
|
//RECT destr = {dest.x, dest.y, dest.x + size.Width, dest.y + size.Height};
|
||
|
|
||
|
if (FAILED( ptempsurface->LockRect(&lr, NULL, 0) ))
|
||
|
{
|
||
|
psurface->Release();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
switch (TextureFormat)
|
||
|
{
|
||
|
case D3DFMT_A8L8:
|
||
|
for (int j = 0; j < size.Height; j++)
|
||
|
for (int k = 0; k < size.Width; k++)
|
||
|
{
|
||
|
((UByte*)lr.pBits)[j * lr.Pitch + k * 2 + 1] = pim->pData[pim->Pitch * (j + sourceRect.Top) + k + sourceRect.Left];
|
||
|
((UByte*)lr.pBits)[j * lr.Pitch + k * 2] = 255;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case D3DFMT_A4R4G4B4:
|
||
|
for (int j = 0; j < size.Height; j++)
|
||
|
for (int k = 0; k < size.Width; k++)
|
||
|
{
|
||
|
((UByte*)lr.pBits)[j * lr.Pitch + k * 2] = 255;
|
||
|
((UByte*)lr.pBits)[j * lr.Pitch + k * 2 + 1] = (pim->pData[pim->Pitch * (j + sourceRect.Top) + k + sourceRect.Left]) | 0xf;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case D3DFMT_A8:
|
||
|
for (int j = 0; j < size.Height; j++)
|
||
|
memcpy(((UByte*)lr.pBits) + j * lr.Pitch,
|
||
|
pim->pData + pim->Pitch * (j + sourceRect.Top) + pim->GetBytesPerPixel() * sourceRect.Left,
|
||
|
size.Width * pim->GetBytesPerPixel());
|
||
|
break;
|
||
|
case D3DFMT_A8R8G8B8:
|
||
|
for (int j = 0; j < size.Height; j++)
|
||
|
memcpy(((UByte*)lr.pBits) + j * lr.Pitch,
|
||
|
pim->pData + pim->Pitch * (j + sourceRect.Top) + pim->GetBytesPerPixel() * sourceRect.Left,
|
||
|
size.Width * pim->GetBytesPerPixel());
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ptempsurface->UnlockRect();
|
||
|
|
||
|
// ** Now, copy the buffer to D3D Texture surface
|
||
|
RECT sr = { 0, 0, size.Width, size.Height}; // changed for floats
|
||
|
POINT pos= { sourceRect.Left - rect.Left + dest.x, sourceRect.Top - rect.Top + dest.y};
|
||
|
|
||
|
#if (GFC_D3D_VERSION == 9)
|
||
|
pRenderer->pDevice->UpdateSurface(ptempsurface, &sr, psurface, &pos);
|
||
|
|
||
|
#elif (GFC_D3D_VERSION == 8)
|
||
|
pRenderer->pDevice->CopyRects(ptempsurface, &sr, 1, psurface, &pos);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
psurface->Release();
|
||
|
}
|
||
|
|
||
|
|
||
|
int GTextureD3DxImpl::Map(int level, int n, MapRect* maps, int flags)
|
||
|
{
|
||
|
GUNUSED2(n,flags);
|
||
|
GASSERT(n > 0 && maps);
|
||
|
|
||
|
if (!pD3DTexture)
|
||
|
{
|
||
|
GImage::ImageFormat format = GImage::Image_A_8;
|
||
|
if (TextureFormat == D3DFMT_A8R8G8B8)
|
||
|
format = GImage::Image_ARGB_8888;
|
||
|
else if (TextureFormat == D3DFMT_A8R8G8B8)
|
||
|
format = GImage::Image_RGB_888;
|
||
|
|
||
|
if (!InitDynamicTexture(TexWidth, TexHeight, format, Mipmaps, Usage_Map))
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GTextureD3Dx::Map failed, could not recreate texture");
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int h = TexHeight;
|
||
|
int w = TexWidth;
|
||
|
|
||
|
for (int i = 0; i < level; i++)
|
||
|
{
|
||
|
h >>= 1;
|
||
|
if (h < 1)
|
||
|
h = 1;
|
||
|
w >>= 1;
|
||
|
if (w < 1)
|
||
|
w = 1;
|
||
|
}
|
||
|
|
||
|
D3DLOCKED_RECT rect;
|
||
|
if (FAILED(pD3DTexture->LockRect(level, &rect, NULL, 0)))
|
||
|
return 0;
|
||
|
maps[0].pData = (UByte*)rect.pBits;
|
||
|
maps[0].pitch = rect.Pitch;
|
||
|
maps[0].width = w;
|
||
|
maps[0].height = h;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool GTextureD3DxImpl::Unmap(int level, int n, MapRect* maps, int flags)
|
||
|
{
|
||
|
GUNUSED3(n,maps,flags);
|
||
|
return (S_OK == pD3DTexture->UnlockRect(level));
|
||
|
}
|
||
|
|
||
|
bool GTextureD3DxImpl::LoadFromImage(GImageBase* sourceImg)
|
||
|
{
|
||
|
bool success = false;
|
||
|
IDirect3DSurfaceX* thisSurface;
|
||
|
if (pD3DTexture && pD3DTexture->GetSurfaceLevel(0, &thisSurface) == S_OK)
|
||
|
{
|
||
|
IDirect3DSurfaceX* sourceSurface;
|
||
|
GPtr<GTextureD3Dx> sourceTex = *pRenderer->CreateTexture();
|
||
|
if (sourceTex && sourceTex->InitTexture(sourceImg, Usage_Map))
|
||
|
{
|
||
|
if (sourceTex->GetNativeTexture() && sourceTex->GetNativeTexture()->GetSurfaceLevel(0, &sourceSurface) == S_OK)
|
||
|
{
|
||
|
HRESULT hr = D3DXLoadSurfaceFromSurface(thisSurface, NULL, NULL, sourceSurface, NULL, NULL, D3DX_DEFAULT, 0);
|
||
|
sourceSurface->Release();
|
||
|
success = !FAILED(hr);
|
||
|
}
|
||
|
}
|
||
|
thisSurface->Release();
|
||
|
}
|
||
|
return success;
|
||
|
}
|
||
|
|
||
|
void GTextureD3DxImpl::Bind(int stageIndex, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps)
|
||
|
{
|
||
|
if (!pD3DTexture)
|
||
|
CallRecreate();
|
||
|
|
||
|
pRenderer->pDevice->SetTexture(stageIndex, pD3DTexture);
|
||
|
pRenderer->ApplySampleMode(stageIndex, WrapMode, SampleMode, useMipmaps);
|
||
|
}
|
||
|
|
||
|
GTextureD3DxImplYUV::~GTextureD3DxImplYUV()
|
||
|
{
|
||
|
for (int i = 0; i < 3; i++)
|
||
|
if (pD3DTextureUVA[i])
|
||
|
{
|
||
|
GASSERT(pRenderer);
|
||
|
if (pRenderer)
|
||
|
pRenderer->AddResourceForReleasing(pD3DTextureUVA[i]);
|
||
|
else
|
||
|
// it should never happen
|
||
|
pD3DTextureUVA[i]->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GTextureD3DxImplYUV::ReleaseTexture()
|
||
|
{
|
||
|
GTextureD3DxImpl::ReleaseTexture();
|
||
|
for (int i = 0; i < 3; i++)
|
||
|
if (pD3DTextureUVA[i])
|
||
|
{
|
||
|
pD3DTextureUVA[i]->Release();
|
||
|
pD3DTextureUVA[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool GTextureD3DxImplYUV::InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage)
|
||
|
{
|
||
|
if (!pRenderer || !pRenderer->pDevice)
|
||
|
return 0;
|
||
|
|
||
|
GUNUSED(usage);
|
||
|
ReleaseTexture();
|
||
|
|
||
|
TexWidth = width;
|
||
|
TexHeight = height;
|
||
|
Mipmaps = mipmaps;
|
||
|
IsManaged = 1;
|
||
|
|
||
|
HRESULT result = pRenderer->pDevice->CreateTexture(width, height, mipmaps+1, 0,
|
||
|
D3DFMT_A8, D3DPOOL_MANAGED, &pD3DTexture NULL9);
|
||
|
result |= pRenderer->pDevice->CreateTexture(width>>1, height>>1, mipmaps+1, 0,
|
||
|
D3DFMT_A8, D3DPOOL_MANAGED, &pD3DTextureUVA[0] NULL9);
|
||
|
result |= pRenderer->pDevice->CreateTexture(width>>1, height>>1, mipmaps+1, 0,
|
||
|
D3DFMT_A8, D3DPOOL_MANAGED, &pD3DTextureUVA[1] NULL9);
|
||
|
if (format == GImage::Image_ARGB_8888)
|
||
|
{
|
||
|
IsAlpha = 1;
|
||
|
result |= pRenderer->pDevice->CreateTexture(width, height, mipmaps+1, 0,
|
||
|
D3DFMT_A8, D3DPOOL_MANAGED, &pD3DTextureUVA[2] NULL9);
|
||
|
}
|
||
|
else
|
||
|
IsAlpha = 0;
|
||
|
|
||
|
if (result != S_OK)
|
||
|
{
|
||
|
GFC_DEBUG_ERROR(1, "GTextureD3Dx - Can't create YUV texture");
|
||
|
ReleaseTexture();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int GTextureD3DxImplYUV::Map(int level, int n, MapRect* maps, int flags)
|
||
|
{
|
||
|
GUNUSED(flags);
|
||
|
GASSERT(n >= (IsAlpha ? 4 : 3) && maps);
|
||
|
|
||
|
if (!pD3DTexture)
|
||
|
{
|
||
|
if (!InitDynamicTexture(TexWidth, TexHeight, IsAlpha ? GImage::Image_ARGB_8888 : GImage::Image_RGB_888, Mipmaps, Usage_Map))
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GTextureD3Dx::Map failed, could not recreate texture");
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int h = TexHeight;
|
||
|
int w = TexWidth;
|
||
|
|
||
|
for (int i = 0; i < level; i++)
|
||
|
{
|
||
|
h >>= 1;
|
||
|
if (h < 1)
|
||
|
h = 1;
|
||
|
w >>= 1;
|
||
|
if (w < 1)
|
||
|
w = 1;
|
||
|
}
|
||
|
|
||
|
n = IsAlpha ? 4 : 3;
|
||
|
D3DLOCKED_RECT rect;
|
||
|
pD3DTexture->LockRect(level, &rect, NULL, 0);
|
||
|
maps[0].pData = (UByte*)rect.pBits;
|
||
|
maps[0].pitch = rect.Pitch;
|
||
|
maps[0].width = w;
|
||
|
maps[0].height = h;
|
||
|
for (int i = 1; i < n; i++)
|
||
|
{
|
||
|
pD3DTextureUVA[i-1]->LockRect(level, &rect, NULL, 0);
|
||
|
maps[i].pData = (UByte*)rect.pBits;
|
||
|
maps[i].pitch = rect.Pitch;
|
||
|
maps[i].width = (i == 3) ? w : (w >> 1);
|
||
|
maps[i].height = (i == 3) ? h : (h >> 1);
|
||
|
}
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
bool GTextureD3DxImplYUV::Unmap(int level, int n, MapRect* maps, int flags)
|
||
|
{
|
||
|
GUNUSED3(n,maps,flags);
|
||
|
pD3DTexture->UnlockRect(level);
|
||
|
for (int i = 0; i < 3; i++)
|
||
|
if (pD3DTextureUVA[i])
|
||
|
pD3DTextureUVA[i]->UnlockRect(level);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void GTextureD3DxImplYUV::Bind(int stageIndex, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps)
|
||
|
{
|
||
|
if (!pD3DTexture)
|
||
|
{
|
||
|
if (!InitDynamicTexture(TexWidth, TexHeight, IsAlpha ? GImage::Image_ARGB_8888 : GImage::Image_RGB_888, Mipmaps, Usage_Map))
|
||
|
GFC_DEBUG_WARNING(1, "GTextureD3Dx::Bind failed, could not recreate texture");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GASSERT(stageIndex == 0);
|
||
|
GUNUSED(stageIndex);
|
||
|
|
||
|
pRenderer->pDevice->SetTexture(0, pD3DTexture);
|
||
|
pRenderer->pDevice->SetTexture(1, pD3DTextureUVA[0]);
|
||
|
pRenderer->pDevice->SetTexture(2, pD3DTextureUVA[1]);
|
||
|
pRenderer->ApplySampleMode(0, WrapMode, SampleMode, useMipmaps);
|
||
|
pRenderer->ApplySampleMode(1, WrapMode, SampleMode, useMipmaps);
|
||
|
pRenderer->ApplySampleMode(2, WrapMode, SampleMode, useMipmaps);
|
||
|
if (pD3DTextureUVA[2])
|
||
|
{
|
||
|
pRenderer->pDevice->SetTexture(3, pD3DTextureUVA[2]);
|
||
|
pRenderer->ApplySampleMode(3, WrapMode, SampleMode, useMipmaps);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Factory.
|
||
|
GRendererD3Dx* GRendererD3Dx::CreateRenderer()
|
||
|
{
|
||
|
return new GRendererD3DxImpl;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////
|
||
|
|
||
|
GDepthBufferD3D9Impl::~GDepthBufferD3D9Impl()
|
||
|
{
|
||
|
if (pDepthStencil)
|
||
|
{
|
||
|
GASSERT(pRenderer);
|
||
|
if (pRenderer)
|
||
|
pRenderer->AddResourceForReleasing(pDepthStencil);
|
||
|
else
|
||
|
// it should never happen
|
||
|
pDepthStencil->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GDepthBufferD3D9Impl::ReleaseTexture()
|
||
|
{
|
||
|
if (pDepthStencil)
|
||
|
pDepthStencil->Release();
|
||
|
pDepthStencil = 0;
|
||
|
TextureFormat = D3DFMT_UNKNOWN;
|
||
|
}
|
||
|
|
||
|
bool GDepthBufferD3D9Impl::InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage)
|
||
|
{
|
||
|
if (!pRenderer || !pRenderer->pDevice)
|
||
|
return 0;
|
||
|
|
||
|
GUNUSED(usage);
|
||
|
GUNUSED(format);
|
||
|
ReleaseTexture();
|
||
|
|
||
|
TexWidth = width;
|
||
|
TexHeight = height;
|
||
|
Mipmaps = mipmaps;
|
||
|
TextureFormat = D3DFMT_D24S8;
|
||
|
|
||
|
pRenderer->pDevice->CreateDepthStencilSurface( width, height, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0,
|
||
|
TRUE, &pDepthStencil, NULL);
|
||
|
return pDepthStencil != 0;
|
||
|
}
|
||
|
|
||
|
GRenderTargetD3D9Impl::GRenderTargetD3D9Impl(GRendererD3D9Impl *prenderer)
|
||
|
: GRenderTargetD3D9(&prenderer->RenderTargets)
|
||
|
{
|
||
|
pRenderer = prenderer;
|
||
|
pRenderSurface = 0;
|
||
|
pStencilSurface = 0;
|
||
|
IsTemp = 0;
|
||
|
}
|
||
|
|
||
|
GRenderTargetD3D9Impl::~GRenderTargetD3D9Impl()
|
||
|
{
|
||
|
if (pRenderSurface)
|
||
|
{
|
||
|
GASSERT(pRenderer);
|
||
|
if (pRenderer)
|
||
|
{
|
||
|
pRenderer->AddResourceForReleasing(pRenderSurface);
|
||
|
pRenderer->AddResourceForReleasing(pStencilSurface);
|
||
|
}
|
||
|
}
|
||
|
if (!pRenderer)
|
||
|
return;
|
||
|
GLock::Locker guard(&pRenderer->TexturesLock);
|
||
|
if (pFirst)
|
||
|
RemoveNode();
|
||
|
}
|
||
|
|
||
|
void GRenderTargetD3D9Impl::ReleaseResources()
|
||
|
{
|
||
|
if (pRenderSurface)
|
||
|
{
|
||
|
pRenderSurface->Release();
|
||
|
pRenderSurface = 0;
|
||
|
}
|
||
|
if (pStencilSurface)
|
||
|
{
|
||
|
pStencilSurface->Release();
|
||
|
pStencilSurface = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GRenderer* GRenderTargetD3D9Impl::GetRenderer() const
|
||
|
{
|
||
|
return pRenderer;
|
||
|
}
|
||
|
|
||
|
void GRenderTargetD3D9Impl::RemoveFromRenderer()
|
||
|
{
|
||
|
// Clear pRenderer so that CallHandlers passes null
|
||
|
// renderer as an internal argument for Event_RendererReleased.
|
||
|
pRenderer = 0;
|
||
|
|
||
|
// Texture could be in the process of being killed on another
|
||
|
// thread (if its destructor is being called but hasn't had a chance
|
||
|
// to clean us out from the list); if that is the case we can not
|
||
|
// call AddRef to revive the object.
|
||
|
if (AddRef_NotZero())
|
||
|
{
|
||
|
ReleaseResources();
|
||
|
CallHandlers(ChangeHandler::Event_RendererReleased);
|
||
|
if (pNext) // We may have been released by user.
|
||
|
RemoveNode();
|
||
|
Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (pNext) // We may have been released by user.
|
||
|
RemoveNode();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// stores a pointer to the GTextureD3D9Impl that is passed in,
|
||
|
// creates a corresponding depth buffer of the same size.
|
||
|
//
|
||
|
bool GRenderTargetD3D9Impl::InitRenderTarget(GTexture *pTarget, GTexture* pdepth, GTexture* pstencil)
|
||
|
{
|
||
|
ReleaseResources();
|
||
|
pTexture = (GTextureD3DxImpl*)pTarget;
|
||
|
TargetWidth = pTexture->TexWidth;
|
||
|
TargetHeight = pTexture->TexHeight;
|
||
|
if (pTexture && pTexture->pD3DTexture)
|
||
|
pTexture->pD3DTexture->GetSurfaceLevel(0, &pRenderSurface);
|
||
|
else
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(true, "InitRenderTarget used with uninitialized texture");
|
||
|
}
|
||
|
if (pdepth)
|
||
|
pStencilTexture = (GDepthBufferD3D9Impl*)pdepth;
|
||
|
else if (pstencil)
|
||
|
pStencilTexture = (GDepthBufferD3D9Impl*)pstencil;
|
||
|
|
||
|
if (pStencilTexture && pStencilTexture->TextureFormat == D3DFMT_D24S8 && pStencilTexture->pDepthStencil)
|
||
|
{
|
||
|
pStencilSurface = pStencilTexture->pDepthStencil;
|
||
|
pStencilSurface->AddRef();
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Store the render texture and depth buffer that is passed in
|
||
|
//
|
||
|
bool GRenderTargetD3D9Impl::InitRenderTarget(D3D9RenderTargetParams RTParams)
|
||
|
{
|
||
|
pRenderSurface = RTParams.pRenderSurface;
|
||
|
pStencilSurface = RTParams.pStencilSurface;
|
||
|
pTexture = NULL;
|
||
|
|
||
|
GASSERT(pRenderSurface && pStencilSurface);
|
||
|
|
||
|
D3DSURFACE_DESC desc;
|
||
|
pRenderSurface->GetDesc(&desc);
|
||
|
TargetWidth = desc.Width;
|
||
|
TargetHeight = desc.Height;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|