mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
D3D: Assorted cleanup. Add a missing register specification.
This commit is contained in:
parent
163f81e5be
commit
7b66059ae0
7 changed files with 99 additions and 112 deletions
|
@ -493,9 +493,6 @@ void DIRECTX9_GPU::BeginFrameInternal() {
|
|||
}
|
||||
shaderManager_->DirtyShader();
|
||||
|
||||
// Not sure if this is really needed.
|
||||
shaderManager_->DirtyUniform(DIRTY_ALL);
|
||||
|
||||
framebufferManager_.BeginFrame();
|
||||
}
|
||||
|
||||
|
|
|
@ -237,23 +237,23 @@ void GenerateFragmentShaderDX9(char *buffer) {
|
|||
WRITE(p, "float3 roundAndScaleTo255v(float3 x) { return floor(x * 255.0f + 0.5f); }\n");
|
||||
}
|
||||
|
||||
WRITE(p, " struct PS_IN {\n");
|
||||
WRITE(p, "struct PS_IN {\n");
|
||||
if (doTexture) {
|
||||
if (doTextureProjection)
|
||||
WRITE(p, " float3 v_texcoord: TEXCOORD0;\n");
|
||||
WRITE(p, " float3 v_texcoord: TEXCOORD0;\n");
|
||||
else
|
||||
WRITE(p, " float2 v_texcoord: TEXCOORD0;\n");
|
||||
WRITE(p, " float2 v_texcoord: TEXCOORD0;\n");
|
||||
}
|
||||
WRITE(p, " float4 v_color0: COLOR0;\n");
|
||||
WRITE(p, " float4 v_color0: COLOR0;\n");
|
||||
if (lmode) {
|
||||
WRITE(p, " float3 v_color1: COLOR1;\n");
|
||||
WRITE(p, " float3 v_color1: COLOR1;\n");
|
||||
}
|
||||
if (enableFog) {
|
||||
WRITE(p, "float2 v_fogdepth: TEXCOORD1;\n");
|
||||
WRITE(p, " float2 v_fogdepth: TEXCOORD1;\n");
|
||||
}
|
||||
WRITE(p, " };\n\n");
|
||||
WRITE(p, " float4 main( PS_IN In ) : COLOR\n");
|
||||
WRITE(p, " {\n");
|
||||
WRITE(p, "};\n");
|
||||
WRITE(p, "float4 main( PS_IN In ) : COLOR\n");
|
||||
WRITE(p, "{\n");
|
||||
|
||||
if (gstate.isModeClear()) {
|
||||
// Clear mode does not allow any fancy shading.
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
namespace DX9 {
|
||||
|
||||
PSShader::PSShader(const char *code, bool useHWTransform) : failed_(false), useHWTransform_(useHWTransform) {
|
||||
PSShader::PSShader(const char *code, bool useHWTransform) : shader(nullptr), failed_(false), useHWTransform_(useHWTransform) {
|
||||
source_ = code;
|
||||
#ifdef SHADERLOG
|
||||
OutputDebugString(ConvertUTF8ToWString(code).c_str());
|
||||
|
@ -77,7 +77,7 @@ PSShader::~PSShader() {
|
|||
shader->Release();
|
||||
}
|
||||
|
||||
VSShader::VSShader(const char *code, int vertType, bool useHWTransform) : failed_(false), useHWTransform_(useHWTransform) {
|
||||
VSShader::VSShader(const char *code, int vertType, bool useHWTransform) : shader(nullptr), failed_(false), useHWTransform_(useHWTransform) {
|
||||
source_ = code;
|
||||
#ifdef SHADERLOG
|
||||
OutputDebugString(ConvertUTF8ToWString(code).c_str());
|
||||
|
@ -86,7 +86,6 @@ VSShader::VSShader(const char *code, int vertType, bool useHWTransform) : failed
|
|||
std::string errorMessage;
|
||||
|
||||
success = CompileVertexShader(code, &shader, NULL, errorMessage);
|
||||
|
||||
if (!errorMessage.empty()) {
|
||||
if (success) {
|
||||
ERROR_LOG(G3D, "Warnings in shader compilation!");
|
||||
|
@ -120,9 +119,9 @@ VSShader::~VSShader() {
|
|||
|
||||
void ShaderManagerDX9::PSSetColorUniform3(int creg, u32 color) {
|
||||
const float col[4] = {
|
||||
((color & 0xFF)) / 255.0f,
|
||||
((color & 0xFF00) >> 8) / 255.0f,
|
||||
((color & 0xFF0000) >> 16) / 255.0f,
|
||||
((color & 0xFF)) * (1.0f / 255.0f),
|
||||
((color & 0xFF00) >> 8) * (1.0f / 255.0f),
|
||||
((color & 0xFF0000) >> 16) * (1.0f / 255.0f),
|
||||
0.0f
|
||||
};
|
||||
pD3Ddevice->SetPixelShaderConstantF(creg, col, 1);
|
||||
|
@ -296,11 +295,9 @@ void ShaderManagerDX9::VSUpdateUniforms(int dirtyUniforms) {
|
|||
}
|
||||
}
|
||||
#else
|
||||
float bonetemp[16];
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) {
|
||||
ConvertMatrix4x3To4x4(bonetemp, gstate.boneMatrix + 12 * i);
|
||||
VSSetMatrix(CONST_VS_BONE0 + 4 * i, bonetemp);
|
||||
VSSetMatrix4x3(CONST_VS_BONE0 + 4 * i, gstate.boneMatrix + 12 * i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -412,39 +409,35 @@ void ShaderManagerDX9::DirtyShader() {
|
|||
// Forget the last shader ID
|
||||
lastFSID_.clear();
|
||||
lastVSID_.clear();
|
||||
lastVShader_ = 0;
|
||||
lastPShader_ = 0;
|
||||
lastVShader_ = nullptr;
|
||||
lastPShader_ = nullptr;
|
||||
globalDirty_ = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
void ShaderManagerDX9::DirtyLastShader() { // disables vertex arrays
|
||||
lastVShader_ = 0;
|
||||
lastPShader_ = 0;
|
||||
lastVShader_ = nullptr;
|
||||
lastPShader_ = nullptr;
|
||||
}
|
||||
|
||||
|
||||
VSShader *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) {
|
||||
if (globalDirty_) {
|
||||
PSUpdateUniforms(globalDirty_);
|
||||
VSUpdateUniforms(globalDirty_);
|
||||
globalDirty_ = 0;
|
||||
}
|
||||
|
||||
bool useHWTransform = CanUseHardwareTransformDX9(prim);
|
||||
|
||||
VertexShaderIDDX9 VSID;
|
||||
FragmentShaderIDDX9 FSID;
|
||||
ComputeVertexShaderIDDX9(&VSID, vertType, prim, useHWTransform);
|
||||
FragmentShaderIDDX9 FSID;
|
||||
ComputeFragmentShaderIDDX9(&FSID);
|
||||
|
||||
// Just update uniforms if this is the same shader as last time.
|
||||
if (lastVShader_ != nullptr && lastPShader_ != nullptr && VSID == lastVSID_ && FSID == lastFSID_) {
|
||||
if (globalDirty_) {
|
||||
PSUpdateUniforms(globalDirty_);
|
||||
VSUpdateUniforms(globalDirty_);
|
||||
globalDirty_ = 0;
|
||||
}
|
||||
return lastVShader_; // Already all set.
|
||||
}
|
||||
|
||||
lastVSID_ = VSID;
|
||||
lastFSID_ = FSID;
|
||||
|
||||
VSCache::iterator vsIter = vsCache_.find(VSID);
|
||||
VSShader *vs;
|
||||
if (vsIter == vsCache_.end()) {
|
||||
|
@ -470,6 +463,7 @@ VSShader *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) {
|
|||
} else {
|
||||
vs = vsIter->second;
|
||||
}
|
||||
lastVSID_ = VSID;
|
||||
|
||||
FSCache::iterator fsIter = fsCache_.find(FSID);
|
||||
PSShader *fs;
|
||||
|
@ -482,6 +476,14 @@ VSShader *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) {
|
|||
fs = fsIter->second;
|
||||
}
|
||||
|
||||
lastFSID_ = FSID;
|
||||
|
||||
if (globalDirty_) {
|
||||
PSUpdateUniforms(globalDirty_);
|
||||
VSUpdateUniforms(globalDirty_);
|
||||
globalDirty_ = 0;
|
||||
}
|
||||
|
||||
pD3Ddevice->SetPixelShader(fs->shader);
|
||||
pD3Ddevice->SetVertexShader(vs->shader);
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ public:
|
|||
void DirtyUniform(u32 what) {
|
||||
globalDirty_ |= what;
|
||||
}
|
||||
void DirtyLastShader(); // disables vertex arrays
|
||||
void DirtyLastShader();
|
||||
|
||||
int NumVertexShaders() const { return (int)vsCache_.size(); }
|
||||
int NumFragmentShaders() const { return (int)fsCache_.size(); }
|
||||
|
|
|
@ -281,12 +281,12 @@ IDirect3DVertexDeclaration9 *TransformDrawEngineDX9::SetupDecFmtForDraw(VSShader
|
|||
// Vertices Elements orders
|
||||
// WEIGHT
|
||||
if (decFmt.w0fmt != 0) {
|
||||
VertexAttribSetup(VertexElement, decFmt.w0fmt, decFmt.w0off, D3DDECLUSAGE_BLENDWEIGHT, 0);
|
||||
VertexAttribSetup(VertexElement, decFmt.w0fmt, decFmt.w0off, D3DDECLUSAGE_TEXCOORD, 1);
|
||||
VertexElement++;
|
||||
}
|
||||
|
||||
if (decFmt.w1fmt != 0) {
|
||||
VertexAttribSetup(VertexElement, decFmt.w1fmt, decFmt.w1off, D3DDECLUSAGE_BLENDWEIGHT, 1);
|
||||
VertexAttribSetup(VertexElement, decFmt.w1fmt, decFmt.w1off, D3DDECLUSAGE_TEXCOORD, 2);
|
||||
VertexElement++;
|
||||
}
|
||||
|
||||
|
|
|
@ -112,14 +112,14 @@ void ComputeVertexShaderIDDX9(VertexShaderIDDX9 *id, u32 vertType, int prim, boo
|
|||
|
||||
static const char * const boneWeightAttrDecl[9] = {
|
||||
"#ERROR#",
|
||||
"float a_w1 :BLENDWEIGHT0;\n",
|
||||
"float2 a_w1:BLENDWEIGHT0;\n",
|
||||
"float3 a_w1:BLENDWEIGHT0;\n",
|
||||
"float4 a_w1:BLENDWEIGHT0;\n",
|
||||
"float4 a_w1:BLENDWEIGHT0;\n float a_w2 :BLENDWEIGHT1;\n",
|
||||
"float4 a_w1:BLENDWEIGHT0;\n float2 a_w2:BLENDWEIGHT1;\n",
|
||||
"float4 a_w1:BLENDWEIGHT0;\n float3 a_w2:BLENDWEIGHT1;\n",
|
||||
"float4 a_w1:BLENDWEIGHT0;\n float4 a_w2:BLENDWEIGHT1;\n",
|
||||
"float a_w1:TEXCOORD1;\n",
|
||||
"float2 a_w1:TEXCOORD1;\n",
|
||||
"float3 a_w1:TEXCOORD1;\n",
|
||||
"float4 a_w1:TEXCOORD1;\n",
|
||||
"float4 a_w1:TEXCOORD1;\n float a_w2:TEXCOORD2;\n",
|
||||
"float4 a_w1:TEXCOORD1;\n float2 a_w2:TEXCOORD2;\n",
|
||||
"float4 a_w1:TEXCOORD1;\n float3 a_w2:TEXCOORD2;\n",
|
||||
"float4 a_w1:TEXCOORD1;\n float4 a_w2:TEXCOORD2;\n",
|
||||
};
|
||||
|
||||
enum DoLightComputation {
|
||||
|
@ -171,7 +171,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
|||
WRITE(p, "float2 u_fogcoef : register(c%i);\n", CONST_VS_FOGCOEF);
|
||||
}
|
||||
if (useHWTransform || !hasColor)
|
||||
WRITE(p, "float4 u_matambientalpha;\n"); // matambient + matalpha
|
||||
WRITE(p, "float4 u_matambientalpha : register(c%i);\n", CONST_VS_MATAMBIENTALPHA); // matambient + matalpha
|
||||
|
||||
if (useHWTransform) {
|
||||
// When transforming by hardware, we need a great deal more uniforms...
|
||||
|
@ -179,10 +179,10 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
|||
WRITE(p, "float4x4 u_view : register(c%i);\n", CONST_VS_VIEW);
|
||||
if (gstate.getUVGenMode() == 1)
|
||||
WRITE(p, "float4x4 u_texmtx : register(c%i);\n", CONST_VS_TEXMTX);
|
||||
if (vertTypeGetWeightMask(vertType) != GE_VTYPE_WEIGHT_NONE) {
|
||||
if (vertTypeIsSkinningEnabled(vertType)) {
|
||||
int numBones = TranslateNumBonesDX9(vertTypeGetNumBoneWeights(vertType));
|
||||
#ifdef USE_BONE_ARRAY
|
||||
WRITE(p, "float4x4 u_bone[%i];\n", numBones);
|
||||
WRITE(p, "float4x4 u_bone[%i] : register(c%i);\n", numBones, CONST_VS_BONE0);
|
||||
#else
|
||||
for (int i = 0; i < numBones; i++) {
|
||||
WRITE(p, "float4x4 u_bone%i : register(c%i);\n", i, CONST_VS_BONE0 + i * 4);
|
||||
|
@ -226,58 +226,54 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
|||
}
|
||||
|
||||
if (useHWTransform) {
|
||||
WRITE(p, " struct VS_IN { \n");
|
||||
if (vertTypeGetWeightMask(vertType) != GE_VTYPE_WEIGHT_NONE) {
|
||||
WRITE(p, "struct VS_IN { \n");
|
||||
if (vertTypeIsSkinningEnabled(vertType)) {
|
||||
WRITE(p, "%s", boneWeightAttrDecl[TranslateNumBonesDX9(vertTypeGetNumBoneWeights(vertType))]);
|
||||
}
|
||||
if (doTexture && hasTexcoord) {
|
||||
if (doTextureProjection)
|
||||
WRITE(p, " float3 texcoord: TEXCOORD0; \n");
|
||||
WRITE(p, " float3 texcoord : TEXCOORD0;\n");
|
||||
else
|
||||
WRITE(p, " float2 texcoord: TEXCOORD0; \n");
|
||||
WRITE(p, " float2 texcoord : TEXCOORD0;\n");
|
||||
}
|
||||
if (hasColor) {
|
||||
WRITE(p, " float4 color0: COLOR0; \n");
|
||||
WRITE(p, " float4 color0 : COLOR0;\n");
|
||||
}
|
||||
if (hasNormal) {
|
||||
WRITE(p, " float3 normal: NORMAL; \n");
|
||||
WRITE(p, " float3 normal : NORMAL;\n");
|
||||
}
|
||||
WRITE(p, " float3 position: POSITION; \n");
|
||||
WRITE(p, " }; \n");
|
||||
WRITE(p, " \n");
|
||||
WRITE(p, " float3 position : POSITION;\n");
|
||||
WRITE(p, "};\n");
|
||||
|
||||
} else {
|
||||
WRITE(p, " struct VS_IN { \n");
|
||||
WRITE(p, " float4 position : POSITION; \n");
|
||||
WRITE(p, " float3 texcoord : TEXCOORD0; \n");
|
||||
WRITE(p, " float4 color0 : COLOR0; \n");
|
||||
WRITE(p, "struct VS_IN {\n");
|
||||
WRITE(p, " float4 position : POSITION;\n");
|
||||
WRITE(p, " float3 texcoord : TEXCOORD0;\n");
|
||||
WRITE(p, " float4 color0 : COLOR0;\n");
|
||||
// only software transform supplies color1 as vertex data
|
||||
WRITE(p, " float4 color1 : COLOR1; \n");
|
||||
WRITE(p, " }; \n");
|
||||
WRITE(p, " float4 color1 : COLOR1;\n");
|
||||
WRITE(p, "};\n");
|
||||
}
|
||||
|
||||
WRITE(p, " struct VS_OUT \n");
|
||||
WRITE(p, " { \n");
|
||||
WRITE(p, " float4 gl_Position : POSITION; \n");
|
||||
WRITE(p, "struct VS_OUT {\n");
|
||||
WRITE(p, " float4 gl_Position : POSITION;\n");
|
||||
if (doTexture) {
|
||||
if (doTextureProjection)
|
||||
WRITE(p, " float3 v_texcoord: TEXCOORD0; \n");
|
||||
WRITE(p, " float3 v_texcoord: TEXCOORD0;\n");
|
||||
else
|
||||
WRITE(p, " float2 v_texcoord: TEXCOORD0; \n");
|
||||
WRITE(p, " float2 v_texcoord: TEXCOORD0;\n");
|
||||
}
|
||||
WRITE(p, " float4 v_color0 : COLOR0; \n");
|
||||
WRITE(p, " float4 v_color0 : COLOR0;\n");
|
||||
if (lmode)
|
||||
WRITE(p, " float3 v_color1 : COLOR1; \n");
|
||||
WRITE(p, " float3 v_color1 : COLOR1;\n");
|
||||
|
||||
if (enableFog) {
|
||||
WRITE(p, "float2 v_fogdepth: TEXCOORD1;\n");
|
||||
WRITE(p, " float2 v_fogdepth: TEXCOORD1;\n");
|
||||
}
|
||||
WRITE(p, " }; \n");
|
||||
WRITE(p, " \n");
|
||||
WRITE(p, "};\n");
|
||||
|
||||
WRITE(p, " VS_OUT main( VS_IN In ) \n");
|
||||
WRITE(p, " { \n");
|
||||
WRITE(p, " VS_OUT Out = (VS_OUT)0; \n");
|
||||
WRITE(p, "VS_OUT main(VS_IN In) {\n");
|
||||
WRITE(p, " VS_OUT Out = (VS_OUT)0; \n");
|
||||
if (!useHWTransform) {
|
||||
// Simple pass-through of vertex data to fragment shader
|
||||
if (doTexture) {
|
||||
|
@ -306,7 +302,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
|||
}
|
||||
} else {
|
||||
// Step 1: World Transform / Skinning
|
||||
if (vertTypeGetWeightMask(vertType) == GE_VTYPE_WEIGHT_NONE) {
|
||||
if (!vertTypeIsSkinningEnabled(vertType)) {
|
||||
// No skinning, just standard T&L.
|
||||
WRITE(p, " float3 worldpos = mul(float4(In.position.xyz, 1.0), u_world).xyz;\n");
|
||||
if (hasNormal)
|
||||
|
@ -594,7 +590,7 @@ void GenerateVertexShaderDX9(int prim, char *buffer, bool useHWTransform) {
|
|||
}
|
||||
|
||||
// WRITE(p, "Out.gl_Position.z = (Out.gl_Position.z + Out.gl_Position.w) * 0.5f;");
|
||||
WRITE(p, " return Out; ");
|
||||
WRITE(p, " return Out;\n");
|
||||
WRITE(p, "}\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -9,44 +9,38 @@ LPDIRECT3DDEVICE9EX pD3DdeviceEx = NULL;
|
|||
LPDIRECT3D9 pD3D = NULL;
|
||||
|
||||
static const char * vscode =
|
||||
" float4x4 matWVP : register(c0); "
|
||||
" "
|
||||
" struct VS_IN { "
|
||||
" float4 ObjPos : POSITION; "
|
||||
" float2 Uv : TEXCOORD0; " // Vertex color
|
||||
" }; "
|
||||
" "
|
||||
" struct VS_OUT { "
|
||||
" float4 ProjPos : POSITION; "
|
||||
" float2 Uv : TEXCOORD0; " // Vertex color
|
||||
" }; "
|
||||
" "
|
||||
" VS_OUT main( VS_IN In ) { "
|
||||
" VS_OUT Out; "
|
||||
" Out.ProjPos = In.ObjPos; " // Transform vertex into
|
||||
" Out.Uv = In.Uv; "
|
||||
" return Out; " // Transfer color
|
||||
" } ";
|
||||
"struct VS_IN {\n"
|
||||
" float4 ObjPos : POSITION;\n"
|
||||
" float2 Uv : TEXCOORD0;\n"
|
||||
"};"
|
||||
"struct VS_OUT {\n"
|
||||
" float4 ProjPos : POSITION;\n"
|
||||
" float2 Uv : TEXCOORD0;\n"
|
||||
"};\n"
|
||||
"VS_OUT main( VS_IN In ) {\n"
|
||||
" VS_OUT Out;\n"
|
||||
" Out.ProjPos = In.ObjPos;\n"
|
||||
" Out.Uv = In.Uv;\n"
|
||||
" return Out;\n"
|
||||
"}\n";
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Pixel shader
|
||||
//--------------------------------------------------------------------------------------
|
||||
static const char * pscode =
|
||||
" sampler s: register(s0); "
|
||||
" struct PS_IN { "
|
||||
" float2 Uv : TEXCOORD0; "
|
||||
" }; "
|
||||
" "
|
||||
" float4 main( PS_IN In ) : COLOR { "
|
||||
" float4 c = tex2D(s, In.Uv) ; "
|
||||
" c.a = 1.0f;"
|
||||
" return c; "
|
||||
" } ";
|
||||
"sampler s: register(s0);\n"
|
||||
"struct PS_IN {\n"
|
||||
" float2 Uv : TEXCOORD0;\n"
|
||||
"};\n"
|
||||
"float4 main( PS_IN In ) : COLOR {\n"
|
||||
" float4 c = tex2D(s, In.Uv);\n"
|
||||
" c.a = 1.0f;\n"
|
||||
" return c;\n"
|
||||
"}\n";
|
||||
|
||||
IDirect3DVertexDeclaration9* pFramebufferVertexDecl = NULL;
|
||||
|
||||
static const D3DVERTEXELEMENT9 VertexElements[] =
|
||||
{
|
||||
static const D3DVERTEXELEMENT9 VertexElements[] = {
|
||||
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
||||
{ 0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
|
||||
D3DDECL_END()
|
||||
|
@ -54,8 +48,7 @@ static const D3DVERTEXELEMENT9 VertexElements[] =
|
|||
|
||||
IDirect3DVertexDeclaration9* pSoftVertexDecl = NULL;
|
||||
|
||||
static const D3DVERTEXELEMENT9 SoftTransVertexElements[] =
|
||||
{
|
||||
static const D3DVERTEXELEMENT9 SoftTransVertexElements[] = {
|
||||
{ 0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
||||
{ 0, 16, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
|
||||
{ 0, 28, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
|
||||
|
@ -263,7 +256,6 @@ void DirectxInit(HWND window) {
|
|||
// TODO
|
||||
}
|
||||
|
||||
|
||||
#ifdef _XBOX
|
||||
pD3Ddevice->SetRingBufferParameters( &d3dr );
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue