3620 lines
118 KiB
C++
3620 lines
118 KiB
C++
![]() |
/**********************************************************************
|
||
|
|
||
|
Filename : GRendererD3D9Xbox360.cpp
|
||
|
Content : Sample GRenderer implementation for XBox 360
|
||
|
Created : February 8, 2006
|
||
|
Authors :
|
||
|
|
||
|
Copyright : (c) 2001-2005 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 "GHash.h"
|
||
|
#include "GString.h"
|
||
|
#include "GMsgFormat.h"
|
||
|
|
||
|
#if defined(GFC_OS_WIN32)
|
||
|
#include <windows.h>
|
||
|
#endif
|
||
|
|
||
|
#include "GRendererXbox360.h"
|
||
|
#include "GRendererCommonImpl.h"
|
||
|
|
||
|
#include <string.h> // for memset()
|
||
|
|
||
|
|
||
|
#if defined(GFC_BUILD_DEFINE_NEW) && defined(GFC_DEFINE_NEW)
|
||
|
#undef new
|
||
|
#endif
|
||
|
|
||
|
#include <d3d9.h>
|
||
|
#include <d3dx9.h>
|
||
|
#include <xgraphics.h>
|
||
|
|
||
|
#if defined(GFC_BUILD_DEFINE_NEW) && defined(GFC_DEFINE_NEW)
|
||
|
#define new GFC_DEFINE_NEW
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// ***** Classes implemented
|
||
|
class GRendererXbox360Impl;
|
||
|
class GTextureXbox360Impl;
|
||
|
|
||
|
// #define GRENDERER_USE_PS20
|
||
|
#ifdef GRENDERER_USE_PS20
|
||
|
#include "ShadersD3D9/asm20.cpp"
|
||
|
#else
|
||
|
#include "ShadersD3D9/hlsl.cpp"
|
||
|
#endif
|
||
|
|
||
|
#include "D3D9/D3D9Shaders.cpp"
|
||
|
using namespace D3D9;
|
||
|
|
||
|
|
||
|
// ***** GTextureXbox360Impl implementation
|
||
|
|
||
|
// GTextureXbox360Impl declaration
|
||
|
class GTextureXbox360Impl : public GTextureD3D9
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
// Renderer
|
||
|
GRendererXbox360Impl* pRenderer;
|
||
|
SInt TexWidth, TexHeight;
|
||
|
|
||
|
// D3D9 Texture pointer
|
||
|
IDirect3DTexture9* pD3DTexture;
|
||
|
D3DFORMAT TextureFormat;
|
||
|
|
||
|
|
||
|
GTextureXbox360Impl(GRendererXbox360Impl *prenderer);
|
||
|
~GTextureXbox360Impl();
|
||
|
|
||
|
virtual void ReleaseTexture();
|
||
|
|
||
|
// Obtains the renderer that create TextureInfo
|
||
|
virtual GRenderer* GetRenderer() const;
|
||
|
virtual bool IsDataValid() const;
|
||
|
|
||
|
// Texture loading logic.
|
||
|
virtual bool InitTexture(IDirect3DTexture9 *ptex, bool managed);
|
||
|
virtual bool InitTexture(GImageBase* pim, UInt usage);
|
||
|
|
||
|
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);
|
||
|
|
||
|
// Remove texture from renderer, notifies of renderer destruction
|
||
|
void RemoveFromRenderer();
|
||
|
|
||
|
virtual IDirect3DTexture9* GetNativeTexture() const { return pD3DTexture; }
|
||
|
|
||
|
virtual int IsYUVTexture() { return 0; }
|
||
|
virtual void Bind(int stage, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps);
|
||
|
};
|
||
|
|
||
|
class GTextureXbox360ImplYUV : public GTextureXbox360Impl
|
||
|
{
|
||
|
public:
|
||
|
bool IsAlpha;
|
||
|
IDirect3DTexture9* pD3DTextureUVA[3];
|
||
|
|
||
|
GTextureXbox360ImplYUV(GRendererXbox360Impl *prenderer) : GTextureXbox360Impl(prenderer)
|
||
|
{ pD3DTextureUVA[0] = pD3DTextureUVA[1] = pD3DTextureUVA[2] = 0; }
|
||
|
~GTextureXbox360ImplYUV();
|
||
|
|
||
|
virtual bool InitTexture(IDirect3DTexture9 *, bool) { return 0; }
|
||
|
virtual bool InitTexture(GImageBase*, UInt = Usage_Wrap) { return 0; }
|
||
|
virtual bool InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage);
|
||
|
virtual void Update(int, int, const UpdateRect *, const GImageBase *) { }
|
||
|
|
||
|
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 GRenderTargetXbox360Impl : public GRenderTargetD3D9
|
||
|
{
|
||
|
public:
|
||
|
UInt TargetWidth, TargetHeight;
|
||
|
UInt BaseTile, TileSize;
|
||
|
GRendererXbox360Impl* pRenderer;
|
||
|
GPtr<GTextureXbox360Impl> pTexture; // if this is non-null, then pRenderTexture is NULL
|
||
|
IDirect3DSurface9* pRenderSurface; // if this is non-null, then pTexture is NULL
|
||
|
IDirect3DSurface9* pStencilSurface;
|
||
|
|
||
|
GRenderTargetXbox360Impl(GRendererXbox360Impl *pRend);
|
||
|
~GRenderTargetXbox360Impl();
|
||
|
|
||
|
virtual GRenderer* GetRenderer() const;
|
||
|
void RemoveFromRenderer();
|
||
|
void ReleaseResources();
|
||
|
|
||
|
virtual bool InitRenderTarget(D3D9RenderTargetParams RTParams);
|
||
|
virtual bool InitRenderTarget(GTexture *ptarget, UInt base);
|
||
|
virtual bool InitRenderTarget(GTexture *ptarget, GTexture* pdepth = 0, GTexture* pstencil = 0)
|
||
|
{
|
||
|
return InitRenderTarget(ptarget, (UInt)0);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
// ***** Vertex Declarations and Shaders
|
||
|
|
||
|
// 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_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
||
|
{0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
|
||
|
{0, 24, 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()
|
||
|
};
|
||
|
|
||
|
// Vertex shader declarations we can use
|
||
|
enum VDeclType
|
||
|
{
|
||
|
VD_None,
|
||
|
VD_Strip,
|
||
|
VD_Glyph,
|
||
|
VD_XY16iC32,
|
||
|
VD_XY16iCF32,
|
||
|
VD_Count
|
||
|
};
|
||
|
|
||
|
// Vertex declaration lookup table, must correspond to VDeclType +1
|
||
|
static const D3DVERTEXELEMENT9 *VertexDeclTypeTable[VD_Count - 1] =
|
||
|
{
|
||
|
StripVertexDecl,
|
||
|
GlyphVertexDecl,
|
||
|
VertexDeclXY16iC32,
|
||
|
VertexDeclXY16iCF32
|
||
|
};
|
||
|
|
||
|
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 - 1] =
|
||
|
{
|
||
|
pStripVShaderText,
|
||
|
pGlyphVShaderText,
|
||
|
pStripVShaderXY16iC32Text,
|
||
|
pStripVShaderXY16iCF32Text,
|
||
|
pStripVShaderXY16iCF32_T2Text
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
// Vertex buffer structure used for glyphs.
|
||
|
struct GGlyphVertex
|
||
|
{
|
||
|
float x,y,z,w;
|
||
|
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_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,
|
||
|
|
||
|
PS_Count
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
struct PixelShaderDesc
|
||
|
{
|
||
|
// Shader, used if not mull.
|
||
|
const char* pShader;
|
||
|
};
|
||
|
|
||
|
PixelShaderDesc PixelShaderInitTable[PS_Count] =
|
||
|
{
|
||
|
// Non-AA Shaders.
|
||
|
{ pSource_PS_SolidColor},
|
||
|
{ pSource_PS_CxformTexture},
|
||
|
{ pSource_PS_CxformTextureMultiply},
|
||
|
{ pSource_PS_TextTextureAlpha},
|
||
|
{ pSource_PS_TextTextureColor},
|
||
|
{ pSource_PS_TextTextureColorMultiply},
|
||
|
{ pSource_PS_TextTextureYUV},
|
||
|
{ pSource_PS_TextTextureYUVMultiply},
|
||
|
{ pSource_PS_TextTextureYUVA},
|
||
|
{ pSource_PS_TextTextureYUVAMultiply},
|
||
|
|
||
|
// AA Shaders.
|
||
|
{ pSource_PS_CxformGauraud},
|
||
|
{ pSource_PS_CxformGauraudNoAddAlpha},
|
||
|
// Texture stage fixed-function fall-backs only (their implementation is incorrect).
|
||
|
{ pSource_PS_CxformGauraudTexture},
|
||
|
{ pSource_PS_Cxform2Texture},
|
||
|
{ pSource_PS_CxformGauraudMultiply},
|
||
|
{ pSource_PS_CxformGauraudMultiplyNoAddAlpha},
|
||
|
{ pSource_PS_CxformGauraudMultiplyTexture},
|
||
|
{ pSource_PS_CxformMultiply2Texture},
|
||
|
|
||
|
{ pSource_PS_CmatrixTexture},
|
||
|
{ pSource_PS_CmatrixTextureMultiply}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
class GRendererXbox360Impl : public GRendererXbox360
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
// Some renderer state.
|
||
|
bool ModeSet;
|
||
|
SInt RenderMode;
|
||
|
|
||
|
// Shaders and declarations that are currently set.
|
||
|
VDeclType VDeclIndex;
|
||
|
VShaderType VShaderIndex;
|
||
|
|
||
|
// Current pixel shader index
|
||
|
int PShaderIndex;
|
||
|
|
||
|
// Video Mode Configuration Flags (VMConfigFlags)
|
||
|
UInt32 VMCFlags;
|
||
|
|
||
|
// 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];
|
||
|
|
||
|
// Direct3DDevice
|
||
|
IDirect3DDevice9* 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;
|
||
|
DWORD StencilCounter;
|
||
|
bool StencilEnabled;
|
||
|
|
||
|
// Output size.
|
||
|
Float DisplayWidth;
|
||
|
Float DisplayHeight;
|
||
|
|
||
|
Matrix UserMatrix;
|
||
|
Matrix ViewportMatrix;
|
||
|
GViewport ViewRect;
|
||
|
Matrix CurrentMatrix;
|
||
|
Cxform CurrentCxform;
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
bool UVPMatricesChanged;
|
||
|
GMatrix3D ViewMatrix;
|
||
|
GMatrix3D ProjMatrix;
|
||
|
GMatrix3D UVPMatrix;
|
||
|
const GMatrix3D *pWorldMatrix;
|
||
|
#endif
|
||
|
|
||
|
// Link list of all allocated textures
|
||
|
GRendererNode Textures;
|
||
|
GRendererNode RenderTargets;
|
||
|
mutable GLock TexturesLock;
|
||
|
|
||
|
// 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;
|
||
|
|
||
|
// Vertex data pointer
|
||
|
const void* pVertexData;
|
||
|
const void* pIndexData;
|
||
|
VertexFormat VertexFmt;
|
||
|
_D3DFORMAT IndexFmt;
|
||
|
|
||
|
// Current sample mode
|
||
|
BitmapSampleMode SampleMode;
|
||
|
|
||
|
typedef GArrayConstPolicy<0, 4, true> NeverShrinkPolicy;
|
||
|
typedef GArrayLH<BlendType, GStat_Default_Mem, NeverShrinkPolicy> BlendModeStackType;
|
||
|
|
||
|
// Current blend mode
|
||
|
BlendType BlendMode;
|
||
|
BlendModeStackType BlendModeStack;
|
||
|
|
||
|
// render target
|
||
|
struct RTState
|
||
|
{
|
||
|
GRenderTargetXbox360Impl* pRT;
|
||
|
GMatrix2D ViewMatrix;
|
||
|
GMatrix3D ViewMatrix3D;
|
||
|
GMatrix3D PerspMatrix3D;
|
||
|
const GMatrix3D* pWorldMatrix3D;
|
||
|
GViewport ViewRect;
|
||
|
SInt RenderMode;
|
||
|
SInt StencilCounter;
|
||
|
bool StencilEnabled;
|
||
|
|
||
|
RTState() { pRT = 0; pWorldMatrix3D = 0; }
|
||
|
RTState(GRenderTargetXbox360Impl* 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;
|
||
|
|
||
|
GRenderTargetXbox360Impl* pCurRenderTarget;
|
||
|
bool CurRenderTargetSet;
|
||
|
RTStackType RenderTargetStack;
|
||
|
GArrayLH<GPtr<GRenderTargetXbox360Impl> > TempRenderTargets;
|
||
|
|
||
|
// Presentation parameters specified to configure the mode.
|
||
|
D3DPRESENT_PARAMETERS PresentParams;
|
||
|
HWND hWnd;
|
||
|
|
||
|
// Buffer used to pass along glyph vertices
|
||
|
enum { GlyphVertexBufferSize = 6 * 48 };
|
||
|
GGlyphVertex GlyphVertexBuffer[GlyphVertexBufferSize];
|
||
|
|
||
|
// Linked list used for buffer cache testing, otherwise holds no data.
|
||
|
CacheNode CacheList;
|
||
|
|
||
|
// resources to retain during tiling frames
|
||
|
GArray<GPtr<GTexture> > FrameResources;
|
||
|
|
||
|
// all D3D call 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
|
||
|
GArray<IDirect3DResource9*> ResourceReleasingQueue;
|
||
|
GLock ResourceReleasingQueueLock;
|
||
|
|
||
|
// this method is called from GTextureXXX destructor to put a system resource into releasing queue
|
||
|
void AddResourceForReleasing(IDirect3DResource9* 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)
|
||
|
ResourceReleasingQueue[i]->Release();
|
||
|
ResourceReleasingQueue.Clear();
|
||
|
}
|
||
|
|
||
|
GRendererXbox360Impl()
|
||
|
{
|
||
|
ModeSet = 0;
|
||
|
|
||
|
VMCFlags = 0;
|
||
|
|
||
|
StencilAvailable = 0;
|
||
|
StencilChecked = 0;
|
||
|
StencilCounter = 0;
|
||
|
|
||
|
VDeclIndex = VD_None;
|
||
|
VShaderIndex = VS_None;
|
||
|
PShaderIndex = PS_None;
|
||
|
|
||
|
SampleMode = Sample_Linear;
|
||
|
IndexFmt = D3DFMT_UNKNOWN;
|
||
|
VertexFmt = Vertex_None;
|
||
|
|
||
|
pDevice = 0;
|
||
|
hWnd = 0;
|
||
|
|
||
|
pVertexData = 0;
|
||
|
pIndexData = 0;
|
||
|
|
||
|
// Glyph buffer z, w components are always 0 and 1.
|
||
|
UInt i;
|
||
|
for(i = 0; i < GlyphVertexBufferSize; i++)
|
||
|
{
|
||
|
GlyphVertexBuffer[i].z = 0.0f;
|
||
|
GlyphVertexBuffer[i].w = 1.0f;
|
||
|
}
|
||
|
|
||
|
RenderMode = 0;
|
||
|
pCurRenderTarget = 0;
|
||
|
CurRenderTargetSet = 0;
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
pWorldMatrix = 0;
|
||
|
S3DDisplay = StereoCenter;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
~GRendererXbox360Impl()
|
||
|
{
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
void Clear()
|
||
|
{
|
||
|
// Remove/notify all textures
|
||
|
{
|
||
|
GLock::Locker guard(&TexturesLock);
|
||
|
while (Textures.pFirst != &Textures)
|
||
|
((GTextureXbox360Impl*)Textures.pFirst)->RemoveFromRenderer();
|
||
|
|
||
|
while (RenderTargets.pFirst != &RenderTargets)
|
||
|
((GRenderTargetXbox360Impl*)RenderTargets.pFirst)->RemoveFromRenderer();
|
||
|
}
|
||
|
|
||
|
CacheList.ReleaseList();
|
||
|
|
||
|
if (ModeSet)
|
||
|
ResetVideoMode();
|
||
|
|
||
|
ReleaseQueuedResources();
|
||
|
}
|
||
|
|
||
|
void ReleaseResources()
|
||
|
{
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
// 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, "GRendererXbox360 - failed to create vertex declaration");
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool CreateVertexShader(GPtr<IDirect3DVertexShader9> *pshaderPtr, const char* pshaderText)
|
||
|
{
|
||
|
if (!*pshaderPtr)
|
||
|
{
|
||
|
GPtr<ID3DXBuffer> pshader;
|
||
|
HRESULT hr;
|
||
|
|
||
|
#ifdef GRENDERER_VSHADER_PROFILE
|
||
|
hr = D3DXCompileShader(pshaderText, (UInt)strlen(pshaderText),
|
||
|
NULL, NULL, "main", GRENDERER_VSHADER_PROFILE, D3DXSHADER_DEBUG, &pshader.GetRawRef(), NULL, NULL);
|
||
|
#else
|
||
|
hr = D3DXAssembleShader(pshaderText, (UInt)strlen(pshaderText),
|
||
|
NULL, NULL, Xbox360SHADER_DEBUG, &pshader.GetRawRef(), NULL);
|
||
|
#endif
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
return 0;
|
||
|
|
||
|
if (!pshader ||
|
||
|
((hr = pDevice->CreateVertexShader( (DWORD*)pshader->GetBufferPointer(),
|
||
|
&pshaderPtr->GetRawRef())) != S_OK) )
|
||
|
{
|
||
|
GFC_DEBUG_WARNING1(1, "GRendererXbox360 - Can't create D3D9 vshader; error code = %d", hr);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
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", GRENDERER_PSHADER_PROFILE, D3DXSHADER_DEBUG, &pshader.GetRawRef(), &pmsg.GetRawRef(), NULL);
|
||
|
#else
|
||
|
hr = D3DXAssembleShader(pshaderText, (UInt)strlen(pshaderText),
|
||
|
NULL, NULL, Xbox360SHADER_DEBUG, &pshader.GetRawRef(), &pmsg.GetRawRef());
|
||
|
#endif
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
GFC_DEBUG_WARNING1(1, "GRendererXbox360 - PixelShader errors:\n %s ", pmsg->GetBufferPointer() );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (!pshader ||
|
||
|
((hr = pDevice->CreatePixelShader( (DWORD*)pshader->GetBufferPointer(),
|
||
|
&pshaderPtr->GetRawRef())) != S_OK) )
|
||
|
{
|
||
|
GFC_DEBUG_WARNING1(1, "GRendererXbox360 - Can't create D3D9 pshader; error code = %d", hr);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Initialize the vshader we use for SWF mesh rendering.
|
||
|
bool InitShaders()
|
||
|
{
|
||
|
bool success = 1;
|
||
|
UInt i;
|
||
|
|
||
|
for (i = 1; i < VD_Count; i++)
|
||
|
if (!CreateVertexDeclaration(&VertexDecls[i], VertexDeclTypeTable[i-1]))
|
||
|
{
|
||
|
success = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
for (i = 1; i < VS_Count; i++)
|
||
|
if (!CreateVertexShader(&VertexShaders[i], VertexShaderTextTable[i-1]))
|
||
|
{
|
||
|
success = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
for (i = 1; i < PS_Count; i++)
|
||
|
{
|
||
|
if (PixelShaderInitTable[i-1].pShader)
|
||
|
{
|
||
|
if (!CreatePixelShader(&PixelShaders[i], PixelShaderInitTable[i-1].pShader))
|
||
|
{
|
||
|
success = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for (int i = 0; i < FS2_FCMatrix; i++)
|
||
|
if (FShaderSources2[i])
|
||
|
{
|
||
|
if (!CreatePixelShader(&StaticFilterShaders[i], FShaderSources2[i]))
|
||
|
{
|
||
|
success = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!success)
|
||
|
{
|
||
|
ReleaseShaders();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ReleaseShaders()
|
||
|
{
|
||
|
if (pDevice)
|
||
|
{
|
||
|
pDevice->SetVertexShader(0);
|
||
|
pDevice->SetPixelShader(0);
|
||
|
pDevice->SetVertexDeclaration(0);
|
||
|
}
|
||
|
|
||
|
UInt i;
|
||
|
for (i=0; i< VD_Count; i++)
|
||
|
if (VertexDecls[i])
|
||
|
VertexDecls[i] = 0;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// Sets a shader to specified type.
|
||
|
void SetVertexDecl(VDeclType vd)
|
||
|
{
|
||
|
if (VDeclIndex != vd)
|
||
|
{
|
||
|
VDeclIndex = vd;
|
||
|
pDevice->SetVertexDeclaration(VertexDecls[vd]);
|
||
|
}
|
||
|
}
|
||
|
void SetVertexShader(VShaderType vt)
|
||
|
{
|
||
|
if (VShaderIndex != vt)
|
||
|
{
|
||
|
VShaderIndex = vt;
|
||
|
pDevice->SetVertexShader(VertexShaders[vt]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Set shader to a device based on a constant
|
||
|
void SetPixelShader(PixelShaderType shaderType)
|
||
|
{
|
||
|
if (shaderType != PShaderIndex)
|
||
|
{
|
||
|
pDevice->SetPixelShader(PixelShaders[shaderType]);
|
||
|
PShaderIndex = shaderType;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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;
|
||
|
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 (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);
|
||
|
}
|
||
|
|
||
|
// 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
|
||
|
|
||
|
GTextureXbox360Impl* ptexture = ((GTextureXbox360Impl*)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->SetVertexShaderConstantF(matrixVertexConstIndex, p, 1);
|
||
|
|
||
|
p[0] = m.M_[1][0];
|
||
|
p[1] = m.M_[1][1];
|
||
|
p[3] = m.M_[1][2];
|
||
|
pDevice->SetVertexShaderConstantF(matrixVertexConstIndex + 1, p, 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
void ApplyPShaderCxform(const Cxform &cxform, UInt cxformPShaderConstIndex) const
|
||
|
{
|
||
|
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->SetPixelShaderConstantF(cxformPShaderConstIndex, cxformData, 2);
|
||
|
}
|
||
|
|
||
|
|
||
|
class GFxFillStyle
|
||
|
{
|
||
|
public:
|
||
|
enum FillMode
|
||
|
{
|
||
|
FM_None,
|
||
|
FM_Color,
|
||
|
FM_Bitmap,
|
||
|
FM_Gouraud
|
||
|
};
|
||
|
|
||
|
FillMode Mode;
|
||
|
|
||
|
GouraudFillType GouraudType;
|
||
|
GColor Color;
|
||
|
|
||
|
Cxform BitmapColorTransform;
|
||
|
|
||
|
FillTexture Fill;
|
||
|
FillTexture Fill2;
|
||
|
|
||
|
|
||
|
GFxFillStyle()
|
||
|
{
|
||
|
Mode = FM_None;
|
||
|
GouraudType = GFill_Color;
|
||
|
Fill.pTexture = 0;
|
||
|
Fill2.pTexture = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Push our style into Direct3D
|
||
|
void Apply(GRendererXbox360Impl *prenderer) const
|
||
|
{
|
||
|
IDirect3DDevice9* 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)
|
||
|
{
|
||
|
// Gradient and texture fills.
|
||
|
GASSERT(Fill.pTexture != NULL);
|
||
|
|
||
|
prenderer->ApplyColor(Color);
|
||
|
prenderer->ApplySampleMode(Fill.SampleMode);
|
||
|
|
||
|
|
||
|
if (Fill.pTexture == NULL)
|
||
|
{
|
||
|
// Just in case, for release build.
|
||
|
prenderer->SetPixelShader(PS_None);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pdevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||
|
|
||
|
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->VertexFmt == 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
|
||
|
{
|
||
|
GASSERT(prenderer->VertexFmt != Vertex_XY16i);
|
||
|
shader = PS_CxformGauraud;
|
||
|
}
|
||
|
|
||
|
prenderer->ApplyPShaderCxform(BitmapColorTransform, 2);
|
||
|
|
||
|
}
|
||
|
|
||
|
// We have a textured or multi-textured gouraud case.
|
||
|
else
|
||
|
{
|
||
|
|
||
|
pdevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||
|
|
||
|
prenderer->ApplyPShaderCxform(BitmapColorTransform, 2);
|
||
|
// 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 5 and 6
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Disable()
|
||
|
{
|
||
|
Mode = FM_None;
|
||
|
Fill.pTexture = 0;
|
||
|
}
|
||
|
void SetColor(GColor color)
|
||
|
{
|
||
|
Mode = FM_Color; Color = color;
|
||
|
}
|
||
|
|
||
|
void SetCxform(const Cxform& colorTransform)
|
||
|
{
|
||
|
BitmapColorTransform = colorTransform;
|
||
|
}
|
||
|
|
||
|
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.
|
||
|
GTextureD3D9* CreateTexture()
|
||
|
{
|
||
|
ReleaseQueuedResources();
|
||
|
GLock::Locker guard(&TexturesLock);
|
||
|
return new GTextureXbox360Impl(this);
|
||
|
}
|
||
|
|
||
|
GTextureD3D9* CreateTextureYUV()
|
||
|
{
|
||
|
ReleaseQueuedResources();
|
||
|
GLock::Locker guard(&TexturesLock);
|
||
|
return new GTextureXbox360ImplYUV(this);
|
||
|
}
|
||
|
|
||
|
GTextureD3D9* CreateDepthStencilBuffer()
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// Helper function to query renderer capabilities.
|
||
|
bool GetRenderCaps(RenderCaps *pcaps)
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererXBox360::GetRenderCaps fails - video mode not set");
|
||
|
pcaps->CapBits |= Cap_NoTexOverwrite;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
pcaps->CapBits = Cap_Index16 | Cap_Index32 |
|
||
|
Cap_FillGouraud |Cap_FillGouraudTex |
|
||
|
Cap_CxformAdd | Cap_NestedMasks |
|
||
|
Cap_TexNonPower2 | Cap_TexNonPower2Wrap | Cap_TexNonPower2Mip |
|
||
|
Cap_RenderTargetPrePass | Cap_RenderTargetNonPow2 |
|
||
|
Cap_Filter_ColorMatrix | Cap_Filter_Blurs;
|
||
|
|
||
|
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 (VMCFlags & VMConfig_SupportTiling)
|
||
|
pcaps->CapBits |= Cap_NoTexOverwrite;
|
||
|
|
||
|
D3DCAPS9 caps9;
|
||
|
pDevice->GetDeviceCaps(&caps9);
|
||
|
pcaps->MaxTextureSize = G_Min(caps9.MaxTextureWidth, caps9.MaxTextureWidth);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void EndFrame()
|
||
|
{
|
||
|
FrameResources.Clear();
|
||
|
GRenderer::EndFrame();
|
||
|
}
|
||
|
|
||
|
void PushRenderTarget(const GRectF& frameRect, GRenderTarget* prt)
|
||
|
{
|
||
|
GASSERT(RenderTargetStack.GetSize() == 0 ||
|
||
|
(CurRenderTargetSet == 0 && RenderTargetStack.GetSize() == 1));
|
||
|
|
||
|
if (!pCurRenderTarget)
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererXbox360: SetDisplayRenderTarget not called, render targets unavailable");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// push onto RT stack
|
||
|
RenderTargetStack.PushBack(RTState(pCurRenderTarget, ViewportMatrix,
|
||
|
#ifndef GFC_NO_3D
|
||
|
ViewMatrix, ProjMatrix, pWorldMatrix,
|
||
|
#else
|
||
|
GMatrix3D(), GMatrix3D(), 0,
|
||
|
#endif
|
||
|
ViewRect, RenderMode, StencilCounter, StencilEnabled));
|
||
|
pCurRenderTarget = (GRenderTargetXbox360Impl*)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);
|
||
|
|
||
|
RenderMode = GViewport::View_AlphaComposite;
|
||
|
StencilEnabled = 0;
|
||
|
|
||
|
CurRenderTargetSet = 0;
|
||
|
}
|
||
|
|
||
|
void CheckRenderTarget()
|
||
|
{
|
||
|
if (CurRenderTargetSet || !pCurRenderTarget)
|
||
|
return;
|
||
|
|
||
|
// 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);
|
||
|
}
|
||
|
|
||
|
pDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
|
||
|
|
||
|
D3DVIEWPORT9 vp;
|
||
|
vp.MinZ = 0.0f;
|
||
|
vp.MaxZ = 1.0f;
|
||
|
|
||
|
if (pCurRenderTarget->pTexture)
|
||
|
{
|
||
|
vp.X = 0;
|
||
|
vp.Y = 0;
|
||
|
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.X = ViewRect.Left;
|
||
|
vp.Y = ViewRect.Top;
|
||
|
vp.Width = ViewRect.Width;
|
||
|
vp.Height = ViewRect.Height;
|
||
|
pDevice->SetViewport(&vp);
|
||
|
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
if (StencilEnabled)
|
||
|
{
|
||
|
pDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
|
||
|
EndSubmitMask();
|
||
|
}
|
||
|
else
|
||
|
DisableMask();
|
||
|
|
||
|
CurRenderTargetSet = 1;
|
||
|
}
|
||
|
|
||
|
void PopRenderTarget()
|
||
|
{
|
||
|
if (!pCurRenderTarget)
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererXbox360: SetDisplayRenderTarget not called, render targets unavailable");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (CurRenderTargetSet)
|
||
|
pDevice->Resolve(D3DRESOLVE_RENDERTARGET0, NULL, pCurRenderTarget->pTexture->pD3DTexture, NULL, 0, 0, NULL, 1.f, 0, NULL);
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
CurRenderTargetSet = 0;
|
||
|
}
|
||
|
|
||
|
GTextureXbox360Impl* PushTempRenderTarget(const GRectF& frameRect, UInt inw, UInt inh, bool needStencil = 0)
|
||
|
{
|
||
|
GUNUSED(needStencil);
|
||
|
|
||
|
GRenderTargetXbox360Impl* pRT = 0;
|
||
|
UInt w = 1, h = 1;
|
||
|
|
||
|
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 done;
|
||
|
}
|
||
|
|
||
|
while (w < inw) w <<= 1;
|
||
|
while (h < inh) h <<= 1;
|
||
|
|
||
|
for (UInt i = 0; i < TempRenderTargets.GetSize(); i++)
|
||
|
if (TempRenderTargets[i]->pTexture->GetRefCount() <= 1)
|
||
|
{
|
||
|
pDevice->SetTexture(0, NULL);
|
||
|
pDevice->SetTexture(1, NULL);
|
||
|
|
||
|
pRT = TempRenderTargets[i];
|
||
|
pRT->pTexture->InitDynamicTexture(w, h, GImage::Image_ARGB_8888, 0, GTexture::Usage_RenderTarget);
|
||
|
// should use handlers instead
|
||
|
pRT->InitRenderTarget(pRT->pTexture);
|
||
|
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
GTexture* prtt = CreateTexture();
|
||
|
prtt->InitDynamicTexture(w, h, GImage::Image_ARGB_8888, 0, GTexture::Usage_RenderTarget);
|
||
|
pRT = (GRenderTargetXbox360Impl *)CreateRenderTarget();
|
||
|
pRT->InitRenderTarget(prtt);
|
||
|
TempRenderTargets.PushBack(*pRT);
|
||
|
prtt->Release();
|
||
|
}
|
||
|
done:
|
||
|
pRT->TargetWidth = inw;
|
||
|
pRT->TargetHeight = inh;
|
||
|
PushRenderTarget(frameRect, pRT);
|
||
|
return pRT->pTexture;
|
||
|
}
|
||
|
|
||
|
void ReleaseTempRenderTargets(UInt keepArea)
|
||
|
{
|
||
|
GArray<GPtr<GRenderTargetXbox360Impl> > NewTempRenderTargets;
|
||
|
|
||
|
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());
|
||
|
}
|
||
|
|
||
|
GRenderTargetXbox360Impl* CreateRenderTarget()
|
||
|
{
|
||
|
return new GRenderTargetXbox360Impl(this);
|
||
|
}
|
||
|
|
||
|
void SetDisplayRenderTarget(GRenderTarget *renderTarget, bool bSetState)
|
||
|
{
|
||
|
GASSERT(RenderTargetStack.GetSize() == 0);
|
||
|
pCurRenderTarget = (GRenderTargetXbox360Impl*)renderTarget;
|
||
|
if (bSetState)
|
||
|
{
|
||
|
pDevice->SetRenderTarget(0, pCurRenderTarget->pRenderSurface);
|
||
|
pDevice->SetDepthStencilSurface(pCurRenderTarget->pStencilSurface);
|
||
|
}
|
||
|
CurRenderTargetSet = 1;
|
||
|
}
|
||
|
|
||
|
UInt CheckFilterSupport(const BlurFilterParams& params)
|
||
|
{
|
||
|
UInt flags = FilterSupport_Ok;
|
||
|
// blurs/shadows may be scaled up and require multiple passes, but were sorted into prepass and main pass when set.
|
||
|
if (params.Passes > 1 || (params.Mode & (Filter_Blur|Filter_Shadow)))
|
||
|
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<GTextureXbox360Impl> psrcinRef = (GTextureXbox360Impl*)psrcin;
|
||
|
GPtr<GTextureXbox360Impl> psrc = (GTextureXbox360Impl*)psrcin;
|
||
|
GRectF srcrect, destrect(-1,-1,1,1);
|
||
|
|
||
|
UInt n = params.Passes;
|
||
|
|
||
|
BlurFilterParams pass[3];
|
||
|
FragShaderType2 passis[3];
|
||
|
|
||
|
pass[0] = params;
|
||
|
pass[1] = params;
|
||
|
pass[2] = params;
|
||
|
|
||
|
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;
|
||
|
|
||
|
UInt bufWidth = (UInt)ceilf(insrcrect.Width());
|
||
|
UInt bufHeight = (UInt)ceilf(insrcrect.Height());
|
||
|
UInt last = n-1;
|
||
|
|
||
|
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];
|
||
|
|
||
|
pDevice->SetPixelShader(StaticFilterShaders[passis[passi]]);
|
||
|
|
||
|
GTextureXbox360Impl* pnextsrc;
|
||
|
if (i != n - 1)
|
||
|
{
|
||
|
pnextsrc = PushTempRenderTarget(GRectF(-1,-1,1,1), bufWidth, bufHeight);
|
||
|
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);
|
||
|
|
||
|
CheckRenderTarget();
|
||
|
|
||
|
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;
|
||
|
|
||
|
Float uniforms[32];
|
||
|
|
||
|
if (FShaderUniforms[passis[passi]][FSU_cxadd] >= 0)
|
||
|
{
|
||
|
if (i == n - 1)
|
||
|
{
|
||
|
float cxformData[4 * 2] =
|
||
|
{
|
||
|
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],
|
||
|
|
||
|
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
|
||
|
};
|
||
|
|
||
|
SetUniform(uniforms, passis[passi], FSU_cxmul, cxformData, 4);
|
||
|
SetUniform(uniforms, passis[passi], FSU_cxadd, cxformData+4, 4);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const float add[] = {0,0,0,0};
|
||
|
const float mul[] = {1,1,1,1};
|
||
|
SetUniform(uniforms, passis[passi], FSU_cxmul, mul, 4);
|
||
|
SetUniform(uniforms, passis[passi], FSU_cxadd, add, 4);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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(0, uniforms, 8);
|
||
|
|
||
|
psrc->Bind(FShaderUniforms[passis[passi]][FSU_tex], Wrap_Clamp, Sample_Linear, false);
|
||
|
if (FShaderUniforms[passis[passi]][FSU_srctex] >= 0)
|
||
|
((GTextureXbox360Impl*)psrcin)->Bind(FShaderUniforms[passis[passi]][FSU_srctex], Wrap_Clamp, Sample_Linear, false);
|
||
|
|
||
|
GColor w;
|
||
|
GGlyphVertex strip[4] =
|
||
|
{
|
||
|
{ destrect.Left, destrect.Top, 0,1, srcrect.Left, srcrect.Top, w},
|
||
|
{ destrect.Right, destrect.Top, 0,1, srcrect.Right, srcrect.Top, w},
|
||
|
{ destrect.Left, destrect.Bottom, 0,1, srcrect.Left, srcrect.Bottom, w},
|
||
|
{ destrect.Right, destrect.Bottom,0,1, srcrect.Right, srcrect.Bottom, w}
|
||
|
};
|
||
|
|
||
|
pDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, strip, sizeof(GGlyphVertex));
|
||
|
|
||
|
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);
|
||
|
CheckRenderTarget();
|
||
|
|
||
|
GTextureXbox360Impl* psrc = (GTextureXbox360Impl*) psrcin;
|
||
|
if (BlendMode == Blend_Multiply || BlendMode == Blend_Darken)
|
||
|
SetPixelShader(PS_CmatrixTextureMultiply);
|
||
|
else
|
||
|
SetPixelShader(PS_CmatrixTexture);
|
||
|
SetVertexDecl(VD_Glyph);
|
||
|
SetVertexShader(VS_Glyph);
|
||
|
PShaderIndex = (PixelShaderType)~0;
|
||
|
|
||
|
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->SetPixelShaderConstantF(0, matrix, 4);
|
||
|
pDevice->SetPixelShaderConstantF(4, matrix+16, 1);
|
||
|
|
||
|
ApplyBlendMode(BlendMode, false, true);
|
||
|
|
||
|
GColor w(0xffffffff);
|
||
|
GGlyphVertex strip[4] =
|
||
|
{
|
||
|
{ destrect.Left, destrect.Top, 0,1, srcrect.Left, srcrect.Top, w},
|
||
|
{ destrect.Right, destrect.Top, 0,1, srcrect.Right, srcrect.Top, w},
|
||
|
{ destrect.Left, destrect.Bottom, 0,1, srcrect.Left, srcrect.Bottom, w},
|
||
|
{ destrect.Right, destrect.Bottom,0,1, srcrect.Right, srcrect.Bottom, w}
|
||
|
};
|
||
|
|
||
|
pDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, strip, sizeof(GGlyphVertex));
|
||
|
|
||
|
pDevice->SetTexture(0, NULL);
|
||
|
pDevice->SetTexture(1, NULL);
|
||
|
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 (ViewportX0, ViewportY0, ViewportX0 +
|
||
|
// ViewportWidth, ViewportY0 + 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, "GRendererD3D9::BeginDisplay failed - video mode not set");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CheckRenderTarget();
|
||
|
|
||
|
RenderMode = (vpin.Flags & GViewport::View_AlphaComposite);
|
||
|
|
||
|
DisplayWidth = fabsf(x1 - x0);
|
||
|
DisplayHeight = fabsf(y1 - y0);
|
||
|
|
||
|
// 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) vpin.BufferWidth)
|
||
|
{
|
||
|
clipX1 = x0 + ((vpin.BufferWidth - viewportX0_save) * dx) / (float) viewportW_save;
|
||
|
viewport.Width = vpin.BufferWidth - 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) vpin.BufferHeight)
|
||
|
{
|
||
|
clipY1 = y0 + ((vpin.BufferHeight - viewportY0_save) * dy) / (float) viewportH_save;
|
||
|
viewport.Height = vpin.BufferHeight - viewport.Top;
|
||
|
}
|
||
|
|
||
|
dx = clipX1 - clipX0;
|
||
|
dy = clipY1 - clipY0;
|
||
|
|
||
|
// Viewport.
|
||
|
D3DVIEWPORT9 vp;
|
||
|
|
||
|
vp.MinZ = 0.0f;
|
||
|
vp.MaxZ = 0.0f;
|
||
|
|
||
|
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);
|
||
|
|
||
|
ViewRect = viewport;
|
||
|
|
||
|
ViewportMatrix.SetIdentity();
|
||
|
ViewportMatrix.M_[0][0] = 2.0f / dx;
|
||
|
ViewportMatrix.M_[1][1] = -2.0f / dy;
|
||
|
|
||
|
// 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 *= 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.
|
||
|
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);
|
||
|
SampleMode = Sample_Linear;
|
||
|
pDevice->SetSamplerState(0, D3DSAMP_MIPMAPLODBIAS, bias.d );
|
||
|
|
||
|
// No ZWRITE by default
|
||
|
pDevice->SetRenderState(D3DRS_ZWRITEENABLE, 0);
|
||
|
pDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||
|
pDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
|
||
|
|
||
|
pDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
|
||
|
pDevice->SetRenderState(D3DRS_SCISSORTESTENABLE,FALSE);
|
||
|
|
||
|
// Turn of back-face culling.
|
||
|
pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||
|
|
||
|
pDevice->SetTexture(0, 0);
|
||
|
pDevice->SetTexture(1, 0); // No texture
|
||
|
|
||
|
// 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);
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
pWorldMatrix = 0;
|
||
|
#endif
|
||
|
|
||
|
// Init test for depth-stencil presence.
|
||
|
StencilChecked = 0;
|
||
|
StencilAvailable= 0;
|
||
|
StencilCounter = 0;
|
||
|
StencilEnabled = 0;
|
||
|
|
||
|
// Clear the background, if background color has alpha > 0.
|
||
|
if (backgroundColor.GetAlpha() > 0)
|
||
|
{
|
||
|
// @@ for testing
|
||
|
/*
|
||
|
static SInt testColor = 0;
|
||
|
pDevice->Clear(
|
||
|
0,
|
||
|
NULL,
|
||
|
D3DCLEAR_TARGET | (StencilAvailable ? (D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL) : 0),
|
||
|
testColor += 5,
|
||
|
0.0f,
|
||
|
0);
|
||
|
*/
|
||
|
|
||
|
// Draw a big quad.
|
||
|
ApplyColor(backgroundColor);
|
||
|
SetMatrix(Matrix::Identity);
|
||
|
ApplyMatrix(CurrentMatrix);
|
||
|
|
||
|
// 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 }
|
||
|
};
|
||
|
|
||
|
pDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, strip, sizeof(Vertex));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// 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);
|
||
|
SetVertexShader(VS_None);
|
||
|
pDevice->SetTexture(0,0);
|
||
|
|
||
|
if (!(VMCFlags&VMConfig_NoSceneCalls))
|
||
|
pDevice->EndScene();
|
||
|
}
|
||
|
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
|
||
|
UVPMatricesChanged = 1;
|
||
|
#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 *??
|
||
|
};
|
||
|
|
||
|
// For debug build
|
||
|
GASSERT(((UInt) mode) < 15);
|
||
|
// For release
|
||
|
if (((UInt) mode) >= 15)
|
||
|
mode = Blend_None;
|
||
|
|
||
|
if (!pDevice)
|
||
|
return;
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ApplySampleMode(BitmapSampleMode mode)
|
||
|
{
|
||
|
if (SampleMode != mode)
|
||
|
{
|
||
|
SampleMode = mode;
|
||
|
_D3DTEXTUREFILTERTYPE filter =
|
||
|
(mode == Sample_Point) ? D3DTEXF_POINT : D3DTEXF_LINEAR;
|
||
|
pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, filter);
|
||
|
pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, filter);
|
||
|
|
||
|
pDevice->SetSamplerState(1, D3DSAMP_MINFILTER, filter);
|
||
|
pDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, filter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// 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, "GRendererD3D9::PopBlendMode - blend mode stack is empty");
|
||
|
}
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
virtual void SetPerspective3D(const GMatrix3D &projMatIn)
|
||
|
{
|
||
|
ProjMatrix = projMatIn;
|
||
|
UVPMatricesChanged = 1;
|
||
|
}
|
||
|
|
||
|
virtual void SetView3D(const GMatrix3D &viewMatIn)
|
||
|
{
|
||
|
ViewMatrix = viewMatIn;
|
||
|
UVPMatricesChanged = 1;
|
||
|
}
|
||
|
|
||
|
virtual void SetWorld3D(const GMatrix3D *pWorldMatIn)
|
||
|
{
|
||
|
pWorldMatrix = pWorldMatIn;
|
||
|
}
|
||
|
|
||
|
virtual void SetStereoDisplay(StereoDisplay sDisplay, bool setstate)
|
||
|
{
|
||
|
S3DDisplay = sDisplay;
|
||
|
UVPMatricesChanged = 1;
|
||
|
|
||
|
GASSERT(!setstate);
|
||
|
}
|
||
|
|
||
|
void UpdateStereoProjection()
|
||
|
{
|
||
|
Float eyeZ = -ViewMatrix.M_[3][2];
|
||
|
if (S3DDisplay == StereoLeft)
|
||
|
{
|
||
|
GMatrix3D left;
|
||
|
GetStereoProjectionMatrix(&left, NULL, ProjMatrix, eyeZ);
|
||
|
ProjMatrix = left;
|
||
|
}
|
||
|
else
|
||
|
if (S3DDisplay == StereoRight)
|
||
|
{
|
||
|
GMatrix3D right;
|
||
|
GetStereoProjectionMatrix(NULL, &right, ProjMatrix, eyeZ);
|
||
|
ProjMatrix = right;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// multiply current GRenderer::Matrix with d3d GRenderer::Matrix
|
||
|
void ApplyMatrix(const Matrix& matIn)
|
||
|
{
|
||
|
#ifndef GFC_NO_3D
|
||
|
if (pWorldMatrix)
|
||
|
{
|
||
|
if (UVPMatricesChanged)
|
||
|
{
|
||
|
UpdateStereoProjection();
|
||
|
UVPMatricesChanged = 0;
|
||
|
UVPMatrix = UserMatrix;
|
||
|
UVPMatrix.Append(ViewMatrix);
|
||
|
UVPMatrix.Append(ProjMatrix);
|
||
|
|
||
|
if (RenderTargetStack.GetSize())
|
||
|
Adjust3DMatrixForRT(UVPMatrix, ProjMatrix, RenderTargetStack[0].ViewMatrix, ViewportMatrix);
|
||
|
}
|
||
|
|
||
|
GMatrix3D Final = GMatrix3D(matIn);
|
||
|
Final.Append(*pWorldMatrix);
|
||
|
Final.Append(UVPMatrix);
|
||
|
Final.Transpose();
|
||
|
pDevice->SetVertexShaderConstantF(0, Final, 4);
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
{
|
||
|
Matrix m(ViewportMatrix);
|
||
|
m.Prepend(matIn);
|
||
|
|
||
|
float row0[4];
|
||
|
float row1[4];
|
||
|
float row2[4];
|
||
|
float row3[4];
|
||
|
|
||
|
row0[0] = m.M_[0][0];
|
||
|
row0[1] = m.M_[0][1];
|
||
|
row0[2] = 0;
|
||
|
row0[3] = m.M_[0][2];
|
||
|
|
||
|
row1[0] = m.M_[1][0];
|
||
|
row1[1] = m.M_[1][1];
|
||
|
row1[2] = 0;
|
||
|
row1[3] = m.M_[1][2];
|
||
|
|
||
|
row2[0] = 0;
|
||
|
row2[1] = 0;
|
||
|
row2[2] = 1.0f;
|
||
|
row2[3] = 0;
|
||
|
|
||
|
row3[0] = 0;
|
||
|
row3[1] = 0;
|
||
|
row3[2] = 0;
|
||
|
row3[3] = 1.0f;
|
||
|
|
||
|
pDevice->SetVertexShaderConstantF(0, row0, 1);
|
||
|
pDevice->SetVertexShaderConstantF(1, row1, 1);
|
||
|
|
||
|
pDevice->SetVertexShaderConstantF(2, row2, 1);
|
||
|
pDevice->SetVertexShaderConstantF(3, row3, 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set the given color.
|
||
|
void ApplyColor(GColor c)
|
||
|
{
|
||
|
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->SetPixelShaderConstantF(0, rgba, 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
// 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)
|
||
|
{
|
||
|
pVertexData = pvertices;
|
||
|
VertexFmt = vf;
|
||
|
// Note: this could populate a static/dynamic buffer instead (if not null).
|
||
|
|
||
|
// 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)
|
||
|
{
|
||
|
pIndexData = pindices;
|
||
|
switch(idxf)
|
||
|
{
|
||
|
case Index_None: IndexFmt = D3DFMT_UNKNOWN; break;
|
||
|
case Index_16: IndexFmt = D3DFMT_INDEX16; break;
|
||
|
case Index_32: IndexFmt = D3DFMT_INDEX32; break;
|
||
|
}
|
||
|
// Note: this could populate a dynamic buffer instead (if not null).
|
||
|
|
||
|
// Test cache buffer management support.
|
||
|
CacheList.VerifyCachedData( this, pcache, CacheNode::Buffer_Index, (pindices!=0),
|
||
|
numIndices, (((pindices!=0)&&numIndices) ? *((SInt16*)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;
|
||
|
if (!pVertexData || !pIndexData || (IndexFmt == D3DFMT_UNKNOWN)) // Must have vertex data.
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(!pVertexData, "GRendererXBox360::DrawIndexedTriList failed, vertex data not specified");
|
||
|
GFC_DEBUG_WARNING(!pIndexData, "GRendererXBox360::DrawIndexedTriList failed, index data not specified");
|
||
|
GFC_DEBUG_WARNING((IndexFmt == D3DFMT_UNKNOWN), "GRendererXBox360::DrawIndexedTriList failed, index buffer format not specified");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CheckRenderTarget();
|
||
|
|
||
|
bool isGouraud = (CurrentStyles[FILL_STYLE].Mode == GFxFillStyle::FM_Gouraud);
|
||
|
int vertexSize= 2 * sizeof(SInt16);
|
||
|
|
||
|
// Ensure we have the right vertex size.
|
||
|
// MA: Should loosen some rules to allow for other decl/shader combinations?
|
||
|
if (isGouraud)
|
||
|
{
|
||
|
if (VertexFmt == Vertex_XY16iC32)
|
||
|
{
|
||
|
SetVertexDecl(VD_XY16iC32);
|
||
|
SetVertexShader(VS_XY16iC32);
|
||
|
vertexSize = sizeof(VertexXY16iC32);
|
||
|
}
|
||
|
else if (VertexFmt == Vertex_XY16iCF32)
|
||
|
{
|
||
|
SetVertexDecl(VD_XY16iCF32);
|
||
|
|
||
|
if (CurrentStyles[FILL_STYLE].GouraudType != GFill_2Texture)
|
||
|
SetVertexShader(VS_XY16iCF32);
|
||
|
else
|
||
|
SetVertexShader(VS_XY16iCF32_T2);
|
||
|
|
||
|
vertexSize = sizeof(VertexXY16iCF32);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetVertexDecl(VD_Strip);
|
||
|
SetVertexShader(VS_Strip);
|
||
|
|
||
|
GASSERT(VertexFmt == Vertex_XY16i);
|
||
|
vertexSize= 2 * sizeof(SInt16);
|
||
|
}
|
||
|
|
||
|
// Set up current style.
|
||
|
CurrentStyles[FILL_STYLE].Apply(this);
|
||
|
|
||
|
ApplyMatrix(CurrentMatrix);
|
||
|
|
||
|
// TODO - should use a VB instead, and use DrawPrimitive().
|
||
|
// or at least use a Dynamic buffer for now...
|
||
|
const int bytesInIndex = ((IndexFmt == D3DFMT_INDEX16) ? sizeof(UInt16) : sizeof(UInt32));
|
||
|
const UByte* pindices = (UByte*)pIndexData + startIndex * bytesInIndex;
|
||
|
|
||
|
// Draw the mesh.
|
||
|
// XBox360 refuses to render more than 65535 indexes.
|
||
|
const int maxTriangles = 65535/3;
|
||
|
|
||
|
RenderStats.Triangles += triangleCount;
|
||
|
TriangleCnt.AddCount(triangleCount);
|
||
|
while (triangleCount > maxTriangles)
|
||
|
{
|
||
|
pDevice->DrawIndexedPrimitiveUP(
|
||
|
D3DPT_TRIANGLELIST, minVertexIndex, numVertices, maxTriangles,
|
||
|
pindices, IndexFmt,
|
||
|
((UByte*)pVertexData) + baseVertexIndex * vertexSize,
|
||
|
vertexSize );
|
||
|
|
||
|
triangleCount -= maxTriangles;
|
||
|
pindices += bytesInIndex * maxTriangles * 3;
|
||
|
RenderStats.Primitives++;
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
}
|
||
|
|
||
|
if (triangleCount > 0)
|
||
|
{
|
||
|
pDevice->DrawIndexedPrimitiveUP(
|
||
|
D3DPT_TRIANGLELIST, minVertexIndex, numVertices, triangleCount,
|
||
|
pindices, IndexFmt,
|
||
|
((UByte*)pVertexData) + baseVertexIndex * vertexSize,
|
||
|
vertexSize );
|
||
|
|
||
|
RenderStats.Primitives++;
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
// Draw the line strip formed by the sequence of points.
|
||
|
void DrawLineStrip(int baseVertexIndex, int lineCount)
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
return;
|
||
|
|
||
|
if (!pVertexData) // Must have vertex data.
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(!pVertexData, "GRendererXBox360::DrawLineStrip failed, vertex data not specified");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CheckRenderTarget();
|
||
|
|
||
|
// MA: Should loosen some rules to allow for other decl/shader combinations?
|
||
|
GASSERT(VertexFmt == Vertex_XY16i);
|
||
|
SetVertexDecl(VD_Strip);
|
||
|
SetVertexShader(VS_Strip);
|
||
|
|
||
|
// Set up current style.
|
||
|
CurrentStyles[LINE_STYLE].Apply(this);
|
||
|
|
||
|
ApplyMatrix(CurrentMatrix);
|
||
|
|
||
|
pDevice->DrawPrimitiveUP(
|
||
|
D3DPT_LINESTRIP, lineCount,
|
||
|
((UByte*)pVertexData) + baseVertexIndex * 2 * sizeof(SInt16), sizeof(SInt16)*2 );
|
||
|
|
||
|
RenderStats.Lines += lineCount;
|
||
|
RenderStats.Primitives++;
|
||
|
|
||
|
LineCnt.AddCount(lineCount);
|
||
|
DPLineCnt.AddCount(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// 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;
|
||
|
|
||
|
GTextureXbox360Impl* ptexture = (GTextureXbox360Impl*)pti;
|
||
|
// Texture must be valid for rendering
|
||
|
if (!ptexture->pD3DTexture && !ptexture->CallRecreate())
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererXBox360::DrawBitmaps failed, empty texture specified/could not recreate texture");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CheckRenderTarget();
|
||
|
|
||
|
// 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) );
|
||
|
|
||
|
ApplyPShaderCxform(CurrentCxform, 2);
|
||
|
ApplyBlendMode(BlendMode);
|
||
|
ApplySampleMode(Sample_Linear);
|
||
|
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_LIN_A8);
|
||
|
|
||
|
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);
|
||
|
ApplyMatrix(m);
|
||
|
|
||
|
SInt ibitmap = 0, ivertex = 0;
|
||
|
GCOMPILER_ASSERT((GlyphVertexBufferSize%6) == 0);
|
||
|
|
||
|
while (ibitmap < count)
|
||
|
{
|
||
|
for(ivertex = 0; (ivertex < GlyphVertexBufferSize) && (ibitmap<count); ibitmap++, ivertex+= 6)
|
||
|
{
|
||
|
BitmapDesc & bd = pbitmapList[ibitmap + startIndex];
|
||
|
GGlyphVertex* pv = GlyphVertexBuffer + 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);
|
||
|
}
|
||
|
|
||
|
// Draw the generated triangles.
|
||
|
if (ivertex)
|
||
|
{
|
||
|
pDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, ivertex / 3, GlyphVertexBuffer, sizeof(GGlyphVertex));
|
||
|
RenderStats.Primitives++;
|
||
|
DPTriangleCnt.AddCount(1);
|
||
|
}
|
||
|
}
|
||
|
RenderStats.Triangles += count * 2;
|
||
|
TriangleCnt.AddCount(count * 2);
|
||
|
|
||
|
for (int i = 0; i < 4; i++)
|
||
|
pDevice->SetTexture(i, 0);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
void BeginSubmitMask(SubmitMaskMode maskMode)
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
return;
|
||
|
|
||
|
CheckRenderTarget();
|
||
|
|
||
|
if (!StencilAvailable)
|
||
|
{
|
||
|
if (!StencilChecked)
|
||
|
{
|
||
|
// Test for depth-stencil presence.
|
||
|
IDirect3DSurface9 *pdepthStencilSurface = 0;
|
||
|
pDevice->GetDepthStencilSurface(&pdepthStencilSurface);
|
||
|
if (pdepthStencilSurface)
|
||
|
{
|
||
|
D3DSURFACE_DESC sd;
|
||
|
pdepthStencilSurface->GetDesc(&sd);
|
||
|
|
||
|
switch(sd.Format)
|
||
|
{ // Xbox360 formats
|
||
|
case D3DFMT_D24S8:
|
||
|
case D3DFMT_LIN_D24S8:
|
||
|
case D3DFMT_D24FS8:
|
||
|
case D3DFMT_LIN_D24FS8:
|
||
|
StencilAvailable = 1;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pdepthStencilSurface->Release();
|
||
|
pdepthStencilSurface = 0;
|
||
|
}
|
||
|
else
|
||
|
StencilAvailable = 0;
|
||
|
|
||
|
StencilChecked = 1;
|
||
|
}
|
||
|
|
||
|
if (!StencilAvailable)
|
||
|
{
|
||
|
#ifdef GFC_BUILD_DEBUG
|
||
|
static bool StencilWarned = 0;
|
||
|
if (!StencilWarned)
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererD3D9::BeginSubmitMask used, but stencil is not available");
|
||
|
StencilWarned = 1;
|
||
|
}
|
||
|
#endif
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
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);
|
||
|
|
||
|
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:
|
||
|
pDevice->SetRenderState(D3DRS_STENCILREF, StencilCounter);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR);
|
||
|
StencilCounter++;
|
||
|
break;
|
||
|
case Mask_Decrement:
|
||
|
pDevice->SetRenderState(D3DRS_STENCILREF, StencilCounter);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_DECR);
|
||
|
StencilCounter--;
|
||
|
break;
|
||
|
}
|
||
|
RenderStats.Masks++;
|
||
|
MaskCnt.AddCount(1);
|
||
|
}
|
||
|
|
||
|
void EndSubmitMask()
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
return;
|
||
|
if (!StencilAvailable)
|
||
|
return;
|
||
|
|
||
|
StencilEnabled = 1;
|
||
|
|
||
|
// Enable frame-buffer writes.
|
||
|
pDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0xF);
|
||
|
|
||
|
// 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_STENCILREF, StencilCounter);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILMASK, 0xFF);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);
|
||
|
pDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
|
||
|
}
|
||
|
|
||
|
void DisableMask()
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
return;
|
||
|
if (!StencilAvailable)
|
||
|
return;
|
||
|
|
||
|
StencilCounter = 0;
|
||
|
StencilEnabled = 0;
|
||
|
pDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
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();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// GRendererD3D9 interface implementation
|
||
|
|
||
|
virtual bool SetDependentVideoMode(
|
||
|
LPDIRECT3DDEVICE9 pd3dDevice,
|
||
|
D3DPRESENT_PARAMETERS* ppresentParams,
|
||
|
UInt32 vmConfigFlags,
|
||
|
HWND hwnd)
|
||
|
{
|
||
|
if (!pd3dDevice || !ppresentParams)
|
||
|
return 0;
|
||
|
|
||
|
// TODO: Need to check device caps ?
|
||
|
pDevice = pd3dDevice;
|
||
|
pDevice->AddRef();
|
||
|
|
||
|
if (!InitShaders())
|
||
|
{
|
||
|
ReleaseShaders();
|
||
|
pDevice->Release();
|
||
|
pDevice = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
VMCFlags = vmConfigFlags;
|
||
|
|
||
|
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;
|
||
|
|
||
|
pDevice->SetTexture(0, 0);
|
||
|
pDevice->SetTexture(1, 0);
|
||
|
|
||
|
// Not that we no longer generate a texture DataLost event on 360;
|
||
|
// since textures can survive the reset.
|
||
|
|
||
|
ReleaseShaders();
|
||
|
pDevice->Release();
|
||
|
pDevice = 0;
|
||
|
hWnd = 0;
|
||
|
|
||
|
ModeSet = 0;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
virtual DisplayStatus CheckDisplayStatus() const
|
||
|
{
|
||
|
return ModeSet ? DisplayStatus_Ok : DisplayStatus_NoModeSet;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Direct3D9 Access
|
||
|
// Return various Dirext3D related information
|
||
|
virtual LPDIRECT3D9 GetDirect3D() const
|
||
|
{
|
||
|
LPDIRECT3D9 pd3d = 0;
|
||
|
if (pDevice)
|
||
|
pDevice->GetDirect3D(&pd3d);
|
||
|
return pd3d;
|
||
|
}
|
||
|
virtual LPDIRECT3DDEVICE9 GetDirect3DDevice() const
|
||
|
{
|
||
|
return pDevice;
|
||
|
}
|
||
|
virtual bool GetDirect3DPresentParameters(D3DPRESENT_PARAMETERS* ppresentParams) const
|
||
|
{
|
||
|
if (!ModeSet)
|
||
|
return 0;
|
||
|
memcpy(ppresentParams, &PresentParams, sizeof(D3DPRESENT_PARAMETERS));
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
}; // class GRendererXbox360Impl
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// ***** GTextureD3D9 implementation
|
||
|
|
||
|
|
||
|
GTextureXbox360Impl::GTextureXbox360Impl(GRendererXbox360Impl *prenderer)
|
||
|
: GTextureD3D9(&prenderer->Textures)
|
||
|
{
|
||
|
pRenderer = prenderer;
|
||
|
pD3DTexture = 0;
|
||
|
}
|
||
|
|
||
|
GTextureXbox360Impl::~GTextureXbox360Impl()
|
||
|
{
|
||
|
if (pD3DTexture)
|
||
|
{
|
||
|
if (pRenderer && pRenderer->pDevice && pD3DTexture->IsSet(pRenderer->pDevice))
|
||
|
{
|
||
|
pRenderer->pDevice->SetTexture(0,0);
|
||
|
pRenderer->pDevice->SetTexture(1,0);
|
||
|
}
|
||
|
GASSERT(pRenderer);
|
||
|
if (pRenderer)
|
||
|
// because all D3D operation should be done from the main thread
|
||
|
// we add this resource to renderer deletion queue
|
||
|
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* GTextureXbox360Impl::GetRenderer() const
|
||
|
{ return pRenderer; }
|
||
|
bool GTextureXbox360Impl::IsDataValid() const
|
||
|
{ return (pD3DTexture != 0); }
|
||
|
|
||
|
void GTextureXbox360Impl::ReleaseTexture()
|
||
|
{
|
||
|
if (pD3DTexture)
|
||
|
{
|
||
|
pD3DTexture->Release();
|
||
|
pD3DTexture = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remove texture from renderer, notifies renderer destruction
|
||
|
void GTextureXbox360Impl::RemoveFromRenderer()
|
||
|
{
|
||
|
pRenderer = 0;
|
||
|
if (AddRef_NotZero())
|
||
|
{
|
||
|
if (pD3DTexture)
|
||
|
{
|
||
|
pD3DTexture->Release();
|
||
|
pD3DTexture = 0;
|
||
|
}
|
||
|
|
||
|
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();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// 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.
|
||
|
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 GTextureXbox360Impl::InitTexture(IDirect3DTexture9 *ptex, bool managed)
|
||
|
{
|
||
|
GUNUSED(managed);
|
||
|
if (!pRenderer || !pRenderer->pDevice)
|
||
|
return 0;
|
||
|
|
||
|
if (pD3DTexture)
|
||
|
{
|
||
|
pD3DTexture->Release();
|
||
|
pD3DTexture = 0;
|
||
|
}
|
||
|
if (ptex)
|
||
|
{
|
||
|
pD3DTexture = ptex;
|
||
|
ptex->AddRef();
|
||
|
}
|
||
|
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// NOTE: This function destroys pim's data in the process of making mipmaps.
|
||
|
bool GTextureXbox360Impl::InitTexture(GImageBase* pim, UInt usage)
|
||
|
{
|
||
|
GUNUSED(usage);
|
||
|
|
||
|
if (!pRenderer || !pRenderer->pDevice)
|
||
|
return 0;
|
||
|
|
||
|
// Delete old data
|
||
|
if (pD3DTexture)
|
||
|
{
|
||
|
pD3DTexture->Release();
|
||
|
pD3DTexture = 0;
|
||
|
}
|
||
|
if (!pim || !pim->pData)
|
||
|
{
|
||
|
// Kill texture
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// Determine format
|
||
|
UInt bytesPerPixel = 0;
|
||
|
|
||
|
switch(pim->Format)
|
||
|
{
|
||
|
case GImage::Image_ARGB_8888:
|
||
|
bytesPerPixel = 4;
|
||
|
TextureFormat = D3DFMT_A8R8G8B8;
|
||
|
break;
|
||
|
case GImage::Image_RGB_888:
|
||
|
bytesPerPixel = 3;
|
||
|
TextureFormat = D3DFMT_DXT1;
|
||
|
//TextureFormat = D3DFMT_A8R8G8B8;
|
||
|
break;
|
||
|
|
||
|
case GImage::Image_A_8:
|
||
|
bytesPerPixel = 1;
|
||
|
TextureFormat = D3DFMT_A8;
|
||
|
break;
|
||
|
|
||
|
case GImage::Image_DXT1:
|
||
|
TextureFormat = D3DFMT_LIN_DXT1;
|
||
|
bytesPerPixel = 1;
|
||
|
break;
|
||
|
case GImage::Image_DXT3:
|
||
|
TextureFormat = D3DFMT_LIN_DXT3;
|
||
|
bytesPerPixel = 1;
|
||
|
break;
|
||
|
case GImage::Image_DXT5:
|
||
|
TextureFormat = D3DFMT_LIN_DXT5;
|
||
|
bytesPerPixel = 1;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
// Unsupported format
|
||
|
GASSERT(0);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Don't use DXT1 for thin textures (it must be a multiple of 4 for DirectX)
|
||
|
/*
|
||
|
if (((TextureFormat== D3DFMT_DXT1) || (TextureFormat== D3DFMT_DXT3)) &&
|
||
|
((Width<4) || (Height<4)))
|
||
|
TextureFormat = D3DFMT_A8R8G8B8;
|
||
|
*/
|
||
|
|
||
|
UInt w = pim->Width;
|
||
|
UInt h = pim->Height;
|
||
|
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) ||
|
||
|
(pim->Format == GImage::Image_ARGB_8888)) )
|
||
|
{
|
||
|
// Resample the image to new size
|
||
|
if (presampleImage = *new GImage(
|
||
|
((pim->Format == GImage::Image_RGB_888) ? GImage::Image_ARGB_8888 : pim->Format), w, h))
|
||
|
{
|
||
|
GASSERT_ON_RENDERER_RESAMPLING;
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_RGB_888)
|
||
|
{
|
||
|
// Need to insert a dummy alpha byte in the image data, for Xbox360LoadSurfaceFromMemory.
|
||
|
for (UInt y = 0; y < h; y++)
|
||
|
{
|
||
|
UByte* scanline = pim->GetScanline(y);
|
||
|
UByte* pdest = presampleImage->GetScanline(y);
|
||
|
for (UInt x = 0; x < w; x++)
|
||
|
{
|
||
|
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
|
||
|
pdest[x * 4 + 3] = 255; // alpha
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_ARGB_8888)
|
||
|
{
|
||
|
XMemCpy(presampleImage->GetScanline(0), pim->GetScanline(0),
|
||
|
pim->GetPitch() * pim->Height);
|
||
|
}
|
||
|
// HACK: disable mipmaps, need to do something with them! (AB)
|
||
|
if (pim->MipMapCount > 1)
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GRendererD3D9 - Existing mipmap levels have been skipped due to resampling");
|
||
|
levelsNeeded = 1;
|
||
|
}
|
||
|
|
||
|
// Swap byte order for Big-Endian XBox 360
|
||
|
if (presampleImage->Format == GImage::Image_ARGB_8888)
|
||
|
{
|
||
|
for (UInt y = 0; y < h; y++)
|
||
|
{
|
||
|
UInt32* pdest = (UInt32*)presampleImage->GetScanline(y);
|
||
|
for (UInt x = 0; x < w; x++)
|
||
|
pdest[x] = _byteswap_ulong(pdest[x]);
|
||
|
}
|
||
|
|
||
|
// The new image has 4 bytes/pixel.
|
||
|
bytesPerPixel = 4;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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 = GTL::gmax(1u, (bytesPerPixel == 1) ? UInt(levelsNeeded - 1) : 1u);
|
||
|
|
||
|
HRESULT result = pRenderer->pDevice->CreateTexture(
|
||
|
w, h,
|
||
|
levelsNeeded,
|
||
|
0, // XBox: D3DUSAGE_BORDERSOURCE_TEXTURE
|
||
|
TextureFormat,
|
||
|
D3DPOOL_DEFAULT,
|
||
|
&pD3DTexture, NULL);
|
||
|
if (result != S_OK)
|
||
|
{
|
||
|
GFC_DEBUG_ERROR(1, "GTextureD3D9 - Can't create texture");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (pim->IsDataCompressed() || pim->MipMapCount > 1)
|
||
|
{
|
||
|
IDirect3DSurface9* psurface = NULL;
|
||
|
UInt level;
|
||
|
GImageBase* psourceImage= presampleImage ? presampleImage.GetPtr() : pim;
|
||
|
RECT sourceRect = { 0,0, w,h};
|
||
|
D3DFORMAT sourceSurfaceFormat = TextureFormat;
|
||
|
|
||
|
// Determine source data format correctly (it may be different from texture).
|
||
|
if (TextureFormat == D3DFMT_A8R8G8B8)
|
||
|
sourceSurfaceFormat = D3DFMT_LIN_A8B8G8R8;
|
||
|
else if (TextureFormat == D3DFMT_A8)
|
||
|
sourceSurfaceFormat = D3DFMT_LIN_A8;
|
||
|
|
||
|
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,
|
||
|
(pim->IsDataCompressed()) ?
|
||
|
GImageBase::GetMipMapLevelSize(psourceImage->Format, mipW, 1) :
|
||
|
GImageBase::GetPitch(psourceImage->Format, mipW),
|
||
|
NULL,
|
||
|
&sourceRect,
|
||
|
FALSE, 0, 0, // no packed mipmap for now
|
||
|
D3DX_DEFAULT, 0);
|
||
|
psurface->Release();
|
||
|
psurface = 0;
|
||
|
|
||
|
if (result != S_OK)
|
||
|
{
|
||
|
GFC_DEBUG_ERROR1(1, "GTextureD3D9 - 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);
|
||
|
XMemCpy(presampleImage->pData, pim->pData, pim->Height * pim->Pitch);
|
||
|
}
|
||
|
|
||
|
IDirect3DSurface9* psurface = NULL;
|
||
|
UInt level;
|
||
|
GImageBase* psourceImage= presampleImage ? presampleImage.GetPtr() : pim;
|
||
|
RECT sourceRect = { 0,0, w,h};
|
||
|
|
||
|
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,
|
||
|
(bytesPerPixel == 1) ? D3DFMT_LIN_A8 : D3DFMT_LIN_A8B8G8R8, // NOTE: format order conversion from GL
|
||
|
(bytesPerPixel == 1) ? sourceRect.right : psourceImage->Pitch,
|
||
|
NULL,
|
||
|
&sourceRect,
|
||
|
FALSE, 0, 0, // no packed mipmap for now
|
||
|
D3DX_DEFAULT, 0);
|
||
|
psurface->Release();
|
||
|
psurface = 0;
|
||
|
|
||
|
if (result != S_OK)
|
||
|
{
|
||
|
GFC_DEBUG_ERROR1(1, "GTextureD3D9 - 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))
|
||
|
{
|
||
|
GCOMPILER_ASSERT(sizeof(sourceRect.right) == sizeof(int));
|
||
|
GRendererXbox360Impl::MakeNextMiplevel((int*) &sourceRect.right, (int*) &sourceRect.bottom,
|
||
|
psourceImage->pData);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
CallHandlers(ChangeHandler::Event_DataChange);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool GTextureXbox360Impl::InitDynamicTexture(int width, int height, GImage::ImageFormat format, int mipmaps, UInt usage)
|
||
|
{
|
||
|
if (!pRenderer || !pRenderer->pDevice)
|
||
|
return 0;
|
||
|
|
||
|
if (pD3DTexture)
|
||
|
pD3DTexture->Release();
|
||
|
|
||
|
TexWidth = width;
|
||
|
TexHeight = height;
|
||
|
|
||
|
if (usage & Usage_Update)
|
||
|
{
|
||
|
if (format == GImage::Image_ARGB_8888)
|
||
|
TextureFormat = D3DFMT_LIN_A8R8G8B8;
|
||
|
else if (format == GImage::Image_RGB_888)
|
||
|
TextureFormat = D3DFMT_LIN_A8R8G8B8;
|
||
|
else if (format == GImage::Image_A_8)
|
||
|
TextureFormat = D3DFMT_LIN_A8;
|
||
|
else
|
||
|
{ // Unsupported format
|
||
|
GASSERT(0);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
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 = D3DFMT_A8;
|
||
|
else
|
||
|
{ // Unsupported format
|
||
|
GASSERT(0);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT result = pRenderer->pDevice->CreateTexture(width, height, mipmaps+1, 0, TextureFormat,
|
||
|
(usage & Usage_Map) ? D3DPOOL_MANAGED : D3DPOOL_DEFAULT, &pD3DTexture, NULL);
|
||
|
if (result != S_OK)
|
||
|
return 0;
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void GTextureXbox360Impl::Update(int level, int n, const UpdateRect *rects, const GImageBase *pim)
|
||
|
{
|
||
|
UInt bytesPerPixel = 0, convert = 0;
|
||
|
|
||
|
if (pim->Format == GImage::Image_ARGB_8888)
|
||
|
bytesPerPixel = 4;
|
||
|
else if (pim->Format == GImage::Image_RGB_888)
|
||
|
{
|
||
|
convert = 1;
|
||
|
bytesPerPixel = 4;
|
||
|
}
|
||
|
else if (pim->Format == GImage::Image_A_8)
|
||
|
bytesPerPixel = 1;
|
||
|
else
|
||
|
GASSERT(0);
|
||
|
|
||
|
if (!pD3DTexture && !CallRecreate())
|
||
|
{
|
||
|
GFC_DEBUG_WARNING(1, "GTextureXBox360::Update failed, could not recreate texture");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Ensure that our texture isn't set on the device during Update.
|
||
|
pRenderer->pDevice->SetTexture(0, 0);
|
||
|
pRenderer->pDevice->SetTexture(1, 0);
|
||
|
|
||
|
for (int i = 0; i < n; i++)
|
||
|
{
|
||
|
GRect<int> rect = rects[i].src;
|
||
|
GPoint<int> dest = rects[i].dest;
|
||
|
|
||
|
D3DLOCKED_RECT lr;
|
||
|
RECT destr;
|
||
|
UInt32 lockFlags = (pRenderer->VMCFlags & GRendererXbox360::VMConfig_SupportTiling) ? D3DLOCK_NOOVERWRITE : 0;
|
||
|
|
||
|
destr.left = dest.x;
|
||
|
destr.bottom = dest.y + rect.Height() - 1;
|
||
|
destr.right = dest.x + rect.Width() - 1;
|
||
|
destr.top = dest.y;
|
||
|
|
||
|
if (FAILED( pD3DTexture->LockRect(level, &lr, &destr, lockFlags) ))
|
||
|
return;
|
||
|
|
||
|
if (convert && pim->Format == GImage::Image_RGB_888)
|
||
|
{
|
||
|
UByte *pdest = (UByte*)lr.pBits;
|
||
|
//pdest += dest.y * lr.Pitch + dest.x * bytesPerPixel;
|
||
|
|
||
|
for (int j = 0; j < rect.Height(); j++)
|
||
|
for (int k = 0; k < rect.Width(); k++)
|
||
|
{
|
||
|
pdest[j * lr.Pitch + k * bytesPerPixel +0] = pim->pData[(j + rect.Top) * pim->Pitch + (k + rect.Left) * 3 +0];
|
||
|
pdest[j * lr.Pitch + k * bytesPerPixel +1] = pim->pData[(j + rect.Top) * pim->Pitch + (k + rect.Left) * 3 +1];
|
||
|
pdest[j * lr.Pitch + k * bytesPerPixel +2] = pim->pData[(j + rect.Top) * pim->Pitch + (k + rect.Left) * 3 +2];
|
||
|
pdest[j * lr.Pitch + k * bytesPerPixel +3] = 255;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int GTextureXbox360Impl::Map(int level, int n, MapRect* maps, int flags)
|
||
|
{
|
||
|
GUNUSED(flags);
|
||
|
GASSERT(n > 0 && maps);
|
||
|
|
||
|
D3DLOCKED_RECT rect;
|
||
|
pD3DTexture->LockRect(level, &rect, NULL, 0);
|
||
|
maps[0].pData = (UByte*)rect.pBits;
|
||
|
maps[0].pitch = rect.Pitch;
|
||
|
maps[0].width = TexWidth;
|
||
|
maps[0].height = TexHeight;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool GTextureXbox360Impl::Unmap(int level, int n, MapRect* maps, int flags)
|
||
|
{
|
||
|
GUNUSED3(n,maps,flags);
|
||
|
pD3DTexture->UnlockRect(level);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void GTextureXbox360Impl::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);
|
||
|
|
||
|
if (pRenderer->VMCFlags & GRendererXbox360::VMConfig_SupportTiling)
|
||
|
pRenderer->FrameResources.PushBack(this);
|
||
|
}
|
||
|
|
||
|
GTextureXbox360ImplYUV::~GTextureXbox360ImplYUV()
|
||
|
{
|
||
|
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 GTextureXbox360ImplYUV::ReleaseTexture()
|
||
|
{
|
||
|
GTextureXbox360Impl::ReleaseTexture();
|
||
|
for (int i = 0; i < 3; i++)
|
||
|
if (pD3DTextureUVA[i])
|
||
|
{
|
||
|
pD3DTextureUVA[i]->Release();
|
||
|
pD3DTextureUVA[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool GTextureXbox360ImplYUV::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;
|
||
|
|
||
|
HRESULT result = pRenderer->pDevice->CreateTexture(width, height, mipmaps+1, 0,
|
||
|
D3DFMT_LIN_A8, D3DPOOL_DEFAULT, &pD3DTexture, NULL);
|
||
|
result |= pRenderer->pDevice->CreateTexture(width>>1, height>>1, mipmaps+1, 0,
|
||
|
D3DFMT_LIN_A8, D3DPOOL_DEFAULT, &pD3DTextureUVA[0], NULL);
|
||
|
result |= pRenderer->pDevice->CreateTexture(width>>1, height>>1, mipmaps+1, 0,
|
||
|
D3DFMT_LIN_A8, D3DPOOL_DEFAULT, &pD3DTextureUVA[1], NULL);
|
||
|
if (format == GImage::Image_ARGB_8888)
|
||
|
{
|
||
|
IsAlpha = 1;
|
||
|
result |= pRenderer->pDevice->CreateTexture(width, height, mipmaps+1, 0,
|
||
|
D3DFMT_LIN_A8, D3DPOOL_DEFAULT, &pD3DTextureUVA[2], NULL);
|
||
|
}
|
||
|
else
|
||
|
IsAlpha = 0;
|
||
|
|
||
|
if (result != S_OK)
|
||
|
{
|
||
|
GFC_DEBUG_ERROR(1, "GTextureXbox360 - Can't create YUV texture");
|
||
|
ReleaseTexture();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int GTextureXbox360ImplYUV::Map(int level, int n, MapRect* maps, int flags)
|
||
|
{
|
||
|
GUNUSED(flags);
|
||
|
GASSERT(n >= (IsAlpha ? 4 : 3) && maps);
|
||
|
|
||
|
for (int i = 0; i < 4; i++)
|
||
|
pRenderer->pDevice->SetTexture(i, 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 GTextureXbox360ImplYUV::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 GTextureXbox360ImplYUV::Bind(int stageIndex, GRenderer::BitmapWrapMode WrapMode, GRenderer::BitmapSampleMode SampleMode, bool useMipmaps)
|
||
|
{
|
||
|
if (!pD3DTexture)
|
||
|
CallRecreate();
|
||
|
|
||
|
GASSERT(stageIndex == 0);
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
if (pRenderer->VMCFlags & GRendererXbox360::VMConfig_SupportTiling)
|
||
|
pRenderer->FrameResources.PushBack(this);
|
||
|
}
|
||
|
|
||
|
bool GRenderTargetXbox360Impl::InitRenderTarget(GTexture *pTarget, UInt Base)
|
||
|
{
|
||
|
ReleaseResources();
|
||
|
|
||
|
pTexture = (GTextureXbox360Impl*)pTarget;
|
||
|
TargetWidth = pTexture->TexWidth;
|
||
|
TargetHeight = pTexture->TexHeight;
|
||
|
|
||
|
TileSize = XGSurfaceSize(TargetWidth, TargetHeight, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE);
|
||
|
BaseTile = Base;
|
||
|
|
||
|
D3DSURFACE_PARAMETERS params;
|
||
|
params.Base = BaseTile;
|
||
|
params.ColorExpBias = 0;
|
||
|
params.HierarchicalZBase = 0xffffffff;
|
||
|
params.HiZFunc = D3DHIZFUNC_DEFAULT;
|
||
|
|
||
|
pRenderer->pDevice->CreateRenderTarget(TargetWidth, TargetHeight, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, 0,
|
||
|
&pRenderSurface, ¶ms);
|
||
|
params.Base += TileSize;
|
||
|
|
||
|
TileSize += XGSurfaceSize(TargetWidth, TargetHeight, D3DFMT_D24S8, D3DMULTISAMPLE_NONE);
|
||
|
pRenderer->pDevice->CreateDepthStencilSurface(TargetWidth, TargetHeight, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, 0,
|
||
|
&pStencilSurface, ¶ms);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Store the render texture and depth buffer that is passed in
|
||
|
//
|
||
|
GRenderTargetXbox360Impl::GRenderTargetXbox360Impl(GRendererXbox360Impl *pRend) : GRenderTargetD3D9(&pRend->RenderTargets)
|
||
|
{
|
||
|
pRenderer = pRend; BaseTile = TileSize = 0;
|
||
|
pRenderSurface = 0;
|
||
|
pStencilSurface = 0;
|
||
|
}
|
||
|
|
||
|
GRenderTargetXbox360Impl::~GRenderTargetXbox360Impl()
|
||
|
{
|
||
|
if (pRenderSurface)
|
||
|
{
|
||
|
GASSERT(pRenderer);
|
||
|
if (pRenderer)
|
||
|
{
|
||
|
pRenderer->AddResourceForReleasing(pRenderSurface);
|
||
|
pRenderer->AddResourceForReleasing(pStencilSurface);
|
||
|
}
|
||
|
}
|
||
|
if (!pRenderer)
|
||
|
return;
|
||
|
GLock::Locker gruad(&pRenderer->TexturesLock);
|
||
|
if (pFirst)
|
||
|
RemoveNode();
|
||
|
}
|
||
|
|
||
|
void GRenderTargetXbox360Impl::ReleaseResources()
|
||
|
{
|
||
|
if (pRenderSurface)
|
||
|
{
|
||
|
pRenderSurface->Release();
|
||
|
pRenderSurface = 0;
|
||
|
}
|
||
|
if (pStencilSurface)
|
||
|
{
|
||
|
pStencilSurface->Release();
|
||
|
pStencilSurface = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GRenderer* GRenderTargetXbox360Impl::GetRenderer() const
|
||
|
{
|
||
|
return pRenderer;
|
||
|
}
|
||
|
|
||
|
void GRenderTargetXbox360Impl::RemoveFromRenderer()
|
||
|
{
|
||
|
pRenderer = 0;
|
||
|
|
||
|
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();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool GRenderTargetXbox360Impl::InitRenderTarget(D3D9RenderTargetParams RTParams)
|
||
|
{
|
||
|
ReleaseResources();
|
||
|
BaseTile = TileSize = 0;
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
// Factory.
|
||
|
GRendererXbox360* GRendererXbox360::CreateRenderer()
|
||
|
{
|
||
|
return new GRendererXbox360Impl;
|
||
|
}
|
||
|
|
||
|
|