9174 lines
277 KiB
C++
9174 lines
277 KiB
C++
/*=============================================================================
|
|
D3DRendPipeline.cpp : Direct3D specific rendering using shaders pipeline.
|
|
Copyright (c) 2001 Crytek Studios. All Rights Reserved.
|
|
|
|
Revision history:
|
|
* Created by Honitch Andrey
|
|
|
|
=============================================================================*/
|
|
|
|
#include "RenderPCH.h"
|
|
#include "DriverD3D9.h"
|
|
#include <ICryAnimation.h>
|
|
#include "..\common\shadow_renderer.h"
|
|
#include "D3DCGPShader.h"
|
|
#include "D3DCGVProgram.h"
|
|
#include "I3dengine.h"
|
|
#include "CryHeaders.h"
|
|
|
|
//============================================================================================
|
|
// Shaders rendering
|
|
//============================================================================================
|
|
|
|
//============================================================================================
|
|
// Init Shaders rendering
|
|
|
|
void CD3D9Renderer::EF_InitRandTables()
|
|
{
|
|
int i;
|
|
float f;
|
|
|
|
for (i=0; i<256; i++)
|
|
{
|
|
f = (float)rand() / 32767.0f;
|
|
m_RP.m_tRandFloats[i] = f + f - 1.0f;
|
|
|
|
m_RP.m_tRandBytes[i] = (byte)((float)rand() / 32767.0f * 255.0f);
|
|
}
|
|
}
|
|
|
|
void CD3D9Renderer::EF_InitWaveTables()
|
|
{
|
|
int i;
|
|
|
|
//Init wave Tables
|
|
for (i=0; i<1024; i++)
|
|
{
|
|
float f = (float)i;
|
|
|
|
m_RP.m_tSinTable[i] = sin_tpl(f * (360.0f/1023.0f) * M_PI / 180.0f);
|
|
m_RP.m_tHalfSinTable[i] = sin_tpl(f * (360.0f/1023.0f) * M_PI / 180.0f);
|
|
if (m_RP.m_tHalfSinTable[i] < 0)
|
|
m_RP.m_tHalfSinTable[i] = 0;
|
|
m_RP.m_tCosTable[i] = cos_tpl(f * (360.0f/1023.0f) * M_PI / 180.0f);
|
|
m_RP.m_tHillTable[i] = sin_tpl(f * (180.0f/1023.0f) * M_PI / 180.0f);
|
|
|
|
if (i < 512)
|
|
m_RP.m_tSquareTable[i] = 1.0f;
|
|
else
|
|
m_RP.m_tSquareTable[i] = -1.0f;
|
|
|
|
m_RP.m_tSawtoothTable[i] = f / 1024.0f;
|
|
m_RP.m_tInvSawtoothTable[i] = 1.0f - m_RP.m_tSawtoothTable[i];
|
|
|
|
if (i < 512)
|
|
{
|
|
if (i < 256)
|
|
m_RP.m_tTriTable[i] = f / 256.0f;
|
|
else
|
|
m_RP.m_tTriTable[i] = 1.0f - m_RP.m_tTriTable[i-256];
|
|
}
|
|
else
|
|
m_RP.m_tTriTable[i] = 1.0f - m_RP.m_tTriTable[i-512];
|
|
}
|
|
}
|
|
|
|
void CD3D9Renderer::EF_InitEvalFuncs(int num)
|
|
{
|
|
switch(num)
|
|
{
|
|
case 0:
|
|
m_RP.m_pCurFuncs = &m_RP.m_EvalFuncs_C;
|
|
break;
|
|
default:
|
|
case 1:
|
|
m_RP.m_pCurFuncs = &m_RP.m_EvalFuncs_RE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
int CD3D9Renderer::EF_RegisterFogVolume(float fMaxFogDist, float fFogLayerZ, CFColor color, int nIndex, bool bCaustics)
|
|
{
|
|
if (nIndex < 0)
|
|
{
|
|
SMFog Fog;
|
|
memset(&Fog,0,sizeof(Fog));
|
|
|
|
Fog.m_fMaxDist = fMaxFogDist;
|
|
Fog.m_FogInfo.m_FogColor = color;
|
|
Fog.m_Dist = fFogLayerZ;
|
|
Fog.m_Color = color;
|
|
Fog.m_Color.a = 1.0f;
|
|
Fog.bCaustics = bCaustics;
|
|
//Fog.m_FogInfo.m_FogColor = m_FogColor;
|
|
Fog.m_Normal = Vec3d(0,0,1);
|
|
|
|
m_RP.m_FogVolumes.AddElem(Fog);
|
|
return m_RP.m_FogVolumes.Num()-1;
|
|
}
|
|
else
|
|
{
|
|
assert (nIndex < m_RP.m_FogVolumes.Num());
|
|
SMFog *pFog = &m_RP.m_FogVolumes[nIndex];
|
|
pFog->m_fMaxDist = fMaxFogDist;
|
|
pFog->m_FogInfo.m_FogColor = color;
|
|
pFog->m_Dist = fFogLayerZ;
|
|
pFog->m_Color = color;
|
|
pFog->m_Color.a = 1.0f;
|
|
pFog->bCaustics = bCaustics;
|
|
return nIndex;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Init vertex declarations (for fixed pipeline and for programmable pipeline)
|
|
void CD3D9Renderer::EF_InitD3DFixedPipeline()
|
|
{
|
|
if (m_RP.m_D3DFixedPipeline[0][0].m_Declaration.Num())
|
|
return;
|
|
|
|
int i, j;
|
|
SBufInfoTable *pOffs;
|
|
|
|
// base formats declarations (stream 0)
|
|
int n = 0;
|
|
pOffs = &gBufInfoTable[n];
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = 0;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 1;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_P3F
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 2;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_P3F_COL4UB
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_DIFFUSE;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position
|
|
{0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 3;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_P3F_TEX2F
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_TEX1;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position
|
|
{0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 4;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_P3F_COL4UB_TEX2F
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position
|
|
{0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse
|
|
{0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 5;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_TRP3F_COL4UB_TEX2F
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITIONT, 0}, // position
|
|
{0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse
|
|
{0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 6;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_P3F_COL4UB_COL4UB
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position
|
|
{0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // normal
|
|
{0, pOffs->OffsSecColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1}, // specular
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 7;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_P3F_N
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_NORMAL;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position
|
|
{0, pOffs->OffsNormal, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, // normal
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 8;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_P3F_N_COL4UB
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position
|
|
{0, pOffs->OffsNormal, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, // normal
|
|
{0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 9;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_P3F_N_TEX2F
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position
|
|
{0, pOffs->OffsNormal, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, // normal
|
|
{0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 10;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_P3F_N_COL4UB_TEX2F
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position
|
|
{0, pOffs->OffsNormal, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, // normal
|
|
{0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse
|
|
{0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 11;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_P3F_N_COL4UB_COL4UB
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_SPECULAR;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position
|
|
{0, pOffs->OffsNormal, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, // normal
|
|
{0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse
|
|
{0, pOffs->OffsSecColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1}, // specular
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 12;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_P3F_COL4UB_COL4UB_TEX2F
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position
|
|
{0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse
|
|
{0, pOffs->OffsSecColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1}, // specular
|
|
{0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 13;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_P3F_N_COL4UB_COL4UB_TEX2F
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position
|
|
{0, pOffs->OffsNormal, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, // normal
|
|
{0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse
|
|
{0, pOffs->OffsSecColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1}, // specular
|
|
{0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 14;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_T3F_B3F_N3F
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_TEX3;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2}, // tangent
|
|
{0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3}, // binormal
|
|
{0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0}, // tnormal
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 15;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_T2F
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_TEX1;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1}, // tangent
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
n = 16;
|
|
pOffs = &gBufInfoTable[n];
|
|
{ // VERTEX_FORMAT_P3F_COL4UB_TEX2F_TEX2F
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Handle = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX2;
|
|
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // position
|
|
{0, pOffs->OffsColor, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // diffuse
|
|
{0, pOffs->OffsTC, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // texture0
|
|
{0, pOffs->OffsTC+8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1}, // texture1
|
|
D3DDECL_END()
|
|
};
|
|
i = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Add(elem[i]); // end of the declaration
|
|
if (elem[i++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[0][n].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[0][n].m_pDeclaration = NULL;
|
|
}
|
|
|
|
// Additional streams:
|
|
// stream 1 (tangent vectors)
|
|
for (i=0; i<VERTEX_FORMAT_NUMS; i++)
|
|
{
|
|
if (!m_RP.m_D3DFixedPipeline[0][i].m_Declaration.Num())
|
|
continue;
|
|
|
|
for (j=0; j<m_RP.m_D3DFixedPipeline[0][i].m_Declaration.Num()-1; j++)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[1][i].m_Declaration.AddElem(m_RP.m_D3DFixedPipeline[0][i].m_Declaration[j]);
|
|
}
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2}, // tangent
|
|
{1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3}, // binormal
|
|
{1, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0}, // tnormal
|
|
D3DDECL_END()
|
|
};
|
|
n = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[1][i].m_Declaration.Add(elem[n]);
|
|
if (elem[n++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[1][i].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[1][i].m_pDeclaration = NULL;
|
|
}
|
|
|
|
// stream 2 (LM texcoords)
|
|
for (int i=0; i<VERTEX_FORMAT_NUMS; i++)
|
|
{
|
|
if (!m_RP.m_D3DFixedPipeline[0][i].m_Declaration.Num())
|
|
continue;
|
|
|
|
for (int j=0; j<m_RP.m_D3DFixedPipeline[0][i].m_Declaration.Num()-1; j++)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[2][i].m_Declaration.AddElem(m_RP.m_D3DFixedPipeline[0][i].m_Declaration[j]);
|
|
}
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{2, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1}, // LM texcoord
|
|
D3DDECL_END()
|
|
};
|
|
n = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[2][i].m_Declaration.Add(elem[n]);
|
|
if (elem[n++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[2][i].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[2][i].m_pDeclaration = NULL;
|
|
}
|
|
|
|
// stream 1 and 2 (tangent vectors and LM texcoords)
|
|
for (int i=0; i<VERTEX_FORMAT_NUMS; i++)
|
|
{
|
|
if (!m_RP.m_D3DFixedPipeline[0][i].m_Declaration.Num())
|
|
continue;
|
|
|
|
for (int j=0; j<m_RP.m_D3DFixedPipeline[0][i].m_Declaration.Num()-1; j++)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[3][i].m_Declaration.AddElem(m_RP.m_D3DFixedPipeline[0][i].m_Declaration[j]);
|
|
}
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2}, // tangent
|
|
{1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3}, // binormal
|
|
{1, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0}, // tnormal
|
|
{2, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1}, // LM texcoord
|
|
D3DDECL_END()
|
|
};
|
|
n = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[3][i].m_Declaration.Add(elem[n]);
|
|
if (elem[n++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[3][i].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[3][i].m_pDeclaration = NULL;
|
|
}
|
|
// stream 4 (BendInfo)
|
|
for (int i=0; i<VERTEX_FORMAT_NUMS; i++)
|
|
{
|
|
if (!m_RP.m_D3DFixedPipeline[0][i].m_Declaration.Num())
|
|
continue;
|
|
|
|
for (int j=0; j<m_RP.m_D3DFixedPipeline[0][i].m_Declaration.Num()-1; j++)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[4][i].m_Declaration.AddElem(m_RP.m_D3DFixedPipeline[0][i].m_Declaration[j]);
|
|
}
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
|
|
{2, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
|
|
D3DDECL_END()
|
|
};
|
|
n = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[4][i].m_Declaration.Add(elem[n]);
|
|
if (elem[n++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[4][i].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[4][i].m_pDeclaration = NULL;
|
|
}
|
|
// stream 1 and 4 (BendInfo)
|
|
for (int i=0; i<VERTEX_FORMAT_NUMS; i++)
|
|
{
|
|
if (!m_RP.m_D3DFixedPipeline[0][i].m_Declaration.Num())
|
|
continue;
|
|
|
|
for (int j=0; j<m_RP.m_D3DFixedPipeline[0][i].m_Declaration.Num()-1; j++)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[5][i].m_Declaration.AddElem(m_RP.m_D3DFixedPipeline[0][i].m_Declaration[j]);
|
|
}
|
|
D3DVERTEXELEMENT9 elem[] =
|
|
{
|
|
{1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2}, // tangent
|
|
{1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3}, // binormal
|
|
{1, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0}, // tnormal
|
|
{2, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
|
|
{2, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
|
|
D3DDECL_END()
|
|
};
|
|
n = 0;
|
|
while (true)
|
|
{
|
|
m_RP.m_D3DFixedPipeline[5][i].m_Declaration.Add(elem[n]);
|
|
if (elem[n++].Stream == 0xff) break;
|
|
}
|
|
m_RP.m_D3DFixedPipeline[5][i].m_Declaration.Shrink();
|
|
m_RP.m_D3DFixedPipeline[5][i].m_pDeclaration = NULL;
|
|
}
|
|
|
|
m_MaxVertBufferSize = CLAMP((int)(CV_d3d9_pip_buff_size), 5, 100)*1024*1024;
|
|
m_CurVertBufferSize = 0;
|
|
}
|
|
|
|
_inline static void *sAlign0x20(byte *vrts)
|
|
{
|
|
INT_PTR b = (INT_PTR)vrts;
|
|
|
|
if (!(b & 0x1f))
|
|
return vrts;
|
|
|
|
b = (b+0x20)&~0x1f;
|
|
|
|
return (void *)b;
|
|
}
|
|
|
|
// Init shaders pipeline
|
|
void CD3D9Renderer::EF_Init()
|
|
{
|
|
bool nv = 0;
|
|
int i;
|
|
|
|
if (CV_r_logTexStreaming && !m_LogFileStr)
|
|
{
|
|
m_LogFileStr = fxopen ("Direct3DLogStreaming.txt", "w");
|
|
if (m_LogFileStr)
|
|
{
|
|
iLog->Log("Direct3D texture streaming log file '%s' opened\n", "Direct3DLogStreaming.txt");
|
|
char time[128];
|
|
char date[128];
|
|
|
|
_strtime( time );
|
|
_strdate( date );
|
|
|
|
fprintf(m_LogFileStr, "\n==========================================\n");
|
|
fprintf(m_LogFileStr, "Direct3D Textures streaming Log file opened: %s (%s)\n", date, time);
|
|
fprintf(m_LogFileStr, "==========================================\n");
|
|
}
|
|
}
|
|
|
|
m_RP.m_pCurFuncs = NULL;
|
|
m_RP.m_MaxVerts = CV_d3d9_rb_verts;
|
|
m_RP.m_MaxTris = CV_d3d9_rb_tris;
|
|
|
|
iLog->Log("\nAllocate render buffer (%d verts, %d tris)...\n", m_RP.m_MaxVerts, m_RP.m_MaxTris);
|
|
|
|
int n = 0;
|
|
|
|
n += sizeof(struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F) * m_RP.m_MaxVerts + 32;
|
|
|
|
//m_RP.mFogVertValues
|
|
n += sizeof(float)*m_RP.m_MaxVerts+32;
|
|
//m_RP.mBaseTexCoordPointer
|
|
n += sizeof(SMRendTexVert)*m_RP.m_MaxVerts+32;
|
|
//m_RP.mLMTexCoordPointer
|
|
n += sizeof(SMRendTexVert)*m_RP.m_MaxVerts+32;
|
|
//m_RP.mClientColors
|
|
n += sizeof(bvec4)*m_RP.m_MaxVerts+32;
|
|
|
|
//m_RP.mRendIndices;
|
|
n += sizeof(ushort)*3*m_RP.m_MaxTris+32;
|
|
|
|
if (GetFeatures() & RFT_BUMP)
|
|
{
|
|
//m_RP.mBinormals
|
|
n += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
//m_RP.mTangents
|
|
n += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
//m_RP.mTNormals
|
|
n += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
for (i=0; i<4; i++)
|
|
{
|
|
//m_RP.mHalfAngleVectors
|
|
n += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
//m_RP.mLightVectors
|
|
n += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
}
|
|
//m_RP.mAttenuation
|
|
n += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
//m_RP.mLAttenSpec0
|
|
n += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
//m_RP.mLAttenSpec1
|
|
n += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
}
|
|
|
|
byte *buf = new byte [n];
|
|
m_SysArray = buf;
|
|
if (!buf)
|
|
iConsole->Exit("Can't allocate buffers for RB");
|
|
|
|
memset(buf, 0, n);
|
|
|
|
m_RP.m_Ptr.Ptr = sAlign0x20(buf);
|
|
buf += sizeof(struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F) * m_RP.m_MaxVerts + 32;
|
|
m_RP.m_RendIndices = (ushort *)sAlign0x20(buf);
|
|
m_RP.m_SysRendIndices = m_RP.m_RendIndices;
|
|
buf += sizeof(ushort)*3*m_RP.m_MaxTris+32;
|
|
m_RP.m_pClientColors = (bvec4 *)sAlign0x20(buf);
|
|
buf += sizeof(bvec4)*m_RP.m_MaxVerts+32;
|
|
m_RP.m_pBaseTexCoordPointer = (SMRendTexVert *)sAlign0x20(buf);
|
|
buf += sizeof(SMRendTexVert)*m_RP.m_MaxVerts+32;
|
|
m_RP.m_pLMTexCoordPointer = (SMRendTexVert *)sAlign0x20(buf);
|
|
buf += sizeof(SMRendTexVert)*m_RP.m_MaxVerts+32;
|
|
m_RP.m_pFogVertValues = (float *)sAlign0x20(buf);
|
|
buf += sizeof(float)*m_RP.m_MaxVerts+32;
|
|
if (GetFeatures() & RFT_BUMP)
|
|
{
|
|
m_RP.m_pBinormals = (Vec3d *)sAlign0x20(buf);
|
|
buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
m_RP.m_pTangents = (Vec3d *)sAlign0x20(buf);
|
|
buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
m_RP.m_pTNormals = (Vec3d *)sAlign0x20(buf);
|
|
buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
for (i=0; i<4; i++)
|
|
{
|
|
m_RP.m_pLightVectors[i] = (Vec3d *)sAlign0x20(buf);
|
|
buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
m_RP.m_pHalfAngleVectors[i] = (Vec3d *)sAlign0x20(buf);
|
|
buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
}
|
|
m_RP.m_pAttenuation = (Vec3d *)sAlign0x20(buf);
|
|
buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
m_RP.m_pLAttenSpec0 = (Vec3d *)sAlign0x20(buf);
|
|
buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
m_RP.m_pLAttenSpec1 = (Vec3d *)sAlign0x20(buf);
|
|
buf += sizeof(Vec3d)*m_RP.m_MaxVerts+32;
|
|
}
|
|
|
|
EF_Restore();
|
|
|
|
EF_InitWaveTables();
|
|
EF_InitRandTables();
|
|
EF_InitEvalFuncs(0);
|
|
EF_InitFogVolumes();
|
|
EF_InitD3DFixedPipeline();
|
|
|
|
for (i=0; i<VERTEX_FORMAT_NUMS; i++)
|
|
{
|
|
for (int j=0; j<VERTEX_FORMAT_NUMS; j++)
|
|
{
|
|
SVertBufComps Cps[2];
|
|
GetVertBufComps(&Cps[0], i);
|
|
GetVertBufComps(&Cps[1], j);
|
|
|
|
bool bNeedTC = Cps[1].m_bHasTC | Cps[0].m_bHasTC;
|
|
bool bNeedCol = Cps[1].m_bHasColors | Cps[0].m_bHasColors;
|
|
bool bNeedSecCol = Cps[1].m_bHasSecColors | Cps[0].m_bHasSecColors;
|
|
bool bNeedNormals = Cps[1].m_bHasNormals | Cps[0].m_bHasNormals;
|
|
m_RP.m_VFormatsMerge[i][j] = VertFormatForComponents(bNeedCol, bNeedSecCol, bNeedNormals, bNeedTC);
|
|
}
|
|
}
|
|
|
|
//==================================================
|
|
|
|
CCObject::m_Waves.Create(32);
|
|
m_RP.m_VisObjects = new CCObject *[MAX_REND_OBJECTS];
|
|
CCObject::m_ObjMatrices.reinit(32);
|
|
CCObject::m_ObjMatrices[0].SetIdentity();
|
|
|
|
if (!m_RP.m_TempObjects.Num())
|
|
m_RP.m_TempObjects.Reserve(MAX_REND_OBJECTS);
|
|
if (!m_RP.m_Objects.Num())
|
|
{
|
|
m_RP.m_Objects.Reserve(MAX_REND_OBJECTS);
|
|
m_RP.m_Objects.SetUse(1);
|
|
SAFE_DELETE_ARRAY(m_RP.m_ObjectsPool);
|
|
m_RP.m_nNumObjectsInPool = 512;
|
|
m_RP.m_ObjectsPool = new CCObject[m_RP.m_nNumObjectsInPool];
|
|
for (int i=0; i<m_RP.m_nNumObjectsInPool; i++)
|
|
{
|
|
m_RP.m_TempObjects[i] = &m_RP.m_ObjectsPool[i];
|
|
m_RP.m_TempObjects[i]->Init();
|
|
m_RP.m_TempObjects[i]->m_Color = Col_White;
|
|
m_RP.m_TempObjects[i]->m_ObjFlags = 0;
|
|
m_RP.m_TempObjects[i]->m_Matrix.SetIdentity();
|
|
m_RP.m_TempObjects[i]->m_RenderState = 0;
|
|
}
|
|
m_RP.m_VisObjects[0] = &m_RP.m_ObjectsPool[0];
|
|
}
|
|
|
|
for (i=0; i<eSHP_MAX; i++)
|
|
{
|
|
if (i == eSHP_DiffuseLight || i == eSHP_SpecularLight)
|
|
m_SHPTable[i] = eSHP_Light;
|
|
else
|
|
m_SHPTable[i] = (EShaderPassType)i;
|
|
}
|
|
m_RP.m_Name_SpecularExp = CName("specularexp", eFN_Add);
|
|
|
|
// create glare element
|
|
m_RP.m_pREGlare = (CREGlare *)EF_CreateRE(eDATA_Glare);
|
|
m_RP.m_pREHDR = (CREHDRProcess *)EF_CreateRE(eDATA_HDRProcess);
|
|
|
|
//MakeShadowTextures();
|
|
}
|
|
|
|
// Invalidate shaders pipeline
|
|
void CD3D9Renderer::EF_Invalidate()
|
|
{
|
|
int j;
|
|
for (j=0; j<MAX_DYNVBS; j++)
|
|
{
|
|
SAFE_DELETE (m_RP.m_VBs[j].VBPtr_0);
|
|
}
|
|
SAFE_DELETE(m_RP.m_IndexBuf);
|
|
SAFE_DELETE(m_RP.m_VB_Inst);
|
|
}
|
|
|
|
// Restore shaders pipeline
|
|
void CD3D9Renderer::EF_Restore()
|
|
{
|
|
int j;
|
|
|
|
if (!m_RP.m_MaxTris)
|
|
return;
|
|
|
|
EF_Invalidate();
|
|
|
|
m_RP.m_IndexBuf = new DynamicIB<ushort>(m_pd3dDevice, m_RP.m_MaxTris*3);
|
|
m_RP.m_VB_Inst = new DynamicVB <vec4_t>(m_pd3dDevice, 0, MAX_HWINST_PARAMS);
|
|
|
|
for (j=0; j<MAX_DYNVBS; j++)
|
|
{
|
|
m_RP.m_VBs[j].VBPtr_10 = new DynamicVB <struct_VERTEX_FORMAT_P3F_N_COL4UB_TEX2F>(m_pd3dDevice, 0, m_RP.m_MaxVerts*8);
|
|
}
|
|
}
|
|
|
|
// Shutdown shaders pipeline
|
|
void CD3D9Renderer::EF_PipelineShutdown()
|
|
{
|
|
int i, j;
|
|
|
|
EF_Invalidate();
|
|
|
|
CCObject::m_Waves.Free();
|
|
SAFE_DELETE_ARRAY(m_RP.m_VisObjects);
|
|
SAFE_DELETE_ARRAY(m_SysArray);
|
|
|
|
m_RP.m_FogVolumes.Free();
|
|
SAFE_RELEASE(m_RP.m_pREGlare);
|
|
|
|
for (i=0; i<CREClientPoly2D::mPolysStorage.GetSize(); i++)
|
|
{
|
|
SAFE_RELEASE(CREClientPoly2D::mPolysStorage[i]);
|
|
}
|
|
CREClientPoly2D::mPolysStorage.Free();
|
|
|
|
for (j=0; j<4; j++)
|
|
{
|
|
for (i=0; i<CREClientPoly::mPolysStorage[j].GetSize(); i++)
|
|
{
|
|
SAFE_RELEASE(CREClientPoly::mPolysStorage[j][i]);
|
|
}
|
|
CREClientPoly::mPolysStorage[j].Free();
|
|
}
|
|
|
|
EF_Release(EFRF_VSHADERS);
|
|
CCGVProgram_D3D::mfDeleteSharedScripts();
|
|
}
|
|
|
|
// Release all vertex and pixel shaders
|
|
void CD3D9Renderer::EF_Release(int nFlags)
|
|
{
|
|
int i;
|
|
|
|
if (nFlags & EFRF_VSHADERS)
|
|
{
|
|
for (i=0; i<CVProgram::m_VPrograms.Num(); i++)
|
|
{
|
|
CVProgram::m_VPrograms[i]->mfReset();
|
|
}
|
|
}
|
|
if (nFlags & EFRF_PSHADERS)
|
|
{
|
|
for (i=0; i<CPShader::m_PShaders.Num(); i++)
|
|
{
|
|
CPShader::m_PShaders[i]->mfReset();
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrawFullScreenQuad(float fLeftU, float fTopV, float fRightU, float fBottomV);
|
|
|
|
// Clear buffers (color, depth/stencil)
|
|
void CD3D9Renderer::EF_ClearBuffers(bool bForce, bool bOnlyDepth, float *Colors)
|
|
{
|
|
if (m_bWasCleared && !bForce)
|
|
return;
|
|
|
|
m_bWasCleared = true;
|
|
|
|
DWORD cColor;
|
|
if (Colors)
|
|
cColor = D3DRGBA(Colors[0], Colors[1], Colors[2], Colors[3]);
|
|
else
|
|
if(m_polygon_mode==R_WIREFRAME_MODE)
|
|
{
|
|
m_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
|
|
cColor = D3DRGBA(0.25,0.5,1,0);
|
|
}
|
|
else
|
|
{
|
|
m_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
|
|
cColor = D3DRGBA(m_vClearColor[0], m_vClearColor[1], m_vClearColor[2], 0);
|
|
}
|
|
|
|
int nFlags = D3DCLEAR_ZBUFFER;
|
|
if (m_sbpp)
|
|
nFlags |= D3DCLEAR_STENCIL;
|
|
if (!bOnlyDepth)
|
|
{
|
|
// Fill float buffer by HDR fog color
|
|
if (m_RP.m_PersFlags & RBPF_HDR)
|
|
{
|
|
CCGPShader_D3D *fpHDR = NULL;
|
|
//if (m_nHDRType == 1)
|
|
fpHDR = (CCGPShader_D3D *)PShaderForName(m_RP.m_PS_HDR_ClearScreen, "CGRC_HDR_ClearScreen_PS20");
|
|
//else
|
|
//if (m_nHDRType == 2)
|
|
// fpHDR = (CCGPShader_D3D *)PShaderForName(m_RP.m_PS_HDR_ClearScreen, "CGRC_HDR_ClearScreen_MRT_PS20");
|
|
if (fpHDR)
|
|
{
|
|
EF_SetState(GS_NODEPTHTEST);
|
|
D3DSetCull(eCULL_None);
|
|
m_TexMan->m_Text_White->Set();
|
|
fpHDR->mfSet(true);
|
|
// Draw a fullscreen quad to sample the RT
|
|
DrawFullScreenQuad(0.0f, 0.0f, 1.0f, 1.0f);
|
|
fpHDR->mfSet(false);
|
|
}
|
|
}
|
|
else
|
|
nFlags |= D3DCLEAR_TARGET;
|
|
}
|
|
m_pd3dDevice->Clear(0, NULL, nFlags, cColor, 1.0f, 0);
|
|
|
|
if (CV_r_measureoverdraw)
|
|
{
|
|
if (m_sbpp <= 4)
|
|
{
|
|
iLog->Log("Warning: Not enough stencil bits to measure overdraw: %d\n");
|
|
CV_r_measureoverdraw = 0;
|
|
m_RP.m_PersFlags &= ~RBPF_MEASUREOVERDRAW;
|
|
}
|
|
else
|
|
{
|
|
m_RP.m_PersFlags &= ~RBPF_MEASUREOVERDRAW;
|
|
EF_SetState(GS_STENCIL | GS_DEPTHWRITE);
|
|
m_RP.m_PersFlags |= RBPF_MEASUREOVERDRAW;
|
|
EF_SetStencilState(STENC_FUNC(FSS_STENCFUNC_ALWAYS) |
|
|
STENCOP_FAIL(FSS_STENCOP_KEEP) |
|
|
STENCOP_ZFAIL(FSS_STENCOP_INCR) |
|
|
STENCOP_PASS(FSS_STENCOP_INCR),
|
|
0, 0xffffffff);
|
|
}
|
|
}
|
|
else
|
|
m_RP.m_PersFlags &= ~RBPF_MEASUREOVERDRAW;
|
|
}
|
|
|
|
//==========================================================================
|
|
// Calculate current scene node matrices
|
|
void CD3D9Renderer::EF_SetCameraInfo()
|
|
{
|
|
m_RP.m_ViewOrg = m_cam.GetPos();
|
|
|
|
float fm[16];
|
|
GetModelViewMatrix(fm);
|
|
m_ViewMatrix = (Matrix44&)fm;
|
|
m_CameraMatrix = m_ViewMatrix;
|
|
|
|
Matrix44 m;
|
|
mathMatrixTranspose(m.GetData(), m_CameraMatrix.GetData(), g_CpuFlags);
|
|
|
|
m_RP.m_CamVecs[0][0] = -m(2,0);
|
|
m_RP.m_CamVecs[0][1] = -m(2,1);
|
|
m_RP.m_CamVecs[0][2] = -m(2,2);
|
|
|
|
m_RP.m_CamVecs[1][0] = m(1,0);
|
|
m_RP.m_CamVecs[1][1] = m(1,1);
|
|
m_RP.m_CamVecs[1][2] = m(1,2);
|
|
|
|
m_RP.m_CamVecs[2][0] = m(0,0);
|
|
m_RP.m_CamVecs[2][1] = m(0,1);
|
|
m_RP.m_CamVecs[2][2] = m(0,2);
|
|
|
|
m_RP.m_TransformFrame++;
|
|
m_RP.m_FrameObject++;
|
|
|
|
GetProjectionMatrix(&m_ProjMatrix(0,0));
|
|
|
|
D3DXMatrixMultiply((D3DXMATRIXA16 *)m_CameraProjMatrix.GetData(), (D3DXMATRIXA16 *)m_CameraMatrix.GetData(), (D3DXMATRIXA16 *)m_ProjMatrix.GetData());
|
|
D3DXMatrixInverse((D3DXMATRIXA16 *)m_InvCameraProjMatrix.GetData(), NULL, (D3DXMATRIXA16 *)m_CameraProjMatrix.GetData());
|
|
|
|
m_RP.m_PersFlags &= ~RBPF_WASWORLDSPACE;
|
|
m_RP.m_ObjFlags = FOB_TRANS_MASK;
|
|
}
|
|
|
|
_declspec(align(16)) static Matrix44 sIdentityMatrix(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1);
|
|
|
|
// Get inverted matrix of the object matrix
|
|
// All matrices are 16 bytes alligned to speedup matrix calculations using SSE instructions
|
|
Matrix44 &CCObject::GetInvMatrix()
|
|
{
|
|
if (m_InvMatrixId == 0)
|
|
return sIdentityMatrix;
|
|
if (m_InvMatrixId > 0)
|
|
return m_ObjMatrices[m_InvMatrixId];
|
|
|
|
//PROFILE_FRAME(Objects_ObjInvTransform);
|
|
|
|
int n = m_ObjMatrices.size();
|
|
m_ObjMatrices.resize(n+1);
|
|
m_InvMatrixId = n;
|
|
|
|
CRenderer *rd = gRenDev;
|
|
Matrix44 &m = m_ObjMatrices[m_InvMatrixId];
|
|
|
|
if (m_ObjFlags & FOB_TRANS_ROTATE)
|
|
{
|
|
mathMatrixInverse(m.GetData(), m_Matrix.GetData(), g_CpuFlags);
|
|
}
|
|
else
|
|
if (m_ObjFlags & FOB_TRANS_SCALE)
|
|
{
|
|
float fiScaleX = 1.0f / m_Matrix(0,0);
|
|
float fiScaleY = 1.0f / m_Matrix(1,1);
|
|
float fiScaleZ = 1.0f / m_Matrix(2,2);
|
|
m(0,0) = fiScaleX;
|
|
m(0,1) = m_Matrix(0,1);
|
|
m(0,2) = m_Matrix(0,2);
|
|
m(0,3) = m_Matrix(0,3);
|
|
|
|
m(1,0) = m_Matrix(1,0);
|
|
m(1,1) = fiScaleY;
|
|
m(1,2) = m_Matrix(1,2);
|
|
m(1,3) = m_Matrix(1,3);
|
|
|
|
m(2,0) = m_Matrix(2,0);
|
|
m(2,1) = m_Matrix(2,1);
|
|
m(2,2) = fiScaleZ;
|
|
m(2,3) = m_Matrix(2,3);
|
|
|
|
m(3,0) = -m_Matrix(3,0) * fiScaleX;
|
|
m(3,1) = -m_Matrix(3,1) * fiScaleY;
|
|
m(3,2) = -m_Matrix(3,2) * fiScaleZ;
|
|
m(3,3) = m_Matrix(3,3);
|
|
}
|
|
else
|
|
if (m_ObjFlags & FOB_TRANS_TRANSLATE)
|
|
{
|
|
m(0,0) = m_Matrix(0,0);
|
|
m(0,1) = m_Matrix(0,1);
|
|
m(0,2) = m_Matrix(0,2);
|
|
m(0,3) = m_Matrix(0,3);
|
|
|
|
m(1,0) = m_Matrix(1,0);
|
|
m(1,1) = m_Matrix(1,1);
|
|
m(1,2) = m_Matrix(1,2);
|
|
m(1,3) = m_Matrix(1,3);
|
|
|
|
m(2,0) = m_Matrix(2,0);
|
|
m(2,1) = m_Matrix(2,1);
|
|
m(2,2) = m_Matrix(2,2);
|
|
m(2,3) = m_Matrix(2,3);
|
|
|
|
m(3,0) = -m_Matrix(3,0);
|
|
m(3,1) = -m_Matrix(3,1);
|
|
m(3,2) = -m_Matrix(3,2);
|
|
m(3,3) = m_Matrix(3,3);
|
|
}
|
|
else
|
|
m.SetIdentity();
|
|
|
|
return m;
|
|
}
|
|
|
|
// Get Project-ModelView matrix for the current object
|
|
// This matrix is passed to the vertex shader
|
|
// All matrices are 16 bytes alligned to speedup matrix calculations using SSE instructions
|
|
Matrix44 &CCObject::GetVPMatrix()
|
|
{
|
|
CRenderer *rd = gRenDev;
|
|
if (m_VPMatrixId == 0)
|
|
return rd->m_CameraProjMatrix;
|
|
if (m_VPMatrixId > 0 && m_VPMatrixFrame == rd->m_RP.m_TransformFrame)
|
|
return m_ObjMatrices[m_VPMatrixId];
|
|
m_VPMatrixFrame = rd->m_RP.m_TransformFrame;
|
|
|
|
int n = m_ObjMatrices.size();
|
|
m_ObjMatrices.resize(n+1);
|
|
m_VPMatrixId = n;
|
|
|
|
Matrix44 &m = m_ObjMatrices[m_VPMatrixId];
|
|
|
|
mathMatrixMultiply(m.GetData(), rd->m_CameraProjMatrix.GetData(), m_Matrix.GetData(), g_CpuFlags);
|
|
//D3DXMatrixMultiplyTranspose((D3DXMATRIX *)m.GetData(), (D3DXMATRIX *)m_Matrix.GetData(), (D3DXMATRIX *)rd->m_CameraProjMatrix.GetData());
|
|
|
|
return m;
|
|
}
|
|
|
|
// Set scissor rectangle for the current object
|
|
void CCObject::SetScissor()
|
|
{
|
|
if (CRenderer::CV_r_scissor)
|
|
{
|
|
if (m_nScissorX2)
|
|
{
|
|
int w = m_nScissorX2 - m_nScissorX1;
|
|
int h = m_nScissorY2 - m_nScissorY1;
|
|
gcpRendD3D->EF_Scissor(true, m_nScissorX1, m_nScissorY1, w, h);
|
|
}
|
|
else
|
|
gcpRendD3D->EF_Scissor(false, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
// Sets per-object alpha blending state to fade-in/fade-out objects on the distance
|
|
void CCObject::SetAlphaState(CPShader *pPS, int nCurState)
|
|
{
|
|
CD3D9Renderer *rd = gcpRendD3D;
|
|
// Fake to prevent light coronas from custom blending
|
|
if (!rd->m_RP.m_pRE || rd->m_RP.m_pRE->mfGetType() != eDATA_OcLeaf)
|
|
return;
|
|
if (rd->m_RP.m_pShader->m_Flags2 & EF2_IGNORERESOURCESTATES)
|
|
return;
|
|
|
|
if (!(nCurState & GS_BLEND_MASK) && !(rd->m_RP.m_ResourceState & GS_BLEND_MASK))
|
|
{
|
|
int State = rd->m_CurState &= ~GS_BLEND_MASK;
|
|
State |= GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;
|
|
State &= ~GS_DEPTHWRITE;
|
|
rd->EF_SetState(State);
|
|
}
|
|
else
|
|
if (rd->m_CurState & GS_DEPTHFUNC_EQUAL)
|
|
rd->EF_SetState(rd->m_CurState & ~GS_DEPTHFUNC_EQUAL);
|
|
|
|
rd->m_RP.m_fCurOpacity = rd->m_RP.m_pCurObject->m_Color.a;
|
|
if (!pPS)
|
|
{
|
|
float fColor = 1.0f;
|
|
int State = rd->m_RP.m_ResourceState & GS_BLEND_MASK;
|
|
if (!State)
|
|
State = nCurState & GS_BLEND_MASK;
|
|
if (State == (GS_BLSRC_DSTCOL | GS_BLDST_ZERO) || State == (GS_BLSRC_ZERO | GS_BLDST_SRCCOL))
|
|
{
|
|
fColor = rd->m_RP.m_fCurOpacity;
|
|
byte bCol = (byte)((1.0f-fColor)*255.0f);
|
|
rd->m_RP.m_NeedGlobalColor.bcolor[0] = bCol;
|
|
rd->m_RP.m_NeedGlobalColor.bcolor[1] = bCol;
|
|
rd->m_RP.m_NeedGlobalColor.bcolor[2] = bCol;
|
|
rd->m_RP.m_NeedGlobalColor.bcolor[3] = (byte)(rd->m_RP.m_fCurOpacity * 255.0f);
|
|
rd->m_RP.m_TexStages[0].m_CO = eCO_ADD;
|
|
rd->m_RP.m_TexStages[0].m_AO = eCO_MODULATE;
|
|
rd->m_RP.m_TexStages[0].m_CA = eCA_Texture | (eCA_Constant<<3);
|
|
rd->m_RP.m_TexStages[0].m_AA = eCA_Texture | (eCA_Constant<<3);
|
|
rd->m_RP.m_FlagsPerFlush |= RBSI_GLOBALRGB;
|
|
}
|
|
else
|
|
if (State == (GS_BLSRC_ONE | GS_BLDST_ONE))
|
|
{
|
|
fColor = rd->m_RP.m_fCurOpacity;
|
|
byte bCol = (byte)(fColor*255.0f);
|
|
rd->m_RP.m_NeedGlobalColor.bcolor[0] = bCol;
|
|
rd->m_RP.m_NeedGlobalColor.bcolor[1] = bCol;
|
|
rd->m_RP.m_NeedGlobalColor.bcolor[2] = bCol;
|
|
rd->m_RP.m_NeedGlobalColor.bcolor[3] = bCol;
|
|
rd->m_RP.m_TexStages[0].m_CO = eCO_MODULATE;
|
|
rd->m_RP.m_TexStages[0].m_AO = eCO_MODULATE;
|
|
rd->m_RP.m_TexStages[0].m_CA = eCA_Texture | (eCA_Constant<<3);
|
|
rd->m_RP.m_TexStages[0].m_AA = eCA_Texture | (eCA_Constant<<3);
|
|
rd->m_RP.m_FlagsPerFlush |= RBSI_GLOBALRGB;
|
|
}
|
|
else
|
|
{
|
|
rd->m_RP.m_NeedGlobalColor.bcolor[3] = (byte)(rd->m_RP.m_fCurOpacity * 255.0f);
|
|
rd->m_RP.m_TexStages[0].m_AO = eCO_MODULATE;
|
|
rd->m_RP.m_TexStages[0].m_AA = eCA_Texture | (eCA_Constant<<3);
|
|
rd->m_RP.m_FlagsPerFlush |= RBSI_GLOBALALPHA;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set object transform for fixed pipeline shader
|
|
void CD3D9Renderer::EF_SetObjectTransform(CCObject *obj, SShader *pSH, int nTransFlags)
|
|
{
|
|
if (nTransFlags & FOB_TRANS_MASK)
|
|
mathMatrixMultiply(m_ViewMatrix.GetData(), m_CameraMatrix.GetData(), obj->m_Matrix.GetData(), g_CpuFlags);
|
|
else
|
|
m_ViewMatrix = m_CameraMatrix;
|
|
if (!pSH || !(pSH->m_Flags & EF_HASVSHADER))
|
|
{
|
|
m_matView->LoadMatrix((D3DXMATRIX *)m_ViewMatrix.GetData());
|
|
m_pd3dDevice->SetTransform(D3DTS_VIEW, m_matView->GetTop());
|
|
m_RP.m_PersFlags &= ~RBPF_MATRIXNOTLOADED;
|
|
}
|
|
else
|
|
m_RP.m_PersFlags |= RBPF_MATRIXNOTLOADED;
|
|
m_bInvertedMatrix = false;
|
|
}
|
|
|
|
// Object changing handling (skinning, shadow maps updating, initial states setting, ...)
|
|
bool CD3D9Renderer::EF_ObjectChange(SShader *Shader, SRenderShaderResources *Res, int nObject, CRendElement *pRE)
|
|
{
|
|
//PROFILE_FRAME(Objects_Changes);
|
|
|
|
CCObject *obj = m_RP.m_VisObjects[nObject];
|
|
if ((obj->m_ObjFlags & FOB_NEAREST) && ((m_RP.m_PersFlags & RBPF_DONTDRAWNEAREST) || CV_r_nodrawnear))
|
|
return false;
|
|
|
|
if (Shader)
|
|
{
|
|
if (m_RP.m_pIgnoreObject && !(Shader->m_Flags & EF_SKY) && IsEquivalent(m_RP.m_pIgnoreObject->GetTranslation(), obj->GetTranslation()))
|
|
return false;
|
|
if ((m_RP.m_PersFlags & RBPF_ONLYREFRACTED) && !(obj->m_ObjFlags & FOB_REFRACTED))
|
|
return false;
|
|
if ((m_RP.m_PersFlags & RBPF_IGNOREREFRACTED) && (obj->m_ObjFlags & FOB_REFRACTED))
|
|
return false;
|
|
}
|
|
|
|
if (obj == m_RP.m_pPrevObject)
|
|
return true;
|
|
|
|
m_RP.m_FrameObject++;
|
|
m_RP.m_pCurObject = obj;
|
|
|
|
bool bTheSameCM = false;
|
|
if (m_RP.m_pPrevObject && (m_RP.m_pPrevObject->m_ObjFlags & FOB_CUBE_MASK))
|
|
{
|
|
bTheSameCM = (obj && (obj->m_ObjFlags & FOB_CUBE_MASK) == (m_RP.m_pPrevObject->m_ObjFlags & FOB_CUBE_MASK));
|
|
if (!bTheSameCM)
|
|
{
|
|
bool bNeedClear;
|
|
if (obj && (obj->m_ObjFlags & FOB_CUBE_MASK))
|
|
bNeedClear = false;
|
|
else
|
|
bNeedClear = true;
|
|
m_TexMan->EndCubeSide(m_RP.m_pPrevObject, bNeedClear);
|
|
}
|
|
}
|
|
|
|
int flags = 0;
|
|
if (nObject)
|
|
{
|
|
m_RP.m_PS.m_NumRendObjects++;
|
|
|
|
// Skinning
|
|
if (obj->m_pCharInstance && !CV_r_character_nodeform)
|
|
{
|
|
PROFILE_FRAME(Objects_ChangesSkinning);
|
|
double time0 = 0;
|
|
ticks(time0);
|
|
m_RP.m_PS.m_NumRendSkinnedObjects++;
|
|
CREOcLeaf *pREOCL = (CREOcLeaf *)pRE;
|
|
int nFlags = 0;
|
|
int nVertFormat = -1;
|
|
if (pREOCL->m_pBuffer && pREOCL->m_pBuffer->m_pMats)
|
|
{
|
|
for (int i=0; i<pREOCL->m_pBuffer->m_pMats->Count(); i++)
|
|
{
|
|
CMatInfo *mi = pREOCL->m_pBuffer->m_pMats->Get(i);
|
|
if (!mi->pRE || !mi->shaderItem.m_pShader)
|
|
continue;
|
|
SShader *pSH = (SShader *)mi->shaderItem.m_pShader->GetTemplate(-1);
|
|
if (pSH->m_Flags3 & EF3_NODRAW)
|
|
continue;
|
|
if (nVertFormat < 0)
|
|
nVertFormat = pSH->m_VertexFormatId;
|
|
else
|
|
nVertFormat = m_RP.m_VFormatsMerge[nVertFormat][pSH->m_VertexFormatId];
|
|
|
|
if (Shader->m_Flags & EF_NEEDTANGENTS)
|
|
nFlags |= SHPF_TANGENTS;
|
|
if (mi->shaderItem.m_pShaderResources && mi->shaderItem.m_pShaderResources->m_bNeedNormals)
|
|
nFlags |= SHPF_NORMALS;
|
|
}
|
|
pRE->mfCheckUpdate(nVertFormat, nFlags | FHF_FORANIM);
|
|
CLeafBuffer *pLB = pREOCL->m_pBuffer->GetVertexContainer();
|
|
bool bForceUpdate = (pLB->m_UpdateFrame == GetFrameID());
|
|
if (pLB->m_pVertexBuffer && pLB->m_pVertexBuffer->m_bFenceSet)
|
|
bForceUpdate = true;
|
|
obj->m_pCharInstance->ProcessSkinning(obj->m_Matrix.GetTranslationOLD(), obj->m_Matrix, obj->m_nTemplId, obj->m_nLod, bForceUpdate);
|
|
}
|
|
unticks(time0);
|
|
m_RP.m_PS.m_fSkinningTime += (float)(time0*1000.0*g_SecondsPerCycle);
|
|
}
|
|
|
|
// shadow map generation
|
|
if (obj->m_pShadowCasters)
|
|
{
|
|
// process casters maps
|
|
for(int i=0; i<obj->m_pShadowCasters->Count(); i++)
|
|
if(obj->m_pShadowCasters->GetAt(i).m_pLS && obj->m_pShadowCasters->GetAt(i).m_pLS->GetShadowMapFrustum())
|
|
{
|
|
#ifdef DO_RENDERLOG
|
|
if (m_LogFile)
|
|
Logv(SRendItem::m_RecurseLevel, "*** Prepare shadow maps for REOcLeaf***\n");
|
|
#endif
|
|
PrepareDepthMap(obj->m_pShadowCasters->GetAt(i).m_pLS->GetShadowMapFrustum(), false);
|
|
m_RP.m_pCurObject = obj;
|
|
}
|
|
|
|
// process receiver map
|
|
/*if(obj->m_pShadowCasters->Count() && obj->m_pShadowCasters->GetAt(0).m_pLS)
|
|
if(obj->m_pShadowCasters->GetAt(0).m_pLS->GetShadowMapFrustumPassiveCasters())
|
|
PrepareDepthMap(obj->m_pShadowCasters->GetAt(0).m_pLS->GetShadowMapFrustumPassiveCasters(), false);
|
|
m_RP.m_pCurObject = obj;*/
|
|
}
|
|
|
|
if(obj->m_ObjFlags & FOB_NEAREST)
|
|
flags |= RBF_NEAREST;
|
|
|
|
if ((flags ^ m_RP.m_Flags) & RBF_NEAREST)
|
|
{
|
|
if (flags & RBF_NEAREST)
|
|
{
|
|
CCamera Cam = GetCamera();
|
|
m_RP.m_PrevCamera = Cam;
|
|
Cam.SetZMin(0.01f);
|
|
Cam.SetZMax(40.0f);
|
|
if (m_LogFile)
|
|
Logv(SRendItem::m_RecurseLevel, "*** Prepare nearest Z range ***\n");
|
|
|
|
// set nice fov for weapons
|
|
Cam.SetFov( Cam.GetFov() * 0.6666f );
|
|
SetCamera(Cam);
|
|
m_Viewport.MaxZ = 0.1f;
|
|
m_pd3dDevice->SetViewport(&m_Viewport);
|
|
m_RP.m_Flags |= RBF_NEAREST;
|
|
}
|
|
else
|
|
{
|
|
if (m_LogFile)
|
|
Logv(SRendItem::m_RecurseLevel, "*** Restore Z range ***\n");
|
|
|
|
SetCamera(m_RP.m_PrevCamera);
|
|
m_Viewport.MaxZ = 1.0f;
|
|
m_pd3dDevice->SetViewport(&m_Viewport);
|
|
m_RP.m_Flags &= ~RBF_NEAREST;
|
|
}
|
|
}
|
|
if ((obj->m_ObjFlags & FOB_CUBE_MASK) && !bTheSameCM)
|
|
m_TexMan->StartCubeSide(obj);
|
|
}
|
|
else
|
|
{
|
|
if (m_RP.m_Flags & RBF_NEAREST)
|
|
{
|
|
if (m_LogFile)
|
|
Logv(SRendItem::m_RecurseLevel, "*** Restore Z range ***\n");
|
|
SetCamera(m_RP.m_PrevCamera);
|
|
m_Viewport.MaxZ = 1.0f;
|
|
m_pd3dDevice->SetViewport(&m_Viewport);
|
|
m_RP.m_Flags &= ~RBF_NEAREST;
|
|
}
|
|
m_RP.m_pCurObject->m_Matrix.SetIdentity();
|
|
m_ViewMatrix = m_CameraMatrix;
|
|
// Restore transform
|
|
if (!Shader || !(Shader->m_Flags & EF_HASVSHADER))
|
|
{
|
|
m_RP.m_PersFlags &= ~RBPF_MATRIXNOTLOADED;
|
|
m_matView->LoadMatrix((D3DXMATRIX *)&m_CameraMatrix(0,0));
|
|
m_pd3dDevice->SetTransform(D3DTS_VIEW, m_matView->GetTop());
|
|
}
|
|
else
|
|
m_RP.m_PersFlags |= RBPF_MATRIXNOTLOADED;
|
|
m_bInvertedMatrix = false;
|
|
}
|
|
m_RP.m_pPrevObject = m_RP.m_pCurObject;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Set clip plane for the current scene
|
|
// on NVidia GPUs we use fake clip planes using texkill PS instruction : m_RP.m_ClipPlaneEnabled = 1
|
|
// on ATI hardware we use native ClipPlanes : m_RP.m_ClipPlaneEnabled = 2
|
|
void CD3D9Renderer::EF_SetClipPlane (bool bEnable, float *pPlane, bool bRefract)
|
|
{
|
|
if (!CV_d3d9_clipplanes)
|
|
return;
|
|
|
|
if (bEnable)
|
|
{
|
|
#ifdef DO_RENDERLOG
|
|
if (CV_r_log)
|
|
Logv(SRendItem::m_RecurseLevel, "Set clip-plane\n");
|
|
#endif
|
|
if (m_RP.m_ClipPlaneEnabled)
|
|
return;
|
|
float p[4];
|
|
p[0] = pPlane[0];
|
|
p[1] = pPlane[1];
|
|
p[2] = pPlane[2];
|
|
p[3] = pPlane[3];
|
|
//if (bRefract)
|
|
//p[3] += 0.1f;
|
|
m_RP.m_ClipPlaneWasOverrided = 0;
|
|
m_RP.m_bClipPlaneRefract = bRefract;
|
|
m_RP.m_CurClipPlane.m_Normal.x = p[0];
|
|
m_RP.m_CurClipPlane.m_Normal.y = p[1];
|
|
m_RP.m_CurClipPlane.m_Normal.z = p[2];
|
|
m_RP.m_CurClipPlane.m_Dist = p[3];
|
|
m_RP.m_CurClipPlane.Init();
|
|
|
|
m_RP.m_CurClipPlaneCull = m_RP.m_CurClipPlane;
|
|
m_RP.m_CurClipPlaneCull.m_Dist = -m_RP.m_CurClipPlaneCull.m_Dist;
|
|
int nGPU = m_Features & RFT_HW_MASK;
|
|
if (m_d3dCaps.MaxUserClipPlanes > 0 && nGPU != RFT_HW_GF3 && nGPU != RFT_HW_GF2 && nGPU != RFT_HW_GFFX)
|
|
{
|
|
m_RP.m_ClipPlaneEnabled = 2;
|
|
m_pd3dDevice->SetClipPlane(0, p);
|
|
m_pd3dDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 1);
|
|
}
|
|
else
|
|
{
|
|
m_RP.m_ClipPlaneEnabled = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DO_RENDERLOG
|
|
if (CV_r_log)
|
|
Logv(SRendItem::m_RecurseLevel, "Reset clip-plane\n");
|
|
#endif
|
|
m_RP.m_ClipPlaneEnabled = 0;
|
|
m_RP.m_ClipPlaneWasOverrided = 0;
|
|
|
|
if (m_d3dCaps.MaxUserClipPlanes > 0)
|
|
{
|
|
m_pd3dDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
// Shader Pipeline
|
|
//=======================================================================
|
|
|
|
// Software vertex deformations stages handling for the current shader
|
|
void CD3D9Renderer::EF_Eval_DeformVerts(TArray<SDeform>* Defs)
|
|
{
|
|
int i;
|
|
|
|
if (!Defs)
|
|
return;
|
|
|
|
for (i=0; i<Defs->Num(); i++)
|
|
{
|
|
SDeform *df = &Defs->Get(i);
|
|
switch (df->m_eType)
|
|
{
|
|
case eDT_Wave:
|
|
m_RP.m_pCurFuncs->WaveDeform(df);
|
|
break;
|
|
|
|
case eDT_Flare:
|
|
m_RP.m_pCurFuncs->FlareDeform(df);
|
|
break;
|
|
|
|
case eDT_Beam:
|
|
m_RP.m_pCurFuncs->BeamDeform(df);
|
|
break;
|
|
|
|
case eDT_VerticalWave:
|
|
m_RP.m_pCurFuncs->VerticalWaveDeform(df);
|
|
break;
|
|
|
|
case eDT_Bulge:
|
|
m_RP.m_pCurFuncs->BulgeDeform(df);
|
|
break;
|
|
|
|
case eDT_FromCenter:
|
|
m_RP.m_pCurFuncs->FromCenterDeform(df);
|
|
break;
|
|
|
|
case eDT_Squeeze:
|
|
m_RP.m_pCurFuncs->SqueezeDeform(df);
|
|
break;
|
|
|
|
default:
|
|
iLog->Log("Unknown deform type %d in Shader '%s'\n", df->m_eType, m_RP.m_pShader->m_Name);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Software/hardware texture coordinates generating modes handling for the current shader
|
|
void CD3D9Renderer::EF_Eval_TexGen(SShaderPass *sfm)
|
|
{
|
|
int j, n;
|
|
SShaderTexUnit *shl;
|
|
SShader *ef = m_RP.m_pShader;
|
|
SMRendTexVert *src;
|
|
int m;
|
|
|
|
for (j=0; j<sfm->m_TUnits.Num(); j++)
|
|
{
|
|
shl = &sfm->m_TUnits[j];
|
|
|
|
if (!shl->m_TexPic || shl->m_GTC)
|
|
continue;
|
|
|
|
switch (shl->m_eGenTC)
|
|
{
|
|
case eGTC_NoFill:
|
|
break;
|
|
|
|
case eGTC_None:
|
|
break;
|
|
|
|
case eGTC_Base:
|
|
if (!m_RP.m_pRE)
|
|
{
|
|
m = m_RP.m_RendNumVerts;
|
|
src = m_RP.m_pBaseTexCoordPointer;
|
|
byte *ptr = m_RP.m_Ptr.PtrB + m_RP.m_OffsT + j*16;
|
|
for (n=0; n<m; n++, ptr+=m_RP.m_Stride)
|
|
{
|
|
*(float *)(ptr) = src[n].vert[0];
|
|
*(float *)(ptr+4) = src[n].vert[1];
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eGTC_LightMap:
|
|
if (!m_RP.m_pRE)
|
|
{
|
|
m = m_RP.m_RendNumVerts;
|
|
src = m_RP.m_pLMTexCoordPointer;
|
|
byte *ptr = m_RP.m_Ptr.PtrB + m_RP.m_OffsT + j*16;
|
|
for (n=0; n<m; n++, ptr+=m_RP.m_Stride)
|
|
{
|
|
*(float *)(ptr) = src[n].vert[0];
|
|
*(float *)(ptr+4) = src[n].vert[1];
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eGTC_Environment:
|
|
m_RP.m_pCurFuncs->ETC_Environment(j);
|
|
break;
|
|
|
|
case eGTC_Projection:
|
|
if (shl->m_TexPic->m_Matrix)
|
|
m_RP.m_pCurFuncs->ETC_Projection(j, shl->m_TexPic->m_Matrix, 1, 1);
|
|
break;
|
|
|
|
case eGTC_SphereMap:
|
|
m_RP.m_pCurFuncs->ETC_SphereMap(j);
|
|
break;
|
|
|
|
case eGTC_SphereMapEnvironment:
|
|
m_RP.m_pCurFuncs->ETC_SphereMapEnvironment(j);
|
|
break;
|
|
|
|
case eGTC_ShadowMap:
|
|
m_RP.m_pCurFuncs->ETC_ShadowMap(j);
|
|
break;
|
|
|
|
default:
|
|
iLog->Log("ERROR: invalid eGenTC '%d' specified for Shader\n", shl->m_eGenTC);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Software/hardware RGBA generating/modificating modes handling for the current shader
|
|
void CD3D9Renderer::EF_Eval_RGBAGen(SShaderPass *sfm)
|
|
{
|
|
SShader *ef = m_RP.m_pShader;
|
|
int n;
|
|
UCol color;
|
|
bool bSetCol = false;
|
|
color = m_RP.m_NeedGlobalColor;
|
|
|
|
switch(sfm->m_eEvalRGB)
|
|
{
|
|
case eERGB_NoFill:
|
|
break;
|
|
|
|
case eERGB_Identity:
|
|
{
|
|
if (m_RP.m_pRE)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_RGBGEN))
|
|
{
|
|
color.dcolor = -1;
|
|
bSetCol = true;
|
|
m_RP.m_FlagsPerFlush |= RBSI_RGBGEN;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
byte *ptr = m_RP.m_Ptr.PtrB+m_RP.m_OffsD;
|
|
for (n=0; n<m_RP.m_RendNumVerts; n++, ptr+=m_RP.m_Stride)
|
|
{
|
|
*(uint *)ptr = -1;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eERGB_FromClient:
|
|
if (!m_RP.m_pRE)
|
|
{
|
|
if (!gbRgb)
|
|
{
|
|
byte *ptr = m_RP.m_Ptr.PtrB+m_RP.m_OffsD;
|
|
byte *src = (byte *)(m_RP.m_pClientColors[0]);
|
|
for (n=0; n<m_RP.m_RendNumVerts; n++, ptr+=m_RP.m_Stride, src+=4)
|
|
{
|
|
*(uint *)ptr = *(uint *)(src);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
byte *ptr = m_RP.m_Ptr.PtrB+m_RP.m_OffsD;
|
|
byte *src = (byte *)(&m_RP.m_pClientColors[0]);
|
|
for (n=0; n<m_RP.m_RendNumVerts; n++, ptr+=m_RP.m_Stride, src+=4)
|
|
{
|
|
ptr[2] = src[0];
|
|
ptr[1] = src[1];
|
|
ptr[0] = src[2];
|
|
ptr[3] = src[3];
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eERGB_OneMinusFromClient:
|
|
if (!m_RP.m_pRE)
|
|
{
|
|
if (!gbRgb)
|
|
{
|
|
byte *ptr = m_RP.m_Ptr.PtrB+m_RP.m_OffsD;
|
|
for (n=0; n<m_RP.m_RendNumVerts; n++, ptr+=m_RP.m_Stride)
|
|
{
|
|
ptr[0] = 255 - m_RP.m_pClientColors[n][0];
|
|
ptr[1] = 255 - m_RP.m_pClientColors[n][1];
|
|
ptr[2] = 255 - m_RP.m_pClientColors[n][2];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
byte *ptr = m_RP.m_Ptr.PtrB+m_RP.m_OffsD;
|
|
for (n=0; n<m_RP.m_RendNumVerts; n++, ptr+=m_RP.m_Stride)
|
|
{
|
|
ptr[0] = 255 - m_RP.m_pClientColors[n][2];
|
|
ptr[1] = 255 - m_RP.m_pClientColors[n][1];
|
|
ptr[2] = 255 - m_RP.m_pClientColors[n][0];
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eERGB_Fixed:
|
|
color = sfm->m_FixedColor;
|
|
bSetCol = true;
|
|
m_RP.m_FlagsPerFlush |= RBSI_RGBGEN;
|
|
break;
|
|
|
|
case eERGB_StyleIntens:
|
|
{
|
|
CLightStyle *ls = CLightStyle::mfGetStyle(sfm->m_Style, m_RP.m_RealTime);
|
|
color = sfm->m_FixedColor;
|
|
color.bcolor[0] = (byte)((float)color.bcolor[0] * ls->m_fIntensity);
|
|
color.bcolor[1] = (byte)((float)color.bcolor[1] * ls->m_fIntensity);
|
|
color.bcolor[2] = (byte)((float)color.bcolor[2] * ls->m_fIntensity);
|
|
bSetCol = true;
|
|
m_RP.m_FlagsPerFlush |= RBSI_RGBGEN;
|
|
}
|
|
break;
|
|
|
|
case eERGB_StyleColor:
|
|
{
|
|
CLightStyle *ls = CLightStyle::mfGetStyle(sfm->m_Style, m_RP.m_RealTime);
|
|
color.dcolor = ls->m_Color.GetTrue();
|
|
bSetCol = true;
|
|
m_RP.m_FlagsPerFlush |= RBSI_RGBGEN;
|
|
}
|
|
break;
|
|
|
|
case eERGB_Comps:
|
|
{
|
|
if (sfm->m_RGBComps)
|
|
{
|
|
float *vals = sfm->m_RGBComps->mfGet();
|
|
color.bcolor[0] = (byte)(vals[0] * 255.0f);
|
|
color.bcolor[1] = (byte)(vals[1] * 255.0f);
|
|
color.bcolor[2] = (byte)(vals[2] * 255.0f);
|
|
color.bcolor[3] = (byte)(vals[3] * 255.0f);
|
|
bSetCol = true;
|
|
m_RP.m_FlagsPerFlush |= RBSI_RGBGEN;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eERGB_Wave:
|
|
if (sfm->m_WaveEvalRGB)
|
|
{
|
|
if (m_RP.m_pRE)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_RGBGEN))
|
|
{
|
|
float val = SEvalFuncs::EvalWaveForm(sfm->m_WaveEvalRGB);
|
|
if (val < 0)
|
|
val = 0;
|
|
if (val > 1)
|
|
val = 1;
|
|
|
|
color.bcolor[0] = color.bcolor[1] = color.bcolor[2] = (int)(val * 255.0f);
|
|
COLCONV(color.dcolor);
|
|
bSetCol = true;
|
|
m_RP.m_FlagsPerFlush |= RBSI_RGBGEN;
|
|
}
|
|
}
|
|
else
|
|
m_RP.m_pCurFuncs->ERGB_Wave(sfm->m_WaveEvalRGB, color);
|
|
}
|
|
break;
|
|
|
|
case eERGB_Noise:
|
|
if (sfm->m_RGBNoise)
|
|
{
|
|
if (m_RP.m_pRE)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_RGBGEN))
|
|
{
|
|
float v = RandomNum();
|
|
byte r = (byte)(CLAMP(v * sfm->m_RGBNoise->m_RangeR + sfm->m_RGBNoise->m_ConstR, 0.0f, 1.0f) * 255.0f);
|
|
v = RandomNum();
|
|
byte g = (byte)(CLAMP(v * sfm->m_RGBNoise->m_RangeG + sfm->m_RGBNoise->m_ConstG, 0.0f, 1.0f) * 255.0f);
|
|
v = RandomNum();
|
|
byte b = (byte)(CLAMP(v * sfm->m_RGBNoise->m_RangeB + sfm->m_RGBNoise->m_ConstB, 0.0f, 1.0f) * 255.0f);
|
|
|
|
color.bcolor[0] = r;
|
|
color.bcolor[1] = g;
|
|
color.bcolor[2] = b;
|
|
COLCONV(color.dcolor);
|
|
bSetCol = true;
|
|
m_RP.m_FlagsPerFlush |= RBSI_RGBGEN;
|
|
}
|
|
}
|
|
else
|
|
m_RP.m_pCurFuncs->ERGB_Noise(sfm->m_RGBNoise, color);
|
|
}
|
|
break;
|
|
|
|
case eERGB_Object:
|
|
if (m_RP.m_pRE)
|
|
{
|
|
if (m_RP.m_pCurObject && !(m_RP.m_FlagsPerFlush & RBSI_RGBGEN))
|
|
{
|
|
bSetCol = true;
|
|
color.bcolor[0] = (byte)(m_RP.m_pCurObject->m_Color[0] * 255.0f);
|
|
color.bcolor[1] = (byte)(m_RP.m_pCurObject->m_Color[1] * 255.0f);
|
|
color.bcolor[2] = (byte)(m_RP.m_pCurObject->m_Color[2] * 255.0f);
|
|
m_RP.m_FlagsPerFlush |= RBSI_RGBGEN;
|
|
}
|
|
}
|
|
else
|
|
m_RP.m_pCurFuncs->ERGB_Object();
|
|
break;
|
|
|
|
case eERGB_OneMinusObject:
|
|
if (m_RP.m_pRE)
|
|
{
|
|
if (m_RP.m_pCurObject && !(m_RP.m_FlagsPerFlush & RBSI_RGBGEN))
|
|
{
|
|
bSetCol = true;
|
|
color.bcolor[0] = (byte)((1.0f - m_RP.m_pCurObject->m_Color[0]) * 255.0f);
|
|
color.bcolor[1] = (byte)((1.0f - m_RP.m_pCurObject->m_Color[1]) * 255.0f);
|
|
color.bcolor[2] = (byte)((1.0f - m_RP.m_pCurObject->m_Color[2]) * 255.0f);
|
|
m_RP.m_FlagsPerFlush |= RBSI_RGBGEN;
|
|
}
|
|
}
|
|
else
|
|
m_RP.m_pCurFuncs->ERGB_OneMinusObject();
|
|
break;
|
|
|
|
case eERGB_RE:
|
|
if (m_RP.m_pRE && !(m_RP.m_FlagsPerFlush & RBSI_RGBGEN))
|
|
{
|
|
bSetCol = true;
|
|
color.bcolor[0] = (byte)(m_RP.m_pRE->m_Color[0] * 255.0f);
|
|
color.bcolor[1] = (byte)(m_RP.m_pRE->m_Color[1] * 255.0f);
|
|
color.bcolor[2] = (byte)(m_RP.m_pRE->m_Color[2] * 255.0f);
|
|
m_RP.m_FlagsPerFlush |= RBSI_RGBGEN;
|
|
}
|
|
break;
|
|
|
|
case eERGB_OneMinusRE:
|
|
if (m_RP.m_pRE && !(m_RP.m_FlagsPerFlush & RBSI_RGBGEN))
|
|
{
|
|
bSetCol = true;
|
|
color.bcolor[0] = (byte)((1.0f - m_RP.m_pRE->m_Color[0]) * 255.0f);
|
|
color.bcolor[1] = (byte)((1.0f - m_RP.m_pRE->m_Color[1]) * 255.0f);
|
|
color.bcolor[2] = (byte)((1.0f - m_RP.m_pRE->m_Color[2]) * 255.0f);
|
|
m_RP.m_FlagsPerFlush |= RBSI_RGBGEN;
|
|
}
|
|
break;
|
|
|
|
case eERGB_World:
|
|
if (m_RP.m_pRE && !(m_RP.m_FlagsPerFlush & RBSI_RGBGEN))
|
|
{
|
|
bSetCol = true;
|
|
color.bcolor[0] = (byte)(gRenDev->m_WorldColor[0] * 255.0f);
|
|
color.bcolor[1] = (byte)(gRenDev->m_WorldColor[1] * 255.0f);
|
|
color.bcolor[2] = (byte)(gRenDev->m_WorldColor[2] * 255.0f);
|
|
m_RP.m_FlagsPerFlush |= RBSI_RGBGEN;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
assert(0);
|
|
}
|
|
|
|
switch(sfm->m_eEvalAlpha)
|
|
{
|
|
case eEALPHA_NoFill:
|
|
break;
|
|
|
|
case eEALPHA_Identity:
|
|
if (sfm->m_eEvalRGB!=eERGB_Identity && sfm->m_eEvalRGB!=eERGB_Fixed)
|
|
{
|
|
if (m_RP.m_pRE)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_RGBGEN))
|
|
{
|
|
color.bcolor[3] = 255;
|
|
bSetCol = true;
|
|
m_RP.m_FlagsPerFlush |= RBSI_RGBGEN;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
byte *ptr = m_RP.m_Ptr.PtrB+m_RP.m_OffsD;
|
|
for (n=0; n<m_RP.m_RendNumVerts; n++, ptr+=m_RP.m_Stride)
|
|
{
|
|
ptr[3] = 255;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eEALPHA_Fixed:
|
|
{
|
|
if (sfm->m_eEvalRGB == eERGB_Fixed)
|
|
break;
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN))
|
|
{
|
|
color.bcolor[3] = sfm->m_FixedColor.bcolor[3];
|
|
bSetCol = true;
|
|
m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eEALPHA_Style:
|
|
{
|
|
CLightStyle *ls = CLightStyle::mfGetStyle(sfm->m_Style, m_RP.m_RealTime);
|
|
color.bcolor[3] = (byte)((float)sfm->m_FixedColor.bcolor[3] * ls->m_fIntensity);
|
|
bSetCol = true;
|
|
m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN;
|
|
}
|
|
break;
|
|
|
|
case eEALPHA_Comps:
|
|
{
|
|
if (sfm->m_eEvalRGB == eERGB_Comps)
|
|
break;
|
|
if (sfm->m_RGBComps)
|
|
{
|
|
float *vals = sfm->m_RGBComps->mfGet();
|
|
if (m_RP.m_pRE)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN))
|
|
{
|
|
color.bcolor[3] = (byte)(vals[0] * 255.0f);
|
|
bSetCol = true;
|
|
m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
byte a = (byte)(vals[0] * 255.0f);
|
|
byte *ptr = m_RP.m_Ptr.PtrB+m_RP.m_OffsD;
|
|
for (n=0; n<m_RP.m_RendNumVerts; n++, ptr+=m_RP.m_Stride)
|
|
{
|
|
ptr[3] = a;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eEALPHA_Wave:
|
|
if (sfm->m_WaveEvalAlpha)
|
|
{
|
|
if (m_RP.m_pRE)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN))
|
|
{
|
|
float val = SEvalFuncs::EvalWaveForm(sfm->m_WaveEvalAlpha);
|
|
if (val < 0)
|
|
val = 0;
|
|
if (val > 1)
|
|
val = 1;
|
|
|
|
color.bcolor[3] = (int)(val * 255.0f);
|
|
bSetCol = true;
|
|
m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN;
|
|
}
|
|
}
|
|
else
|
|
m_RP.m_pCurFuncs->EALPHA_Wave(sfm->m_WaveEvalAlpha, color);
|
|
}
|
|
break;
|
|
|
|
case eEALPHA_Noise:
|
|
if (sfm->m_ANoise)
|
|
{
|
|
if (m_RP.m_pRE)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN))
|
|
{
|
|
float v = RandomNum();
|
|
byte a = (byte)(CLAMP(v * sfm->m_ANoise->m_RangeA + sfm->m_ANoise->m_ConstA, 0.0f, 1.0f) * 255.0f);
|
|
|
|
color.bcolor[3] = a;
|
|
bSetCol = true;
|
|
m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN;
|
|
}
|
|
}
|
|
else
|
|
m_RP.m_pCurFuncs->EALPHA_Noise(sfm->m_ANoise, color);
|
|
}
|
|
break;
|
|
|
|
case eEALPHA_Beam:
|
|
m_RP.m_pCurFuncs->EALPHA_Beam();
|
|
break;
|
|
|
|
case eEALPHA_Object:
|
|
if (m_RP.m_pRE)
|
|
{
|
|
if (m_RP.m_pCurObject && !(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN))
|
|
{
|
|
bSetCol = true;
|
|
color.bcolor[3] = (byte)(m_RP.m_pCurObject->m_Color[3] * 255.0f);
|
|
m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN;
|
|
}
|
|
}
|
|
else
|
|
m_RP.m_pCurFuncs->EALPHA_Object();
|
|
break;
|
|
|
|
case eEALPHA_OneMinusObject:
|
|
if (m_RP.m_pRE)
|
|
{
|
|
if (m_RP.m_pCurObject && !(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN))
|
|
{
|
|
bSetCol = true;
|
|
color.bcolor[3] = (byte)((1.0f - m_RP.m_pCurObject->m_Color[3]) * 255.0f);
|
|
m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN;
|
|
}
|
|
}
|
|
else
|
|
m_RP.m_pCurFuncs->EALPHA_OneMinusObject();
|
|
break;
|
|
|
|
case eEALPHA_RE:
|
|
if (m_RP.m_pRE)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN))
|
|
{
|
|
bSetCol = true;
|
|
color.bcolor[3] = (byte)(m_RP.m_pRE->m_Color[3] * 255.0f);
|
|
m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eEALPHA_OneMinusRE:
|
|
if (m_RP.m_pRE)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN))
|
|
{
|
|
bSetCol = true;
|
|
color.bcolor[3] = (byte)((1.0f - m_RP.m_pCurObject->m_Color[3]) * 255.0f);
|
|
m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eEALPHA_World:
|
|
if (m_RP.m_pRE)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHAGEN))
|
|
{
|
|
bSetCol = true;
|
|
color.bcolor[3] = (byte)(gRenDev->m_WorldColor[3] * 255.0f);
|
|
m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eEALPHA_FromClient:
|
|
if (!m_RP.m_pRE)
|
|
{
|
|
if (sfm->m_eEvalRGB!=eERGB_FromClient)
|
|
{
|
|
byte *ptr = m_RP.m_Ptr.PtrB+m_RP.m_OffsD;
|
|
for (n=0; n<m_RP.m_RendNumVerts; n++, ptr+=m_RP.m_Stride)
|
|
{
|
|
ptr[3] = m_RP.m_pClientColors[n][3];
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
assert(0);
|
|
}
|
|
|
|
if (bSetCol)
|
|
{
|
|
Exchange(color.bcolor[0], color.bcolor[2]);
|
|
m_RP.m_NeedGlobalColor = color;
|
|
//m_RP.m_FlagsPerFlush |= RBSI_GLOBALRGB | RBSI_GLOBALALPHA;
|
|
}
|
|
}
|
|
|
|
// Software Normals generating/modificating modes handling for the current shader
|
|
void CD3D9Renderer::EF_EvalNormalsRB(SShader *ef)
|
|
{
|
|
if (!ef->m_NormGen)
|
|
return;
|
|
|
|
SNormalsGen *ng = ef->m_NormGen;
|
|
|
|
if (ng->m_eNormal == eNORM_Identity || !m_RP.m_OffsN)
|
|
return;
|
|
|
|
int i;
|
|
int nums = m_RP.m_RendNumVerts;
|
|
byte *ptr = m_RP.m_Ptr.PtrB+m_RP.m_OffsN;
|
|
|
|
switch(ng->m_eNormal)
|
|
{
|
|
case eNORM_Custom:
|
|
for (i=0; i<nums; i++, ptr+=m_RP.m_Stride)
|
|
{
|
|
float *tsnrm = (float *)ptr;
|
|
tsnrm[0] = ng->m_CustomNormal[0];
|
|
tsnrm[1] = ng->m_CustomNormal[1];
|
|
tsnrm[2] = ng->m_CustomNormal[2];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Updating of textures animating sequence
|
|
void CD3D9Renderer::EF_UpdateTextures(SShaderPass *Layer)
|
|
{
|
|
SShaderTexUnit *stl;
|
|
int j;
|
|
for (j=0; j<Layer->m_TUnits.Num(); j++)
|
|
{
|
|
stl = &Layer->m_TUnits[j];
|
|
|
|
if (!stl->m_TexPic && !stl->m_AnimInfo)
|
|
break;
|
|
|
|
stl->mfUpdate();
|
|
}
|
|
}
|
|
|
|
// Updating of textures animating sequence
|
|
void CD3D9Renderer::EF_UpdateTextures(SShaderPassHW *Layer)
|
|
{
|
|
SShaderTexUnit *stl;
|
|
int j;
|
|
for (j=0; j<Layer->m_TUnits.Num(); j++)
|
|
{
|
|
stl = &Layer->m_TUnits[j];
|
|
|
|
if (!stl->m_TexPic && !stl->m_AnimInfo)
|
|
break;
|
|
|
|
stl->mfUpdate();
|
|
}
|
|
}
|
|
|
|
//=================================================================================
|
|
// Set current stencil states
|
|
void SStencil::mfSet()
|
|
{
|
|
gRenDev->EF_SetStencilState(m_State, m_FuncRef, m_FuncMask);
|
|
}
|
|
|
|
void CRenderer::EF_SetStencilState(int st, uint nStencRef, uint nStencMask)
|
|
{
|
|
LPDIRECT3DDEVICE9 dv = gcpRendD3D->mfGetD3DDevice();
|
|
if (nStencRef != m_CurStencRef)
|
|
{
|
|
m_CurStencRef = nStencRef;
|
|
dv->SetRenderState(D3DRS_STENCILREF, nStencRef);
|
|
}
|
|
if (nStencMask != m_CurStencMask)
|
|
{
|
|
m_CurStencMask = nStencMask;
|
|
dv->SetRenderState(D3DRS_STENCILMASK, nStencMask);
|
|
}
|
|
|
|
int Changed = st ^ m_CurStencilState;
|
|
if (!Changed)
|
|
return;
|
|
if (Changed & FSS_STENCIL_TWOSIDED)
|
|
{
|
|
if (st & FSS_STENCIL_TWOSIDED)
|
|
dv->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
|
|
else
|
|
dv->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
|
|
}
|
|
if (Changed & FSS_STENCFUNC_MASK)
|
|
{
|
|
int nCurFunc = st & FSS_STENCFUNC_MASK;
|
|
switch(nCurFunc)
|
|
{
|
|
case FSS_STENCFUNC_ALWAYS:
|
|
dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
|
|
break;
|
|
case FSS_STENCFUNC_NEVER:
|
|
dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_NEVER);
|
|
break;
|
|
case FSS_STENCFUNC_LESS:
|
|
dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_LESS);
|
|
break;
|
|
case FSS_STENCFUNC_LEQUAL:
|
|
dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_LESSEQUAL);
|
|
break;
|
|
case FSS_STENCFUNC_GREATER:
|
|
dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_GREATER);
|
|
break;
|
|
case FSS_STENCFUNC_GEQUAL:
|
|
dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_GREATEREQUAL);
|
|
break;
|
|
case FSS_STENCFUNC_EQUAL:
|
|
dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);
|
|
break;
|
|
case FSS_STENCFUNC_NOTEQUAL:
|
|
dv->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_NOTEQUAL);
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
}
|
|
if (Changed & FSS_STENCFAIL_MASK)
|
|
{
|
|
int nCurOp = (st & FSS_STENCFAIL_MASK);
|
|
switch(nCurOp >> FSS_STENCFAIL_SHIFT)
|
|
{
|
|
case FSS_STENCOP_KEEP:
|
|
dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
|
|
break;
|
|
case FSS_STENCOP_REPLACE:
|
|
dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
|
|
break;
|
|
case FSS_STENCOP_INCR:
|
|
dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_INCRSAT);
|
|
break;
|
|
case FSS_STENCOP_DECR:
|
|
dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_DECRSAT);
|
|
break;
|
|
case FSS_STENCOP_INCR_WRAP:
|
|
dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_INCR);
|
|
break;
|
|
case FSS_STENCOP_DECR_WRAP:
|
|
dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_DECR);
|
|
break;
|
|
case FSS_STENCOP_ZERO:
|
|
dv->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_ZERO);
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
}
|
|
if (Changed & FSS_STENCZFAIL_MASK)
|
|
{
|
|
int nCurOp = (st & FSS_STENCZFAIL_MASK);
|
|
switch(nCurOp >> FSS_STENCZFAIL_SHIFT)
|
|
{
|
|
case FSS_STENCOP_KEEP:
|
|
dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);
|
|
break;
|
|
case FSS_STENCOP_REPLACE:
|
|
dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE);
|
|
break;
|
|
case FSS_STENCOP_INCR:
|
|
dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INCRSAT);
|
|
break;
|
|
case FSS_STENCOP_DECR:
|
|
dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_DECRSAT);
|
|
break;
|
|
case FSS_STENCOP_INCR_WRAP:
|
|
dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR);
|
|
break;
|
|
case FSS_STENCOP_DECR_WRAP:
|
|
dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_DECR);
|
|
break;
|
|
case FSS_STENCOP_ZERO:
|
|
dv->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_ZERO);
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
}
|
|
if (Changed & FSS_STENCPASS_MASK)
|
|
{
|
|
int nCurOp = (st & FSS_STENCPASS_MASK);
|
|
switch(nCurOp >> FSS_STENCPASS_SHIFT)
|
|
{
|
|
case FSS_STENCOP_KEEP:
|
|
dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
|
|
break;
|
|
case FSS_STENCOP_REPLACE:
|
|
dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
|
|
break;
|
|
case FSS_STENCOP_INCR:
|
|
dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCRSAT);
|
|
break;
|
|
case FSS_STENCOP_DECR:
|
|
dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_DECRSAT);
|
|
break;
|
|
case FSS_STENCOP_INCR_WRAP:
|
|
dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INCR);
|
|
break;
|
|
case FSS_STENCOP_DECR_WRAP:
|
|
dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_DECR);
|
|
break;
|
|
case FSS_STENCOP_ZERO:
|
|
dv->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_ZERO);
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
if (Changed & (FSS_STENCFUNC_MASK << FSS_CCW_SHIFT))
|
|
{
|
|
int nCurFunc = (st & (FSS_STENCFUNC_MASK << FSS_CCW_SHIFT));
|
|
switch(nCurFunc >> FSS_CCW_SHIFT)
|
|
{
|
|
case FSS_STENCFUNC_ALWAYS:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_ALWAYS);
|
|
break;
|
|
case FSS_STENCFUNC_NEVER:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_NEVER);
|
|
break;
|
|
case FSS_STENCFUNC_LESS:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_LESS);
|
|
break;
|
|
case FSS_STENCFUNC_LEQUAL:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_LESSEQUAL);
|
|
break;
|
|
case FSS_STENCFUNC_GREATER:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_GREATER);
|
|
break;
|
|
case FSS_STENCFUNC_GEQUAL:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_GREATEREQUAL);
|
|
break;
|
|
case FSS_STENCFUNC_EQUAL:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_EQUAL);
|
|
break;
|
|
case FSS_STENCFUNC_NOTEQUAL:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_NOTEQUAL);
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
}
|
|
if (Changed & (FSS_STENCFAIL_MASK << FSS_CCW_SHIFT))
|
|
{
|
|
int nCurOp = (st & (FSS_STENCFAIL_MASK << FSS_CCW_SHIFT));
|
|
switch(nCurOp >> (FSS_STENCFAIL_SHIFT+FSS_CCW_SHIFT))
|
|
{
|
|
case FSS_STENCOP_KEEP:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_KEEP);
|
|
break;
|
|
case FSS_STENCOP_REPLACE:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_REPLACE);
|
|
break;
|
|
case FSS_STENCOP_INCR:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_INCRSAT);
|
|
break;
|
|
case FSS_STENCOP_DECR:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_DECRSAT);
|
|
break;
|
|
case FSS_STENCOP_INCR_WRAP:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_INCR);
|
|
break;
|
|
case FSS_STENCOP_DECR_WRAP:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_DECR);
|
|
break;
|
|
case FSS_STENCOP_ZERO:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_ZERO);
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
}
|
|
if (Changed & (FSS_STENCZFAIL_MASK << FSS_CCW_SHIFT))
|
|
{
|
|
int nCurOp = (st & (FSS_STENCZFAIL_MASK << FSS_CCW_SHIFT));
|
|
switch(nCurOp >> (FSS_STENCZFAIL_SHIFT+FSS_CCW_SHIFT))
|
|
{
|
|
case FSS_STENCOP_KEEP:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_KEEP);
|
|
break;
|
|
case FSS_STENCOP_REPLACE:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_REPLACE);
|
|
break;
|
|
case FSS_STENCOP_INCR:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_INCRSAT);
|
|
break;
|
|
case FSS_STENCOP_DECR:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_DECRSAT);
|
|
break;
|
|
case FSS_STENCOP_INCR_WRAP:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_INCR);
|
|
break;
|
|
case FSS_STENCOP_DECR_WRAP:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_DECR);
|
|
break;
|
|
case FSS_STENCOP_ZERO:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_ZERO);
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
}
|
|
if (Changed & (FSS_STENCPASS_MASK << FSS_CCW_SHIFT))
|
|
{
|
|
int nCurOp = (st & (FSS_STENCPASS_MASK << FSS_CCW_SHIFT));
|
|
switch(nCurOp >> (FSS_STENCPASS_SHIFT+FSS_CCW_SHIFT))
|
|
{
|
|
case FSS_STENCOP_KEEP:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_KEEP);
|
|
break;
|
|
case FSS_STENCOP_REPLACE:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_REPLACE);
|
|
break;
|
|
case FSS_STENCOP_INCR:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_INCRSAT);
|
|
break;
|
|
case FSS_STENCOP_DECR:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_DECRSAT);
|
|
break;
|
|
case FSS_STENCOP_INCR_WRAP:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_INCR);
|
|
break;
|
|
case FSS_STENCOP_DECR_WRAP:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_DECR);
|
|
break;
|
|
case FSS_STENCOP_ZERO:
|
|
dv->SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_ZERO);
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
m_CurStencilState = st;
|
|
}
|
|
|
|
// Set current render states
|
|
void CRenderer::EF_SetState(int st)
|
|
{
|
|
int Changed;
|
|
int src, dst;
|
|
|
|
if (m_RP.m_Flags & RBF_SHOWLINES)
|
|
st |= GS_NODEPTHTEST;
|
|
|
|
if (st & (GS_DEPTHWRITE | GS_DEPTHFUNC_EQUAL))
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHABLEND))
|
|
m_RP.m_FlagsPerFlush |= RBSI_WASDEPTHWRITE;
|
|
}
|
|
if (st & GS_DEPTHWRITE)
|
|
{
|
|
if (m_RP.m_LastVP && m_RP.m_pRE)
|
|
m_RP.m_pRE->m_LastVP = m_RP.m_LastVP;
|
|
}
|
|
|
|
Changed = st ^ m_CurState;
|
|
if (!Changed)
|
|
return;
|
|
|
|
//PROFILE_FRAME(State_RStates);
|
|
|
|
LPDIRECT3DDEVICE9 dv = gcpRendD3D->mfGetD3DDevice();
|
|
m_RP.m_PS.m_NumStateChanges++;
|
|
|
|
if (Changed & (GS_DEPTHFUNC_EQUAL | GS_DEPTHFUNC_GREAT))
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_DEPTHFUNC))
|
|
{
|
|
if (st & (GS_DEPTHFUNC_EQUAL|GS_DEPTHFUNC_GREAT))
|
|
{
|
|
if (st & GS_DEPTHFUNC_EQUAL)
|
|
dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL);
|
|
else
|
|
dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATER);
|
|
}
|
|
else
|
|
dv->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
|
|
}
|
|
else
|
|
{
|
|
st &= ~(GS_DEPTHFUNC_EQUAL|GS_DEPTHFUNC_GREAT);
|
|
st |= (m_CurState & (GS_DEPTHFUNC_EQUAL|GS_DEPTHFUNC_GREAT));
|
|
}
|
|
}
|
|
if (Changed & GS_POLYLINE)
|
|
{
|
|
if (m_polygon_mode == R_SOLID_MODE)
|
|
{
|
|
if (st & GS_POLYLINE)
|
|
dv->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
|
|
else
|
|
dv->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
|
|
}
|
|
}
|
|
|
|
if (Changed & (GS_NOCOLMASK|GS_COLMASKONLYALPHA|GS_COLMASKONLYRGB))
|
|
{
|
|
if (st & (GS_NOCOLMASK|GS_COLMASKONLYALPHA|GS_COLMASKONLYRGB))
|
|
{
|
|
if (st & GS_NOCOLMASK)
|
|
dv->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
|
|
else
|
|
if (st & GS_COLMASKONLYALPHA)
|
|
dv->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA);
|
|
else
|
|
if (st & GS_COLMASKONLYRGB)
|
|
dv->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_BLUE);
|
|
}
|
|
else
|
|
dv->SetRenderState(D3DRS_COLORWRITEENABLE, 0xf);
|
|
}
|
|
|
|
if (Changed & GS_BLEND_MASK)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHABLEND))
|
|
{
|
|
if ((st & GS_BLEND_MASK) == GS_BLEND_MASK)
|
|
{
|
|
st &= ~GS_BLEND_MASK;
|
|
st |= (m_CurState & GS_BLEND_MASK);
|
|
goto skip;
|
|
}
|
|
|
|
if (st & GS_BLEND_MASK)
|
|
{
|
|
// Source factor
|
|
switch (st & GS_BLSRC_MASK)
|
|
{
|
|
case GS_BLSRC_ZERO:
|
|
src = D3DBLEND_ZERO;
|
|
break;
|
|
|
|
case GS_BLSRC_ONE:
|
|
src = D3DBLEND_ONE;
|
|
break;
|
|
|
|
case GS_BLSRC_DSTCOL:
|
|
src = D3DBLEND_DESTCOLOR;
|
|
break;
|
|
|
|
case GS_BLSRC_ONEMINUSDSTCOL:
|
|
src = D3DBLEND_INVDESTCOLOR;
|
|
break;
|
|
|
|
case GS_BLSRC_SRCALPHA:
|
|
src = D3DBLEND_SRCALPHA;
|
|
break;
|
|
|
|
case GS_BLSRC_ONEMINUSSRCALPHA:
|
|
src = D3DBLEND_INVSRCALPHA;
|
|
break;
|
|
|
|
case GS_BLSRC_DSTALPHA:
|
|
src = D3DBLEND_DESTALPHA;
|
|
break;
|
|
|
|
case GS_BLSRC_ONEMINUSDSTALPHA:
|
|
src = D3DBLEND_INVDESTALPHA;
|
|
break;
|
|
|
|
case GS_BLSRC_ALPHASATURATE:
|
|
src = D3DBLEND_SRCALPHASAT;
|
|
break;
|
|
|
|
default:
|
|
iLog->Log("CD3D9Renderer::SetState: invalid src blend state bits '%d'", st & GS_BLSRC_MASK);
|
|
break;
|
|
}
|
|
|
|
//Destination factor
|
|
switch (st & GS_BLDST_MASK)
|
|
{
|
|
case GS_BLDST_ZERO:
|
|
dst = D3DBLEND_ZERO;
|
|
break;
|
|
|
|
case GS_BLDST_ONE:
|
|
dst = D3DBLEND_ONE;
|
|
break;
|
|
|
|
case GS_BLDST_SRCCOL:
|
|
dst = D3DBLEND_SRCCOLOR;
|
|
break;
|
|
|
|
case GS_BLDST_ONEMINUSSRCCOL:
|
|
dst = D3DBLEND_INVSRCCOLOR;
|
|
if (m_nHDRType == 1 && (m_RP.m_PersFlags & RBPF_HDR))
|
|
dst = D3DBLEND_ONE;
|
|
break;
|
|
|
|
case GS_BLDST_SRCALPHA:
|
|
dst = D3DBLEND_SRCALPHA;
|
|
break;
|
|
|
|
case GS_BLDST_ONEMINUSSRCALPHA:
|
|
dst = D3DBLEND_INVSRCALPHA;
|
|
break;
|
|
|
|
case GS_BLDST_DSTALPHA:
|
|
dst = D3DBLEND_DESTALPHA;
|
|
break;
|
|
|
|
case GS_BLDST_ONEMINUSDSTALPHA:
|
|
dst = D3DBLEND_INVDESTALPHA;
|
|
break;
|
|
|
|
default:
|
|
iLog->Log("CD3D9Renderer::SetState: invalid dst blend state bits '%d'", st & GS_BLDST_MASK);
|
|
break;
|
|
}
|
|
if (!(m_CurState & GS_BLEND_MASK))
|
|
dv->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
|
dv->SetRenderState(D3DRS_SRCBLEND, src);
|
|
dv->SetRenderState(D3DRS_DESTBLEND, dst);
|
|
}
|
|
else
|
|
dv->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
|
|
}
|
|
else
|
|
{
|
|
st &= ~GS_BLEND_MASK;
|
|
st |= (m_CurState & GS_BLEND_MASK);
|
|
}
|
|
}
|
|
|
|
skip:
|
|
if (Changed & GS_DEPTHWRITE)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_DEPTHWRITE))
|
|
{
|
|
if (st & GS_DEPTHWRITE)
|
|
dv->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
|
|
else
|
|
dv->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
|
|
}
|
|
else
|
|
{
|
|
st &= ~GS_DEPTHWRITE;
|
|
st |= (m_CurState & GS_DEPTHWRITE);
|
|
}
|
|
}
|
|
|
|
if (Changed & GS_NODEPTHTEST)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_DEPTHTEST))
|
|
{
|
|
if (st & GS_NODEPTHTEST)
|
|
dv->SetRenderState(D3DRS_ZENABLE, FALSE);
|
|
else
|
|
dv->SetRenderState(D3DRS_ZENABLE, TRUE);
|
|
}
|
|
else
|
|
{
|
|
st &= ~GS_NODEPTHTEST;
|
|
st |= (m_CurState & GS_NODEPTHTEST);
|
|
}
|
|
}
|
|
|
|
if (Changed & GS_STENCIL)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_STENCIL) && !(m_RP.m_PersFlags & RBPF_MEASUREOVERDRAW))
|
|
{
|
|
if (st & GS_STENCIL)
|
|
dv->SetRenderState(D3DRS_STENCILENABLE, TRUE);
|
|
else
|
|
dv->SetRenderState(D3DRS_STENCILENABLE, FALSE);
|
|
}
|
|
else
|
|
{
|
|
st &= ~GS_STENCIL;
|
|
st |= (m_CurState & GS_STENCIL);
|
|
}
|
|
}
|
|
|
|
if (Changed & GS_ALPHATEST_MASK)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_ALPHATEST))
|
|
{
|
|
if (st & GS_ALPHATEST_MASK)
|
|
{
|
|
if (!(m_CurState & GS_ALPHATEST_MASK))
|
|
dv->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
|
|
switch (st & GS_ALPHATEST_MASK)
|
|
{
|
|
case GS_ALPHATEST_GREATER0:
|
|
dv->SetRenderState(D3DRS_ALPHAREF, 0);
|
|
dv->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
|
|
break;
|
|
|
|
case GS_ALPHATEST_LESS128:
|
|
dv->SetRenderState(D3DRS_ALPHAREF, 0x80);
|
|
dv->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESS);
|
|
break;
|
|
|
|
case GS_ALPHATEST_GEQUAL128:
|
|
dv->SetRenderState(D3DRS_ALPHAREF, 0x80);
|
|
dv->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
|
|
break;
|
|
|
|
case GS_ALPHATEST_GEQUAL64:
|
|
dv->SetRenderState(D3DRS_ALPHAREF, 0x40);
|
|
dv->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
dv->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
|
}
|
|
else
|
|
{
|
|
st &= ~GS_ALPHATEST_MASK;
|
|
st |= m_CurState & GS_ALPHATEST_MASK;
|
|
}
|
|
}
|
|
m_CurState = st;
|
|
}
|
|
|
|
// Set current texture color op modes (used in fixed pipeline shaders)
|
|
void CD3D9Renderer::SetColorOp(byte eCo, byte eAo, byte eCa, byte eAa)
|
|
{
|
|
EF_SetColorOp(eCo, eAo, eCa, eAa);
|
|
}
|
|
|
|
void CD3D9Renderer::EF_SetColorOp(byte eCo, byte eAo, byte eCa, byte eAa)
|
|
{
|
|
int stage = m_TexMan->m_CurStage;
|
|
|
|
if (eCo != 255 && eCo != m_eCurColorOp[stage])
|
|
{
|
|
switch (eCo)
|
|
{
|
|
case eCO_MODULATE:
|
|
default:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
|
break;
|
|
|
|
case eCO_BLENDDIFFUSEALPHA:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_BLENDDIFFUSEALPHA);
|
|
break;
|
|
|
|
case eCO_BLENDTEXTUREALPHA:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA);
|
|
break;
|
|
|
|
case eCO_MODULATE4X:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATE4X);
|
|
break;
|
|
|
|
case eCO_MODULATE2X:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATE2X);
|
|
break;
|
|
|
|
case eCO_ADD:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_ADD);
|
|
break;
|
|
|
|
case eCO_ADDSIGNED:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_ADDSIGNED);
|
|
break;
|
|
|
|
case eCO_MULTIPLYADD:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MULTIPLYADD);
|
|
break;
|
|
|
|
case eCO_REPLACE:
|
|
case eCO_DECAL:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
|
|
break;
|
|
|
|
case eCO_ARG2:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
|
|
break;
|
|
|
|
case eCO_BUMPENVMAP:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_BUMPENVMAP);
|
|
break;
|
|
|
|
case eCO_MODULATEALPHA_ADDCOLOR:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATEALPHA_ADDCOLOR);
|
|
break;
|
|
|
|
case eCO_MODULATECOLOR_ADDALPHA:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATECOLOR_ADDALPHA);
|
|
break;
|
|
|
|
case eCO_MODULATEINVALPHA_ADDCOLOR:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATEINVALPHA_ADDCOLOR);
|
|
break;
|
|
|
|
case eCO_MODULATEINVCOLOR_ADDALPHA:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_MODULATEINVCOLOR_ADDALPHA);
|
|
break;
|
|
|
|
case eCO_DOTPRODUCT3:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3);
|
|
break;
|
|
|
|
case eCO_LERP:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_LERP);
|
|
break;
|
|
|
|
case eCO_SUBTRACT:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_SUBTRACT);
|
|
break;
|
|
|
|
case eCO_DISABLE:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
|
break;
|
|
}
|
|
m_eCurColorOp[stage] = eCo;
|
|
}
|
|
|
|
if (eAo != 255 && eAo != m_eCurAlphaOp[stage])
|
|
{
|
|
switch (eAo)
|
|
{
|
|
case eCO_MODULATE:
|
|
default:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
|
break;
|
|
|
|
case eCO_BLENDDIFFUSEALPHA:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_BLENDDIFFUSEALPHA);
|
|
break;
|
|
|
|
case eCO_BLENDTEXTUREALPHA:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_BLENDTEXTUREALPHA);
|
|
break;
|
|
|
|
case eCO_MODULATE4X:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_MODULATE4X);
|
|
break;
|
|
|
|
case eCO_MODULATE2X:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_MODULATE2X);
|
|
break;
|
|
|
|
case eCO_ADD:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_ADD);
|
|
break;
|
|
|
|
case eCO_ADDSIGNED:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_ADDSIGNED);
|
|
break;
|
|
|
|
case eCO_MULTIPLYADD:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_MULTIPLYADD);
|
|
break;
|
|
|
|
case eCO_REPLACE:
|
|
case eCO_DECAL:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
|
break;
|
|
|
|
case eCO_ARG2:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
|
|
break;
|
|
|
|
case eCO_BUMPENVMAP:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_BUMPENVMAP);
|
|
break;
|
|
|
|
case eCO_SUBTRACT:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_SUBTRACT);
|
|
break;
|
|
|
|
case eCO_LERP:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_LERP);
|
|
break;
|
|
|
|
case eCO_DISABLE:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
|
break;
|
|
}
|
|
m_eCurAlphaOp[stage] = eAo;
|
|
}
|
|
|
|
if (eCa != 255 && eCa != m_eCurColorArg[stage])
|
|
{
|
|
if ((eCa & 7) != (m_eCurColorArg[stage] & 7))
|
|
{
|
|
switch (eCa & 7)
|
|
{
|
|
case eCA_Texture:
|
|
default:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
|
break;
|
|
case eCA_Diffuse:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
|
|
break;
|
|
case eCA_Specular:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_SPECULAR);
|
|
break;
|
|
case eCA_Previous:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_CURRENT);
|
|
break;
|
|
case eCA_Constant:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG1, D3DTA_TFACTOR);
|
|
break;
|
|
}
|
|
}
|
|
if (((eCa>>3) & 7) != ((m_eCurColorArg[stage]>>3) & 7))
|
|
{
|
|
switch ((eCa >> 3) & 7)
|
|
{
|
|
case eCA_Texture:
|
|
default:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_TEXTURE);
|
|
break;
|
|
case eCA_Diffuse:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
|
break;
|
|
case eCA_Specular:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_SPECULAR);
|
|
break;
|
|
case eCA_Previous:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_CURRENT);
|
|
break;
|
|
case eCA_Constant:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG2, D3DTA_TFACTOR);
|
|
break;
|
|
}
|
|
}
|
|
if ((eCa >> 6) != (m_eCurColorArg[stage] >> 6))
|
|
{
|
|
switch (eCa >> 6)
|
|
{
|
|
case eCA_Texture:
|
|
default:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG0, D3DTA_TEXTURE);
|
|
break;
|
|
case eCA_Diffuse:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG0, D3DTA_DIFFUSE);
|
|
break;
|
|
case eCA_Specular:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG0, D3DTA_SPECULAR);
|
|
break;
|
|
case eCA_Previous:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG0, D3DTA_CURRENT);
|
|
break;
|
|
case eCA_Constant:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_COLORARG0, D3DTA_TFACTOR);
|
|
break;
|
|
}
|
|
}
|
|
m_eCurColorArg[stage] = eCa;
|
|
}
|
|
|
|
if (eAa != 255 && eAa != m_eCurAlphaArg[stage])
|
|
{
|
|
if ((eAa & 7) != (m_eCurAlphaArg[stage] & 7))
|
|
{
|
|
switch (eAa & 7)
|
|
{
|
|
case eCA_Texture:
|
|
default:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
|
break;
|
|
case eCA_Diffuse:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
|
|
break;
|
|
case eCA_Specular:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_SPECULAR);
|
|
break;
|
|
case eCA_Previous:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
|
|
break;
|
|
case eCA_Constant:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
|
|
break;
|
|
}
|
|
}
|
|
if (((eAa>>3) & 7) != ((m_eCurAlphaArg[stage]>>3) & 7))
|
|
{
|
|
switch ((eAa >> 3) & 7)
|
|
{
|
|
case eCA_Texture:
|
|
default:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);
|
|
break;
|
|
case eCA_Diffuse:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
|
break;
|
|
case eCA_Specular:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_SPECULAR);
|
|
break;
|
|
case eCA_Previous:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
|
|
break;
|
|
case eCA_Constant:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG2, D3DTA_TFACTOR);
|
|
break;
|
|
}
|
|
}
|
|
if ((eAa >> 6) != (m_eCurAlphaArg[stage] >> 6))
|
|
{
|
|
switch (eAa >> 6)
|
|
{
|
|
case eCA_Texture:
|
|
default:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG0, D3DTA_TEXTURE);
|
|
break;
|
|
case eCA_Diffuse:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG0, D3DTA_DIFFUSE);
|
|
break;
|
|
case eCA_Specular:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG0, D3DTA_SPECULAR);
|
|
break;
|
|
case eCA_Previous:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG0, D3DTA_CURRENT);
|
|
break;
|
|
case eCA_Constant:
|
|
m_pd3dDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG0, D3DTA_TFACTOR);
|
|
break;
|
|
}
|
|
}
|
|
m_eCurAlphaArg[stage] = eAa;
|
|
}
|
|
}
|
|
|
|
// Set current geometry culling modes
|
|
void CD3D9Renderer::D3DSetCull(ECull eCull)
|
|
{
|
|
if (eCull == m_eCull)
|
|
return;
|
|
|
|
if (eCull == eCULL_None)
|
|
m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
|
else
|
|
{
|
|
if ((eCull == eCULL_Back && !(m_RP.m_PersFlags & RBPF_DRAWMIRROR)) || (eCull != eCULL_Back && (m_RP.m_PersFlags & RBPF_DRAWMIRROR)))
|
|
m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
|
|
else
|
|
m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
|
|
}
|
|
m_eCull = eCull;
|
|
}
|
|
|
|
// Init states before rendering of the scene
|
|
void CD3D9Renderer::EF_PreRender(int Stage)
|
|
{
|
|
int i;
|
|
if (m_bDeviceLost)
|
|
return;
|
|
|
|
if (Stage & 1)
|
|
{ // Before preprocess
|
|
m_RP.m_RealTime = iTimer->GetCurrTime();
|
|
|
|
m_RP.m_Flags = 0;
|
|
m_RP.m_pPrevObject = NULL;
|
|
m_RP.m_FrameObject++;
|
|
|
|
EF_SetCameraInfo();
|
|
if (Stage == 1)
|
|
CCGVProgram_D3D::mfSetGlobalParams();
|
|
|
|
for (i=0; i<m_RP.m_DLights[SRendItem::m_RecurseLevel].Num(); i++)
|
|
{
|
|
CDLight *dl = m_RP.m_DLights[SRendItem::m_RecurseLevel][i];
|
|
if (dl->m_Flags & DLF_FAKE)
|
|
continue;
|
|
|
|
if (dl->m_Flags & DLF_SUN)
|
|
{
|
|
Vec3d pos = GetCamera().GetPos();
|
|
Vec3d delta = dl->m_Origin - pos;
|
|
delta.Normalize();
|
|
m_RP.m_SunDir = delta;
|
|
m_RP.m_SunColor = dl->m_Color;
|
|
}
|
|
}
|
|
// if (i == m_RP.m_DLights.Num() && m_RP.m_SunDir == Vec3d(0,0,0))
|
|
if (i == m_RP.m_DLights[SRendItem::m_RecurseLevel].Num() && IsEquivalent(m_RP.m_SunDir,Vec3d(0,0,0)))
|
|
m_RP.m_SunDir = Vec3d(0,0,1);
|
|
}
|
|
|
|
if (Stage & 2)
|
|
{ // After preprocess
|
|
if (!m_RP.m_bStartPipeline && !m_bWasCleared && !(m_RP.m_PersFlags & RBPF_NOCLEARBUF))
|
|
{
|
|
m_RP.m_bStartPipeline = true;
|
|
EF_ClearBuffers(false, false, NULL);
|
|
}
|
|
}
|
|
m_RP.m_pCurLight = NULL;
|
|
}
|
|
|
|
// Restore states after rendering of the scene
|
|
void CD3D9Renderer::EF_PostRender()
|
|
{
|
|
//FrameProfiler f("CD3D9Renderer:EF_PostRender", iSystem );
|
|
|
|
EF_ObjectChange(NULL, NULL, 0, NULL);
|
|
m_RP.m_pRE = NULL;
|
|
|
|
HRESULT h;
|
|
if (m_RP.m_PersFlags & RBPF_USESTREAM1)
|
|
{
|
|
m_RP.m_PersFlags &= ~RBPF_USESTREAM1;
|
|
h = m_pd3dDevice->SetStreamSource( 1, NULL, 0, 0);
|
|
}
|
|
if (m_RP.m_PersFlags & RBPF_USESTREAM2)
|
|
{
|
|
m_RP.m_PersFlags &= ~RBPF_USESTREAM2;
|
|
h = m_pd3dDevice->SetStreamSource( 2, NULL, 0, 0);
|
|
}
|
|
if (m_RP.m_PersFlags & RBPF_SETCLIPPLANE)
|
|
{
|
|
EF_SetClipPlane(false, NULL, false);
|
|
m_RP.m_PersFlags &= ~RBPF_SETCLIPPLANE;
|
|
}
|
|
m_Viewport.MaxZ = 1.0f;
|
|
m_pd3dDevice->SetViewport(&m_Viewport);
|
|
CD3D9TexMan::BindNULL(1);
|
|
EF_SelectTMU(0);
|
|
m_RP.m_PersFlags &= ~(RBPF_VSNEEDSET | RBPF_PS1NEEDSET);
|
|
m_RP.m_FlagsModificators = 0;
|
|
m_RP.m_CurrentVLights = 0;
|
|
m_RP.m_FlagsPerFlush = 0;
|
|
EF_CommitShadersState();
|
|
EF_CommitVLightsState();
|
|
m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
|
|
if (m_RP.m_TexStages[0].TCIndex != 0)
|
|
{
|
|
m_RP.m_TexStages[0].TCIndex = 0;
|
|
m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU | 0);
|
|
}
|
|
EF_Scissor(false, 0, 0, 0, 0);
|
|
m_RP.m_pShader = NULL;
|
|
m_RP.m_pCurObject = m_RP.m_VisObjects[0];
|
|
|
|
//ResetToDefault();
|
|
}
|
|
|
|
//=================================================================================
|
|
// Check buffer overflow during geometry batching
|
|
void CD3D9Renderer::EF_CheckOverflow(int nVerts, int nInds, CRendElement *re)
|
|
{
|
|
if (m_RP.m_pRE || (m_RP.m_RendNumVerts+nVerts >= m_RP.m_MaxVerts || m_RP.m_RendNumIndices+nInds >= m_RP.m_MaxTris*3))
|
|
{
|
|
m_RP.m_pRenderFunc();
|
|
if (nVerts >= m_RP.m_MaxVerts)
|
|
{
|
|
iLog->Log("CD3D9Renderer::EF_CheckOverflow: numVerts > MAX (%d > %d)\n", nVerts, m_RP.m_MaxVerts);
|
|
nVerts = m_RP.m_MaxVerts;
|
|
}
|
|
if (nInds >= m_RP.m_MaxTris*3)
|
|
{
|
|
iLog->Log("CD3D9Renderer::EF_CheckOverflow: numIndices > MAX (%d > %d)\n", nInds, m_RP.m_MaxTris*3);
|
|
nInds = m_RP.m_MaxTris*3;
|
|
}
|
|
EF_Start(m_RP.m_pShader, m_RP.m_pStateShader, m_RP.m_pShaderResources, m_RP.m_pFogVolume ? (m_RP.m_pFogVolume-&m_RP.m_FogVolumes[0]) : 0, re);
|
|
}
|
|
}
|
|
|
|
|
|
// Initialize of the new shader pipeline (only 2d)
|
|
void CD3D9Renderer::EF_Start(SShader *ef, SShader *efState, SRenderShaderResources *Res, CRendElement *re)
|
|
{
|
|
//FrameProfiler f("CD3D9Renderer:EF_Start", iSystem );
|
|
|
|
m_RP.m_RendPass = 0;
|
|
m_RP.m_RendNumIndices = 0;
|
|
m_RP.m_RendNumVerts = 0;
|
|
m_RP.m_FirstIndex = 0;
|
|
m_RP.m_FirstVertex = 0;
|
|
m_RP.m_BaseVertex = 0;
|
|
m_RP.m_pShader = ef;
|
|
#ifdef PIPE_USE_INSTANCING
|
|
m_RP.m_MergedObjects.SetUse(0);
|
|
#endif
|
|
m_RP.m_pCurLightMaterial = NULL;
|
|
m_RP.m_pStateShader = efState;
|
|
m_RP.m_pShaderResources = Res;
|
|
m_RP.m_FlagsPerFlush = 0;
|
|
m_RP.m_FlagsModificators = 0;
|
|
m_RP.m_pFogVolume = NULL;
|
|
m_RP.m_pRE = NULL;
|
|
m_RP.m_fCurOpacity = 1.0f;
|
|
|
|
// Choose appropriate shader technique depend on some input parameters
|
|
if (ef->m_HWTechniques.Num())
|
|
{
|
|
int nHW = EF_SelectHWTechnique(ef);
|
|
if (nHW >= 0)
|
|
m_RP.m_pCurTechnique = ef->m_HWTechniques[nHW];
|
|
else
|
|
m_RP.m_pCurTechnique = NULL;
|
|
}
|
|
else
|
|
m_RP.m_pCurTechnique = NULL;
|
|
|
|
m_RP.m_Frame++;
|
|
}
|
|
|
|
// Start of the new shader pipeline (3D pipeline version)
|
|
void CD3D9Renderer::EF_Start(SShader *ef, SShader *efState, SRenderShaderResources *Res, int numFog, CRendElement *re)
|
|
{
|
|
m_RP.m_RendPass = 0;
|
|
m_RP.m_FirstIndex = 0;
|
|
m_RP.m_FirstVertex = 0;
|
|
m_RP.m_BaseVertex = 0;
|
|
m_RP.m_RendNumIndices = 0;
|
|
m_RP.m_RendNumVerts = 0;
|
|
m_RP.m_pShader = ef;
|
|
m_RP.m_pStateShader = efState;
|
|
m_RP.m_pShaderResources = Res;
|
|
m_RP.m_pCurEnvTexture = NULL;
|
|
#ifdef PIPE_USE_INSTANCING
|
|
m_RP.m_MergedObjects.SetUse(0);
|
|
#endif
|
|
m_RP.m_pCurLightMaterial = NULL;
|
|
m_RP.m_FlagsPerFlush = 0;
|
|
m_RP.m_FlagsModificators = 0;
|
|
m_RP.m_fCurOpacity = 1.0f;
|
|
if (numFog && CV_r_VolumetricFog)
|
|
m_RP.m_pFogVolume = &m_RP.m_FogVolumes[numFog];
|
|
else
|
|
m_RP.m_pFogVolume = NULL;
|
|
m_RP.m_ObjFlags = m_RP.m_pCurObject->m_ObjFlags;
|
|
|
|
m_RP.m_CurVFormat = ef->m_VertexFormatId;
|
|
|
|
SBufInfoTable *pOffs = &gBufInfoTable[m_RP.m_CurVFormat];
|
|
int Size = m_VertexSize[m_RP.m_CurVFormat];
|
|
m_RP.m_Stride = Size;
|
|
m_RP.m_OffsD = pOffs->OffsColor;
|
|
m_RP.m_OffsT = pOffs->OffsTC;
|
|
m_RP.m_OffsN = pOffs->OffsNormal;
|
|
m_RP.m_NextPtr = m_RP.m_Ptr;
|
|
m_RP.m_DynLMask = m_RP.m_pCurObject->m_DynLMMask;
|
|
m_RP.m_MergedREs.SetUse(0);
|
|
m_RP.m_MergedObjs.SetUse(0);
|
|
|
|
if (!EF_BuildLightsList())
|
|
iLog->Log("WARNING: CD3D9Renderer::EF_BuildLightsList: Too many light sources per render item (> 16). Shader: '%s'\n", ef->m_Name.c_str());
|
|
|
|
// Choose appropriate shader technique depend on some input parameters
|
|
if (ef->m_HWTechniques.Num())
|
|
{
|
|
m_RP.m_pRE = re;
|
|
int nHW = EF_SelectHWTechnique(ef);
|
|
if (nHW >= 0)
|
|
m_RP.m_pCurTechnique = ef->m_HWTechniques[nHW];
|
|
else
|
|
m_RP.m_pCurTechnique = NULL;
|
|
}
|
|
else
|
|
m_RP.m_pCurTechnique = NULL;
|
|
|
|
m_RP.m_pRE = NULL;
|
|
|
|
m_RP.m_Frame++;
|
|
}
|
|
|
|
//========================================================================================
|
|
// Set current HW light states (used in fixed pipeline shaders)
|
|
void CD3D9Renderer::EF_SetHWLight(int Num, vec4_t Pos, CFColor& Diffuse, CFColor& Specular, float ca, float la, float qa, float fRange)
|
|
{
|
|
m_Lights[Num].Position.x = Pos[0];
|
|
m_Lights[Num].Position.y = Pos[1];
|
|
m_Lights[Num].Position.z = Pos[2];
|
|
m_Lights[Num].Range = fRange;
|
|
if (!Pos[3])
|
|
{
|
|
Vec3d v = Vec3d(Pos[0], Pos[1], Pos[2]);
|
|
v.Normalize();
|
|
m_Lights[Num].Direction.x = -v[0];
|
|
m_Lights[Num].Direction.y = -v[1];
|
|
m_Lights[Num].Direction.z = -v[2];
|
|
m_Lights[Num].Type = D3DLIGHT_DIRECTIONAL;
|
|
}
|
|
else
|
|
m_Lights[Num].Type = D3DLIGHT_POINT;
|
|
|
|
m_Lights[Num].Diffuse.r = Diffuse.r;
|
|
m_Lights[Num].Diffuse.g = Diffuse.g;
|
|
m_Lights[Num].Diffuse.b = Diffuse.b;
|
|
m_Lights[Num].Diffuse.a = Diffuse.a;
|
|
|
|
m_Lights[Num].Specular.r = Specular.r;
|
|
m_Lights[Num].Specular.g = Specular.g;
|
|
m_Lights[Num].Specular.b = Specular.b;
|
|
m_Lights[Num].Specular.a = Specular.a;
|
|
|
|
m_Lights[Num].Attenuation0 = ca;
|
|
m_Lights[Num].Attenuation1 = la;
|
|
m_Lights[Num].Attenuation2 = qa;
|
|
|
|
m_pd3dDevice->SetLight(Num, &m_Lights[Num]);
|
|
|
|
m_RP.m_CurrentVLights |= 1<<Num;
|
|
}
|
|
|
|
static float sAttenuation(float Distance, float Radius)
|
|
{
|
|
if(Distance <= Radius)
|
|
{
|
|
float A = Distance / Radius;
|
|
float B = (2 * A * A * A - 3 * A * A + 1);
|
|
|
|
return B / A * A * 2.0f;
|
|
}
|
|
else
|
|
return 0.1f;
|
|
}
|
|
|
|
inline void TransformPosition33(Vec3& out, Vec3& in, Matrix33& m)
|
|
{
|
|
out.x = in.x * m(0,0) + in.y * m(1,0) + in.z * m(2,0);
|
|
out.y = in.x * m(0,1) + in.y * m(1,1) + in.z * m(2,1);
|
|
out.z = in.x * m(0,2) + in.y * m(1,2) + in.z * m(2,2);
|
|
}
|
|
|
|
// Calculate light parameters used for HW vertex lighting (used in fixed pipeline shaders)
|
|
bool CD3D9Renderer::EF_SetLights(int Flags)
|
|
{
|
|
//float MaxD3DRange = cry_sqrtf(FLT_MAX); // xbox libs freak out about illegal light ranges
|
|
|
|
vec4_t Pos;
|
|
Vec3d lpos;
|
|
int n = 0;
|
|
float fCA, fLA, fQA;
|
|
Vec3d vCenterRE;
|
|
float fRadRE;
|
|
bool bCalcDist = false;
|
|
CFColor cDiffuse, cSpecular;
|
|
cSpecular = CFColor(0.0f);
|
|
|
|
for (int i=0; i<m_RP.m_NumActiveDLights; i++)
|
|
{
|
|
if (i >= 16)
|
|
break;
|
|
CDLight *dl = m_RP.m_pActiveDLights[i];
|
|
if ((Flags & LMF_IGNOREPROJLIGHTS) && (dl->m_Flags & DLF_PROJECT))
|
|
continue;
|
|
int nlM;
|
|
bool bSpecularOnly = false;
|
|
if (nlM=(Flags & LMF_LIGHT_MASK))
|
|
{
|
|
if ((nlM >> LMF_LIGHT_SHIFT) != i)
|
|
continue;
|
|
}
|
|
if (dl->m_Flags & DLF_LM)
|
|
{
|
|
if ((m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_Textures[EFTT_LIGHTMAP]) || m_RP.m_pCurObject->m_nLMId)
|
|
{
|
|
if (Flags & LMF_NOSPECULAR)
|
|
continue;
|
|
bSpecularOnly = true;
|
|
}
|
|
}
|
|
|
|
// some statistics
|
|
if (!(m_RP.m_StatLightMask & (1<<i)))
|
|
{
|
|
m_RP.m_StatLightMask |= (1<<i);
|
|
m_RP.m_StatNumLights++;
|
|
}
|
|
|
|
Matrix44 m = m_RP.m_pCurObject->GetInvMatrix();
|
|
TransformPosition(lpos, dl->m_Origin, m);
|
|
//TransformPoint(m, dl->m_Origin, lpos);
|
|
//TransformPosition33(lpos, dl->m_Origin-m_RP.m_pCurObject->m_Matrix.GetTranslationOLD(), Matrix33(GetTransposed44(m_RP.m_pCurObject->m_Matrix)));
|
|
|
|
float fRange = 0;
|
|
if (dl->m_Flags & DLF_DIRECTIONAL)
|
|
{
|
|
Pos[3] = 0.0f;
|
|
fCA = 1.0f;
|
|
fLA = 0.0f;
|
|
fQA = 0.0f;
|
|
cDiffuse = dl->m_Color;
|
|
}
|
|
else
|
|
{
|
|
fRange = dl->m_fRadius;
|
|
Pos[3] = 1.0f;
|
|
if (!bCalcDist)
|
|
{
|
|
bCalcDist = true;
|
|
if (m_RP.m_pRE)
|
|
{
|
|
Vec3d vMins, vMaxs;
|
|
m_RP.m_pRE->mfGetBBox(vMins, vMaxs);
|
|
vCenterRE = (vMins + vMaxs) * 0.5f;
|
|
vCenterRE += m_RP.m_pCurObject->GetTranslation();
|
|
fRadRE = (vMaxs - vMins).Length() * 0.5f;
|
|
}
|
|
else
|
|
{
|
|
fRadRE = 1000.0f;
|
|
vCenterRE = Vec3(0,0,0);
|
|
}
|
|
}
|
|
float fDist = max(0.1f, (vCenterRE - dl->m_Origin).Length());
|
|
float fMaxDist = CLAMP(fDist + fRadRE, dl->m_fRadius * 0.1f, dl->m_fRadius * 0.99f);
|
|
float fMinDist = CLAMP(fDist - fRadRE, dl->m_fRadius * 0.1f, dl->m_fRadius * 0.99f);
|
|
float fMinAtt = 1.0f / sAttenuation(fMinDist, dl->m_fRadius*0.9f);
|
|
float fMaxAtt = 1.0f / sAttenuation(fMaxDist, dl->m_fRadius*0.9f);
|
|
if(fabsf(fMinAtt - fMaxAtt) < 0.00001f)
|
|
{
|
|
fCA = fMinAtt;
|
|
fLA = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
fCA = max(0.01f, fMinAtt - (fMaxAtt - fMinAtt) / (fMaxDist - fMinDist) * fMinDist);
|
|
fLA = max(0.0f, (fMinAtt - fCA) / fMinDist);
|
|
}
|
|
fQA = 0;
|
|
fRange = (256.0f - fCA) / max(0.01f, fLA);
|
|
if (fRange < 0)
|
|
fRange = 0;
|
|
cDiffuse = dl->m_Color;
|
|
}
|
|
/*static float sCA = 0;
|
|
static float sLA = 0;
|
|
static float sRange = 0;
|
|
if (GetAsyncKeyState(VK_NUMPAD1) & 0x8000)
|
|
sCA -= 0.001f;
|
|
if (GetAsyncKeyState(VK_NUMPAD3) & 0x8000)
|
|
sCA += 0.001f;
|
|
if (GetAsyncKeyState(VK_NUMPAD4) & 0x8000)
|
|
sLA -= 0.01f;
|
|
if (GetAsyncKeyState(VK_NUMPAD6) & 0x8000)
|
|
sLA += 0.01f;
|
|
if (GetAsyncKeyState(VK_NUMPAD7) & 0x8000)
|
|
sRange -= 0.1f;
|
|
if (GetAsyncKeyState(VK_NUMPAD9) & 0x8000)
|
|
sRange += 0.1f;
|
|
fCA += sCA;
|
|
fLA += sLA;
|
|
fRange += sRange;*/
|
|
|
|
fCA = max(0.0f, fCA);
|
|
fLA = max(0.0f, fLA);
|
|
fQA = max(0.0f, fQA);
|
|
Pos[0] = lpos.x;
|
|
Pos[1] = lpos.y;
|
|
Pos[2] = lpos.z;
|
|
cDiffuse.a = 1.0f;
|
|
if (!(Flags & LMF_NOSPECULAR))
|
|
cSpecular = dl->m_SpecColor;
|
|
if (bSpecularOnly)
|
|
cDiffuse = Col_Black;
|
|
EF_SetHWLight(n, Pos,
|
|
cDiffuse,
|
|
cSpecular,
|
|
fCA, fLA, fQA, fRange);
|
|
n++;
|
|
}
|
|
m_RP.m_CurrentVLightFlags = Flags;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Initialize HW vertex lighting states for the fixed pipeline shader
|
|
void CD3D9Renderer::EF_LightMaterial(SLightMaterial *lm, int Flags)
|
|
{
|
|
if (!(m_RP.m_pShader->m_Flags & EF_NEEDNORMALS))
|
|
return;
|
|
if (m_RP.m_ObjFlags & FOB_FOGPASS)
|
|
return;
|
|
|
|
//PROFILE_FRAME(State_LightStates);
|
|
|
|
// Use fake lighting with TFactor
|
|
if (!m_RP.m_NumActiveDLights && !(Flags & LMF_HASPSHADER))
|
|
{
|
|
EF_ConstantLightMaterial(lm, Flags);
|
|
return;
|
|
}
|
|
|
|
if (!(Flags & LMF_IGNORELIGHTS) && EF_SetLights(Flags))
|
|
{
|
|
if (!(m_RP.m_CurrentVLights & 0xff) && !(Flags & LMF_HASPSHADER))
|
|
{
|
|
EF_ConstantLightMaterial(lm, Flags);
|
|
return;
|
|
}
|
|
m_RP.m_FlagsPerFlush &= ~(RBSI_GLOBALRGB | RBSI_GLOBALALPHA);
|
|
CFColor colAmb = EF_GetCurrentAmbient(lm, Flags);
|
|
m_Material.Ambient.r = colAmb.r;
|
|
m_Material.Ambient.g = colAmb.g;
|
|
m_Material.Ambient.b = colAmb.b;
|
|
m_Material.Ambient.a = colAmb.a;
|
|
|
|
CFColor colDif = EF_GetCurrentDiffuse(lm, Flags);
|
|
m_Material.Diffuse.r = colDif.r;
|
|
m_Material.Diffuse.g = colDif.g;
|
|
m_Material.Diffuse.b = colDif.b;
|
|
m_Material.Diffuse.a = colAmb.a;
|
|
|
|
// Disable emissive materials to match result to programmable pipeline
|
|
// Pixel shaders don't support emmissive parameters
|
|
//m_Material.Emissive.r = 0; //lm->Front.m_Emission.r;
|
|
//m_Material.Emissive.g = 0; //lm->Front.m_Emission.g;
|
|
//m_Material.Emissive.b = 0; //lm->Front.m_Emission.b;
|
|
//m_Material.Emissive.a = 0; //lm->Front.m_Emission.a;
|
|
|
|
if (!(Flags & LMF_NOSPECULAR))
|
|
{
|
|
m_Material.Specular.r = lm->Front.m_Specular.r;
|
|
m_Material.Specular.g = lm->Front.m_Specular.g;
|
|
m_Material.Specular.b = lm->Front.m_Specular.b;
|
|
m_Material.Specular.a = lm->Front.m_Specular.a;
|
|
|
|
m_Material.Power = lm->Front.m_SpecShininess;
|
|
if (lm->Front.m_Specular == CFColor(0.0f))
|
|
m_Material.Power = 0;
|
|
}
|
|
else
|
|
{
|
|
m_Material.Specular.r = 0;
|
|
m_Material.Specular.g = 0;
|
|
m_Material.Specular.b = 0;
|
|
m_Material.Specular.a = 0;
|
|
|
|
m_Material.Power = 0;
|
|
}
|
|
}
|
|
m_pd3dDevice->SetMaterial(&m_Material);
|
|
m_RP.m_CurrentVLights |= 0x80000000;
|
|
|
|
m_RP.m_TexStages[0].m_CA = eCA_Texture | (eCA_Diffuse<<3);
|
|
m_RP.m_TexStages[0].m_AA = eCA_Texture | (eCA_Diffuse<<3);
|
|
}
|
|
|
|
//=============================================================
|
|
// Calculate matrices (usually texture matrices) for fixed pipeline shaders
|
|
// Set texture transform modes
|
|
void CD3D9Renderer::EF_ApplyMatrixOps(TArray<SMatrixTransform>* MatrixOps, bool bEnable)
|
|
{
|
|
if (!MatrixOps)
|
|
return;
|
|
|
|
LPDIRECT3DDEVICE9 dv = m_pd3dDevice;
|
|
int CurMatrix = D3DTS_VIEW;
|
|
m_CurOpMatrix = NULL;
|
|
int Stage = -1;
|
|
bool bProjected;
|
|
int nCoords = 2;
|
|
int nCurMatrix;
|
|
|
|
for (int i=0; i<MatrixOps->Num(); i++)
|
|
{
|
|
SMatrixTransform *mt = &MatrixOps->Get(i);
|
|
nCurMatrix = mt->m_Matrix & 0xff;
|
|
bProjected = (mt->m_Matrix & 0x8000) != 0;
|
|
if (mt->m_Matrix >> 16)
|
|
nCoords = (mt->m_Matrix >> 16);
|
|
if (nCurMatrix != CurMatrix)
|
|
{
|
|
if (m_CurOpMatrix)
|
|
{
|
|
if (Stage >= 0)
|
|
dv->SetTextureStageState( Stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );
|
|
dv->SetTransform((D3DTRANSFORMSTATETYPE)CurMatrix, m_CurOpMatrix);
|
|
m_CurOpMatrix = NULL;
|
|
}
|
|
switch (nCurMatrix)
|
|
{
|
|
case D3DTS_TEXTURE0:
|
|
m_CurOpMatrix = &m_TexMatrix[0];
|
|
Stage = 0;
|
|
break;
|
|
case D3DTS_TEXTURE1:
|
|
m_CurOpMatrix = &m_TexMatrix[1];
|
|
Stage = 1;
|
|
break;
|
|
case D3DTS_TEXTURE2:
|
|
m_CurOpMatrix = &m_TexMatrix[2];
|
|
Stage = 2;
|
|
break;
|
|
case D3DTS_TEXTURE3:
|
|
m_CurOpMatrix = &m_TexMatrix[3];
|
|
Stage = 3;
|
|
break;
|
|
default:
|
|
Stage = -1;
|
|
}
|
|
if (!bEnable && mt->m_Matrix != D3DTS_PROJECTION && mt->m_Matrix != D3DTS_VIEW)
|
|
{
|
|
if (m_CurOpMatrix)
|
|
{
|
|
D3DXMatrixIdentity(m_CurOpMatrix);
|
|
dv->SetTransform((D3DTRANSFORMSTATETYPE)nCurMatrix, m_CurOpMatrix);
|
|
if (Stage >= 0)
|
|
dv->SetTextureStageState( Stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
|
|
}
|
|
}
|
|
CurMatrix = nCurMatrix;
|
|
}
|
|
mt->mfSet(bEnable);
|
|
}
|
|
if (m_CurOpMatrix && bEnable)
|
|
{
|
|
if (Stage >= 0)
|
|
{
|
|
if (bProjected)
|
|
dv->SetTextureStageState( Stage, D3DTSS_TEXTURETRANSFORMFLAGS, nCoords | D3DTTFF_PROJECTED);
|
|
else
|
|
dv->SetTextureStageState( Stage, D3DTSS_TEXTURETRANSFORMFLAGS, nCoords);
|
|
}
|
|
if (nCoords < 3)
|
|
{
|
|
m_CurOpMatrix->_31 = m_CurOpMatrix->_41;
|
|
m_CurOpMatrix->_32 = m_CurOpMatrix->_42;
|
|
m_CurOpMatrix->_33 = m_CurOpMatrix->_43;
|
|
m_CurOpMatrix->_34 = m_CurOpMatrix->_44;
|
|
}
|
|
//D3DXMatrixTranspose(m_CurOpMatrix, m_CurOpMatrix);
|
|
dv->SetTransform((D3DTRANSFORMSTATETYPE)nCurMatrix, m_CurOpMatrix);
|
|
}
|
|
}
|
|
|
|
#include "../Common/NvTriStrip/NVTriStrip.h"
|
|
|
|
// Commit changed states to the hardware before drawing
|
|
bool CD3D9Renderer::EF_PreDraw(SShaderPass *sl, bool bSetVertexDecl)
|
|
{
|
|
bool bRet = true;
|
|
|
|
//PROFILE_FRAME(Draw_Predraw);
|
|
|
|
EF_CommitShadersState();
|
|
EF_CommitVLightsState();
|
|
|
|
HRESULT hr;
|
|
if (bSetVertexDecl)
|
|
{
|
|
hr = EF_SetVertexDeclaration(m_RP.m_FlagsModificators&7, m_RP.m_CurVFormat);
|
|
if (hr != S_OK)
|
|
return false;
|
|
}
|
|
|
|
if (!m_RP.m_pRE && m_RP.m_RendNumVerts && m_RP.m_RendNumIndices)
|
|
{
|
|
// Mergable geometry (no single render element)
|
|
int nStart;
|
|
int nSize = m_RP.m_Stride*m_RP.m_RendNumVerts;
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_VERTSMERGED))
|
|
{
|
|
m_RP.m_FlagsPerFlush |= RBSI_VERTSMERGED;
|
|
int nFormat = m_RP.m_CurVFormat;
|
|
int nCurVB = m_RP.m_CurVB;
|
|
if (m_RP.m_VBs[nCurVB].VBPtr_0->GetBytesOffset()+nSize >= (int)m_RP.m_VBs[nCurVB].VBPtr_0->GetBytesCount())
|
|
{
|
|
m_RP.m_VBs[nCurVB].VBPtr_0->Reset();
|
|
m_RP.m_CurVB = (nCurVB + 1) & (MAX_DYNVBS-1);
|
|
}
|
|
nCurVB = m_RP.m_CurVB;
|
|
Vec3 *pVB = m_RP.m_VBs[nCurVB].VBPtr_0->Lock(nSize, nStart);
|
|
cryMemcpy(pVB, m_RP.m_Ptr.Ptr, nSize);
|
|
m_RP.m_VBs[nCurVB].VBPtr_0->Unlock();
|
|
m_RP.m_FirstVertex = 0;
|
|
m_RP.m_MergedStreams[0] = m_RP.m_VBs[nCurVB];
|
|
m_RP.m_nStreamOffset[0] = nStart;
|
|
|
|
ushort *pIB = m_RP.m_IndexBuf->Lock(m_RP.m_RendNumIndices, nStart);
|
|
cryMemcpy(pIB, m_RP.m_SysRendIndices, m_RP.m_RendNumIndices*sizeof(short));
|
|
m_RP.m_IndexBuf->Unlock();
|
|
m_RP.m_FirstIndex = nStart;
|
|
}
|
|
m_RP.m_MergedStreams[0].VBPtr_0->Bind(m_pd3dDevice, 0, m_RP.m_nStreamOffset[0], m_RP.m_Stride);
|
|
m_RP.m_IndexBuf->Bind(m_pd3dDevice);
|
|
|
|
if (m_RP.m_FlagsModificators & FHF_TANGENTS)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_TANGSMERGED))
|
|
{
|
|
m_RP.m_FlagsPerFlush |= RBSI_TANGSMERGED;
|
|
int i;
|
|
int nCurVB = m_RP.m_CurVB;
|
|
int nSize = m_RP.m_RendNumVerts*sizeof(SPipTangents);
|
|
if (m_RP.m_VBs[nCurVB].VBPtr_0->GetBytesOffset()+nSize >= (int)m_RP.m_VBs[nCurVB].VBPtr_0->GetBytesCount())
|
|
{
|
|
m_RP.m_VBs[nCurVB].VBPtr_0->Reset();
|
|
m_RP.m_CurVB = (nCurVB + 1) & (MAX_DYNVBS-1);
|
|
}
|
|
nCurVB = m_RP.m_CurVB;
|
|
SPipTangents *dst = (SPipTangents *)m_RP.m_VBs[nCurVB].VBPtr_0->Lock(nSize, nStart);
|
|
for (i=0; i<m_RP.m_MergedREs.Num(); i++)
|
|
{
|
|
CREOcLeaf *re = m_RP.m_MergedREs[i];
|
|
CCObject *obj = m_RP.m_MergedObjs[i];
|
|
CLeafBuffer *lb = re->m_pBuffer;
|
|
CMatInfo *mi = re->m_pChunk;
|
|
SPipTangents *src = (SPipTangents *)lb->m_pSecVertBuffer->m_VS[VSF_TANGENTS].m_VData;
|
|
src += mi->nFirstVertId;
|
|
int nVerts = mi->nNumVerts;
|
|
if (obj->m_ObjFlags & FOB_TRANS_ROTATE)
|
|
{
|
|
Matrix44 *mat = &obj->m_Matrix;
|
|
#ifdef DO_ASM
|
|
_asm
|
|
{
|
|
mov ecx, nVerts;
|
|
mov eax, mat
|
|
mov esi, src
|
|
mov edi, dst
|
|
movaps xmm2,xmmword ptr [eax]
|
|
movaps xmm4,xmmword ptr [eax+10h]
|
|
movaps xmm6,xmmword ptr [eax+20h]
|
|
align 16
|
|
_Loop:
|
|
movlps xmm1,qword ptr [esi]
|
|
movss xmm0,dword ptr [esi+8]
|
|
shufps xmm0,xmm0,0
|
|
prefetcht0 [esi+10h]
|
|
mulps xmm0,xmm6
|
|
movaps xmm3,xmm1
|
|
shufps xmm3,xmm1,55h
|
|
mulps xmm3,xmm4
|
|
shufps xmm1,xmm1,0
|
|
mulps xmm1,xmm2
|
|
addps xmm3,xmm1
|
|
addps xmm3,xmm0
|
|
movaps xmm1,xmm3 // r1 = vx, vy, vz, X
|
|
mulps xmm1,xmm3 // r1 = vx * vx, vy * vy, vz * vz, X
|
|
movhlps xmm5,xmm1 // r5 = vz * vz, X, X, X
|
|
movaps xmm0,xmm1 // r0 = r1
|
|
shufps xmm0,xmm0, 1 // r0 = vy * vy, X, X, X
|
|
addss xmm1,xmm0 // r0 = (vx * vx) + (vy * vy), X, X, X
|
|
addss xmm1,xmm5 // r1 = (vx * vx) + (vy * vy) + (vz * vz), X, X, X
|
|
sqrtss xmm1,xmm1 // r1 = sqrt((vx * vx) + (vy * vy) + (vz * vz)), X, X, X
|
|
rcpss xmm1,xmm1 // r1 = 1/radius, X, X, X
|
|
shufps xmm1,xmm1, 0 // r1 = 1/radius, 1/radius, 1/radius, X
|
|
mulps xmm3,xmm1 // r3 = vx * 1/radius, vy * 1/radius, vz * 1/radius, X
|
|
movhlps xmm5,xmm3
|
|
movlps qword ptr [edi],xmm3
|
|
movss xmm0,dword ptr [esi+20]
|
|
movss dword ptr [edi+8],xmm5
|
|
|
|
movlps xmm1,qword ptr [esi+12]
|
|
shufps xmm0,xmm0,0
|
|
mulps xmm0,xmm6
|
|
prefetcht0 [esi+20h]
|
|
movaps xmm3,xmm1
|
|
shufps xmm3,xmm1,55h
|
|
mulps xmm3,xmm4
|
|
shufps xmm1,xmm1,0
|
|
mulps xmm1,xmm2
|
|
addps xmm3,xmm1
|
|
addps xmm3,xmm0
|
|
movhlps xmm5,xmm3
|
|
movaps xmm1,xmm3 // r1 = vx, vy, vz, X
|
|
mulps xmm1,xmm3 // r1 = vx * vx, vy * vy, vz * vz, X
|
|
movhlps xmm5,xmm1 // r5 = vz * vz, X, X, X
|
|
movaps xmm0,xmm1 // r0 = r1
|
|
shufps xmm0,xmm0, 1 // r0 = vy * vy, X, X, X
|
|
addss xmm1,xmm0 // r0 = (vx * vx) + (vy * vy), X, X, X
|
|
addss xmm1,xmm5 // r1 = (vx * vx) + (vy * vy) + (vz * vz), X, X, X
|
|
sqrtss xmm1,xmm1 // r1 = sqrt((vx * vx) + (vy * vy) + (vz * vz)), X, X, X
|
|
rcpss xmm1,xmm1 // r1 = 1/radius, X, X, X
|
|
shufps xmm1,xmm1, 0 // r1 = 1/radius, 1/radius, 1/radius, X
|
|
mulps xmm3,xmm1 // r3 = vx * 1/radius, vy * 1/radius, vz * 1/radius, X
|
|
movhlps xmm5,xmm3
|
|
movlps qword ptr [edi+12],xmm3
|
|
movss xmm0,dword ptr [esi+32]
|
|
movss dword ptr [edi+20],xmm5
|
|
|
|
movlps xmm1,qword ptr [esi+24]
|
|
shufps xmm0,xmm0,0
|
|
prefetcht0 [esi+30h]
|
|
mulps xmm0,xmm6
|
|
movaps xmm3,xmm1
|
|
shufps xmm3,xmm1,55h
|
|
mulps xmm3,xmm4
|
|
shufps xmm1,xmm1,0
|
|
mulps xmm1,xmm2
|
|
add edi, 36
|
|
addps xmm3,xmm1
|
|
addps xmm3,xmm0
|
|
movaps xmm1,xmm3 // r1 = vx, vy, vz, X
|
|
mulps xmm1,xmm3 // r1 = vx * vx, vy * vy, vz * vz, X
|
|
add esi, 36
|
|
movhlps xmm5,xmm1 // r5 = vz * vz, X, X, X
|
|
movaps xmm0,xmm1 // r0 = r1
|
|
shufps xmm0,xmm0, 1 // r0 = vy * vy, X, X, X
|
|
addss xmm1,xmm0 // r0 = (vx * vx) + (vy * vy), X, X, X
|
|
addss xmm1,xmm5 // r1 = (vx * vx) + (vy * vy) + (vz * vz), X, X, X
|
|
sqrtss xmm1,xmm1 // r1 = sqrt((vx * vx) + (vy * vy) + (vz * vz)), X, X, X
|
|
rcpss xmm1,xmm1 // r1 = 1/radius, X, X, X
|
|
shufps xmm1,xmm1, 0 // r1 = 1/radius, 1/radius, 1/radius, X
|
|
mulps xmm3,xmm1 // r3 = vx * 1/radius, vy * 1/radius, vz * 1/radius, X
|
|
dec ecx
|
|
movhlps xmm5,xmm3
|
|
movlps qword ptr [edi+24-36],xmm3
|
|
movss dword ptr [edi+32-36],xmm5
|
|
|
|
jne _Loop
|
|
mov dst, edi
|
|
}
|
|
#else
|
|
for (int j=0; j<mi->nNumVerts; j++)
|
|
{
|
|
dst->m_Tangent = mat->TransformVectorOLD(src->m_Tangent);
|
|
dst->m_Binormal = mat->TransformVectorOLD(src->m_Binormal);
|
|
dst->m_TNormal = mat->TransformVectorOLD(src->m_TNormal);
|
|
src++;
|
|
dst++;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
for (i=0; i<mi->nNumVerts; i++)
|
|
{
|
|
*dst = *src;
|
|
src++;
|
|
dst++;
|
|
}
|
|
}
|
|
}
|
|
m_RP.m_VBs[nCurVB].VBPtr_0->Unlock();
|
|
m_RP.m_MergedStreams[1] = m_RP.m_VBs[nCurVB];
|
|
m_RP.m_nStreamOffset[1] = nStart;
|
|
}
|
|
m_RP.m_MergedStreams[1].VBPtr_0->Bind(m_pd3dDevice, 1, m_RP.m_nStreamOffset[1], sizeof(SPipTangents));
|
|
m_RP.m_PersFlags |= RBPF_USESTREAM1;
|
|
}
|
|
else
|
|
if (m_RP.m_PersFlags & RBPF_USESTREAM1)
|
|
{
|
|
m_RP.m_PersFlags &= ~RBPF_USESTREAM1;
|
|
m_pd3dDevice->SetStreamSource(1, NULL, 0, 0);
|
|
}
|
|
if (m_RP.m_FlagsModificators & RBMF_LMTCUSED)
|
|
{
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_LMTCMERGED))
|
|
{
|
|
m_RP.m_FlagsPerFlush |= RBSI_LMTCMERGED;
|
|
nSize = sizeof(struct_VERTEX_FORMAT_TEX2F)*m_RP.m_RendNumVerts;
|
|
int nCurVB = m_RP.m_CurVB;
|
|
if (m_RP.m_VBs[nCurVB].VBPtr_0->GetBytesOffset()+nSize >= (int)m_RP.m_VBs[nCurVB].VBPtr_0->GetBytesCount())
|
|
{
|
|
m_RP.m_VBs[nCurVB].VBPtr_0->Reset();
|
|
m_RP.m_CurVB = (nCurVB + 1) & (MAX_DYNVBS-1);
|
|
}
|
|
nCurVB = m_RP.m_CurVB;
|
|
struct_VERTEX_FORMAT_TEX2F *dst = (struct_VERTEX_FORMAT_TEX2F *)m_RP.m_VBs[nCurVB].VBPtr_0->Lock(nSize, nStart);
|
|
for (int i=0; i<m_RP.m_MergedREs.Num(); i++)
|
|
{
|
|
CREOcLeaf *re = m_RP.m_MergedREs[i];
|
|
CCObject *pObj = m_RP.m_MergedObjs[i];
|
|
int nNumVerts = re->m_pChunk->nNumVerts;
|
|
if (!pObj->m_pLMTCBufferO)
|
|
{
|
|
dst += nNumVerts;
|
|
continue;
|
|
}
|
|
struct_VERTEX_FORMAT_TEX2F *src = (struct_VERTEX_FORMAT_TEX2F *)pObj->m_pLMTCBufferO->m_pSecVertBuffer->m_VS[0].m_VData;
|
|
src += re->m_pChunk->nFirstVertId;
|
|
for (int n=0; n<nNumVerts; n++)
|
|
{
|
|
*dst++ = *src++;
|
|
}
|
|
}
|
|
m_RP.m_VBs[nCurVB].VBPtr_0->Unlock();
|
|
m_RP.m_MergedStreams[2] = m_RP.m_VBs[nCurVB];
|
|
m_RP.m_nStreamOffset[2] = nStart;
|
|
}
|
|
m_RP.m_MergedStreams[2].VBPtr_0->Bind(m_pd3dDevice, 2, m_RP.m_nStreamOffset[2], sizeof(SMRendTexVert));
|
|
m_RP.m_PersFlags |= RBPF_USESTREAM2;
|
|
}
|
|
else
|
|
if (m_RP.m_PersFlags & RBPF_USESTREAM2)
|
|
{
|
|
m_RP.m_PersFlags &= ~RBPF_USESTREAM2;
|
|
m_pd3dDevice->SetStreamSource(2, NULL, 0, 0);
|
|
}
|
|
}
|
|
else
|
|
if (m_RP.m_pRE)
|
|
bRet = m_RP.m_pRE->mfPreDraw(sl);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
// Draw current indexed mesh
|
|
void CD3D9Renderer::EF_DrawIndexedMesh (int nPrimType)
|
|
{
|
|
HRESULT h = 0;
|
|
|
|
if (CV_r_nodrawshaders)
|
|
return;
|
|
|
|
D3DPRIMITIVETYPE nType;
|
|
int nFaces;
|
|
|
|
switch (nPrimType)
|
|
{
|
|
case R_PRIMV_TRIANGLES:
|
|
nType = D3DPT_TRIANGLELIST;
|
|
nFaces = m_RP.m_RendNumIndices/3;
|
|
break;
|
|
|
|
case R_PRIMV_TRIANGLE_STRIP:
|
|
nType = D3DPT_TRIANGLESTRIP;
|
|
nFaces = m_RP.m_RendNumIndices-2;
|
|
break;
|
|
|
|
case R_PRIMV_TRIANGLE_FAN:
|
|
nType = D3DPT_TRIANGLEFAN;
|
|
nFaces = m_RP.m_RendNumIndices-2;
|
|
break;
|
|
|
|
case R_PRIMV_MULTI_STRIPS:
|
|
{
|
|
list2<CMatInfo> *mats = m_RP.m_pRE->mfGetMatInfoList();
|
|
if (mats)
|
|
{
|
|
CMatInfo *m = mats->Get(0);
|
|
for (int i=0; i<mats->Count(); i++, m++)
|
|
{
|
|
m_RP.m_PS.m_NumDrawCalls++;
|
|
if (FAILED(h=m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, m_RP.m_BaseVertex, m->nFirstVertId, m->nNumVerts, m->nFirstIndexId, m->nNumIndices - 2)))
|
|
{
|
|
Error("CD3D9Renderer::EF_DrawIndexedMesh: DrawIndexedPrimitive error", h);
|
|
return;
|
|
}
|
|
m_nPolygons += (m->nNumIndices - 2);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case R_PRIMV_MULTI_GROUPS:
|
|
{
|
|
CMatInfo *mi = m_RP.m_pRE->mfGetMatInfo();
|
|
if (mi)
|
|
{
|
|
int offs = mi->nFirstIndexId;
|
|
for (int i=0; i<mi->m_dwNumSections; i++)
|
|
{
|
|
SPrimitiveGroup *g = &mi->m_pPrimitiveGroups[i];
|
|
m_RP.m_PS.m_NumDrawCalls++;
|
|
switch (g->type)
|
|
{
|
|
case PT_STRIP:
|
|
if (FAILED(h=m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, m_RP.m_BaseVertex, m_RP.m_FirstVertex, mi->nNumVerts, g->offsIndex+offs, g->numIndices - 2)))
|
|
{
|
|
Error("CD3D9Renderer::EF_DrawIndexedMesh: DrawIndexedPrimitive error", h);
|
|
return;
|
|
}
|
|
m_nPolygons += (g->numIndices - 2);
|
|
break;
|
|
|
|
case PT_LIST:
|
|
if (FAILED(h=m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, m_RP.m_BaseVertex, m_RP.m_FirstVertex, mi->nNumVerts, g->offsIndex+offs, g->numIndices / 3)))
|
|
{
|
|
Error("CD3D9Renderer::EF_DrawIndexedMesh: DrawIndexedPrimitive error", h);
|
|
return;
|
|
}
|
|
m_nPolygons += (g->numIndices / 3);
|
|
break;
|
|
|
|
case PT_FAN:
|
|
if (FAILED(h=m_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLEFAN, m_RP.m_BaseVertex, m_RP.m_FirstVertex, mi->nNumVerts, g->offsIndex+offs, g->numIndices - 2)))
|
|
{
|
|
Error("CD3D9Renderer::EF_DrawIndexedMesh: DrawIndexedPrimitive error", h);
|
|
return;
|
|
}
|
|
m_nPolygons += (g->numIndices - 2);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
assert(0);
|
|
}
|
|
|
|
if (nFaces)
|
|
{
|
|
m_RP.m_PS.m_NumDrawCalls++;
|
|
//m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
|
|
if (FAILED(h=m_pd3dDevice->DrawIndexedPrimitive(nType, m_RP.m_BaseVertex, m_RP.m_FirstVertex, m_RP.m_RendNumVerts, m_RP.m_FirstIndex, nFaces)))
|
|
{
|
|
Error("CD3D9Renderer::EF_DrawIndexedMesh: DrawIndexedPrimitive error", h);
|
|
return;
|
|
}
|
|
m_nPolygons += nFaces;
|
|
}
|
|
else
|
|
{
|
|
int nnn = 0;
|
|
}
|
|
}
|
|
|
|
// Draw volumetric fog passes (used in FP shaders and in programmable pipeline shaders)
|
|
void CD3D9Renderer::EF_DrawFogOverlayPasses()
|
|
{
|
|
// Usually it means first pass in indoor engine (before shadow pass)
|
|
if (m_RP.m_ObjFlags & FOB_ZPASS)
|
|
return;
|
|
if (m_RP.m_FlagsPerFlush & RBSI_FOGVOLUME)
|
|
return;
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
Logv(SRendItem::m_RecurseLevel, "--- Fog Pass ---\n");
|
|
#endif
|
|
|
|
float fWatLevel = iSystem->GetI3DEngine()->GetWaterLevel();
|
|
SMFog *fb = m_RP.m_pFogVolume;
|
|
SShader *sh = NULL;
|
|
bool bVFFP = false;
|
|
if (!(m_Features & RFT_HW_VS) || CV_r_Quality_BumpMapping == 0)
|
|
bVFFP = true;
|
|
if (!bVFFP || (m_RP.m_pShader->m_Flags & EF_HASVSHADER))
|
|
{
|
|
if (m_RP.m_pShader->m_eSort != eS_Water && fabs(fb->m_Dist-fWatLevel) < 0.1f && SRendItem::m_RecurseLevel <= 1)
|
|
{
|
|
if (m_RP.m_pRE)
|
|
{
|
|
float fDist;
|
|
#ifndef PIPE_USE_INSTANCING
|
|
fDist = m_RP.m_pRE->mfMinDistanceToCamera(m_RP.m_pCurObject);
|
|
#else
|
|
CCObject *pObj = m_RP.m_pCurObject;
|
|
int nObj = 0;
|
|
fDist = 999999.0f;
|
|
while (true)
|
|
{
|
|
fDist = min(fDist, m_RP.m_pRE->mfMinDistanceToCamera(pObj));
|
|
nObj++;
|
|
if (nObj >= m_RP.m_MergedObjects.Num())
|
|
break;
|
|
pObj = gRenDev->m_RP.m_MergedObjects[nObj];
|
|
}
|
|
#endif
|
|
if (fDist < 40.0f && fb->bCaustics)
|
|
sh = m_cEF.m_ShaderFogCaust;
|
|
else
|
|
sh = m_cEF.m_ShaderFog;
|
|
}
|
|
else
|
|
if (fb->bCaustics)
|
|
sh = m_cEF.m_ShaderFogCaust;
|
|
else
|
|
sh = m_cEF.m_ShaderFog;
|
|
}
|
|
else
|
|
sh = m_cEF.m_ShaderFog;
|
|
}
|
|
else
|
|
sh = m_cEF.m_ShaderFog_FP;
|
|
|
|
if (sh && sh->m_HWTechniques.Num())
|
|
{
|
|
if (m_RP.m_pShader->m_eSort == eS_Water && m_RP.m_pFogVolume)
|
|
m_RP.m_pFogVolume->m_Dist += 0.1f;
|
|
EF_DrawGeneralPasses(sh->m_HWTechniques[0], sh, true, 0, sh->m_HWTechniques[0]->m_Passes.Num()-1, false);
|
|
if (m_RP.m_pShader->m_eSort == eS_Water && m_RP.m_pFogVolume)
|
|
m_RP.m_pFogVolume->m_Dist -= 0.1f;
|
|
}
|
|
}
|
|
|
|
// Draw detail textures passes (used in FP shaders and in programmable pipeline shaders)
|
|
void CD3D9Renderer::EF_DrawDetailOverlayPasses()
|
|
{
|
|
// Usually it means first pass in indoor engine (before shadow pass)
|
|
if (m_RP.m_ObjFlags & FOB_ZPASS)
|
|
return;
|
|
|
|
if (!m_RP.m_pShaderResources || !m_RP.m_pShaderResources->m_Textures[EFTT_DETAIL_OVERLAY])
|
|
return;
|
|
|
|
SEfResTexture *rt = m_RP.m_pShaderResources->m_Textures[EFTT_DETAIL_OVERLAY];
|
|
SShader *sh = m_RP.m_pShader;
|
|
int i;
|
|
SMFog fg;
|
|
|
|
float fDistToCam = 500.0f;
|
|
float fDist = CV_r_detaildistance;
|
|
static TArray<float> sfDistRender;
|
|
if (m_RP.m_pRE)
|
|
{
|
|
#ifndef PIPE_USE_INSTANCING
|
|
fDistToCam = m_RP.m_pRE->mfMinDistanceToCamera(m_RP.m_pCurObject);
|
|
if (fDistToCam > fDist+1.0f)
|
|
return;
|
|
#else
|
|
CCObject *pObj = gRenDev->m_RP.m_pCurObject;
|
|
int nObj = 0;
|
|
float fDistToCam = 999999.0f;
|
|
sfDistRender.SetUse(0);
|
|
while (true)
|
|
{
|
|
float fDistObj = m_RP.m_pRE->mfMinDistanceToCamera(pObj);
|
|
if (fDistObj <= fDist+1.0f)
|
|
sfDistRender.AddElem(fDistObj);
|
|
else
|
|
sfDistRender.AddElem(-1.0f);
|
|
fDistToCam = min(fDistToCam, fDistObj);
|
|
nObj++;
|
|
if (nObj >= gRenDev->m_RP.m_MergedObjects.Num())
|
|
break;
|
|
pObj = gRenDev->m_RP.m_MergedObjects[nObj];
|
|
}
|
|
if (fDistToCam > fDist+1.0f)
|
|
return;
|
|
EF_PushMatrix();
|
|
#endif
|
|
}
|
|
else
|
|
return;
|
|
|
|
PROFILE_FRAME(DrawShader_DetailPasses);
|
|
|
|
SMFog *fb = gRenDev->m_RP.m_pFogVolume;
|
|
fg.m_FogInfo.m_WaveFogGen.m_eWFType = eWF_None;
|
|
gRenDev->m_RP.m_pFogVolume = &fg;
|
|
|
|
CD3D9TexMan::BindNULL(2);
|
|
EF_SelectTMU(1);
|
|
gRenDev->m_TexMan->m_Text_Fog->Set();
|
|
EF_SelectTMU(0);
|
|
rt->m_TU.m_TexPic->Set();
|
|
m_RP.m_CurrentVLights = 0;
|
|
|
|
if (m_RP.m_FlagsPerFlush & RBSI_WASDEPTHWRITE)
|
|
EF_SetState(GS_BLSRC_DSTCOL | GS_BLDST_SRCCOL | GS_DEPTHFUNC_EQUAL);
|
|
else
|
|
EF_SetState(GS_BLSRC_DSTCOL | GS_BLDST_SRCCOL);
|
|
|
|
SParamComp_FogMatrix FM;
|
|
vec4_t Vals;
|
|
m_RP.m_FlagsModificators &= ~(7 | (RBMF_TCM | RBMF_TCG));
|
|
if (m_RP.m_TexStages[0].TCIndex != 0)
|
|
{
|
|
m_RP.m_TexStages[0].TCIndex = 0;
|
|
m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU | 0);
|
|
}
|
|
EF_Scissor(false, 0, 0, 0, 0);
|
|
|
|
if (!(sh->m_Flags & EF_HASVSHADER))
|
|
{
|
|
m_RP.m_PersFlags &= ~RBPF_VSNEEDSET;
|
|
|
|
int n = CLAMP(CV_r_detailnumlayers, 1, 4);
|
|
float fUScale = rt->m_TexModificator.m_Tiling[0];
|
|
float fVScale = rt->m_TexModificator.m_Tiling[1];
|
|
if (!fUScale)
|
|
fUScale = CV_r_detailscale;
|
|
if (!fVScale)
|
|
fVScale = CV_r_detailscale;
|
|
|
|
m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
|
|
m_pd3dDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
|
|
m_pd3dDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION | 1);
|
|
|
|
D3DXMATRIX mat, ma, *mi;
|
|
for (i=0; i<n; i++)
|
|
{
|
|
fg.m_fMaxDist = fDist;
|
|
|
|
D3DXMatrixIdentity(&mat);
|
|
D3DXMatrixScaling(&ma, fUScale, fVScale, 1.0f);
|
|
m_pd3dDevice->SetTransform(D3DTS_TEXTURE0, &ma);
|
|
|
|
#ifndef PIPE_USE_INSTANCING
|
|
mi = EF_InverseMatrix();
|
|
FM.m_Offs = 0;
|
|
FM.mfGet4f(Vals);
|
|
mat.m[0][0] = Vals[0];
|
|
mat.m[1][0] = Vals[1];
|
|
mat.m[2][0] = Vals[2];
|
|
mat.m[3][0] = Vals[3];
|
|
|
|
FM.m_Offs = 1;
|
|
FM.mfGet4f(Vals);
|
|
mat.m[0][1] = Vals[0];
|
|
mat.m[1][1] = Vals[1];
|
|
mat.m[2][1] = Vals[2];
|
|
mat.m[3][1] = Vals[3];
|
|
|
|
D3DXMatrixMultiply(&ma, mi, &mat);
|
|
m_pd3dDevice->SetTransform(D3DTS_TEXTURE1, &ma );
|
|
|
|
if (!m_RP.m_RCDetail)
|
|
m_RP.m_RCDetail = CPShader::mfForName("CGRCDetailAtten", true);
|
|
if (m_RP.m_RCDetail)
|
|
m_RP.m_RCDetail->mfSet(true);
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Detail Pass %d [Dist: %.3f]\n", m_RP.m_RendPass, fDist);
|
|
#endif
|
|
|
|
// Draw primitives
|
|
EF_Draw(sh, NULL);
|
|
#else
|
|
int bFogOverrided = 0;
|
|
EF_PreDraw(NULL);
|
|
if (m_FS.m_bEnable)
|
|
bFogOverrided = EF_FogCorrection(false, false);
|
|
|
|
if (m_Features & (RFT_HW_RC | RFT_HW_PS20))
|
|
{
|
|
if (!m_RP.m_RCDetail)
|
|
m_RP.m_RCDetail = CPShader::mfForName("CGRCDetailAtten");
|
|
if (m_RP.m_RCDetail)
|
|
m_RP.m_RCDetail->mfSet(true);
|
|
}
|
|
else
|
|
{
|
|
UCol col;
|
|
col.dcolor = 0xff808080;
|
|
if (m_RP.m_CurGlobalColor.dcolor != col.dcolor)
|
|
{
|
|
m_RP.m_CurGlobalColor = col;
|
|
m_pd3dDevice->SetRenderState(D3DRS_TEXTUREFACTOR, m_RP.m_CurGlobalColor.dcolor);
|
|
}
|
|
EF_SelectTMU(0);
|
|
EF_SetColorOp(eCO_REPLACE, eCO_REPLACE, DEF_TEXARG0, DEF_TEXARG0);
|
|
EF_SelectTMU(1);
|
|
EF_SetColorOp(eCO_BLENDTEXTUREALPHA, eCO_REPLACE, eCA_Constant|(eCA_Previous<<3), DEF_TEXARG0);
|
|
}
|
|
|
|
CCObject *pSaveObj = m_RP.m_pCurObject;
|
|
CCObject *pObj = pSaveObj;
|
|
int nObj = 0;
|
|
while (true)
|
|
{
|
|
if (sfDistRender[nObj] > 0)
|
|
{
|
|
if (nObj)
|
|
{
|
|
m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj];
|
|
m_RP.m_FrameObject++;
|
|
pObj = m_RP.m_pCurObject;
|
|
EF_SetObjectTransform(pObj, sh, pObj->m_ObjFlags);
|
|
}
|
|
|
|
mi = EF_InverseMatrix();
|
|
FM.m_Offs = 0;
|
|
FM.mfGet4f(Vals);
|
|
mat.m[0][0] = Vals[0];
|
|
mat.m[1][0] = Vals[1];
|
|
mat.m[2][0] = Vals[2];
|
|
mat.m[3][0] = Vals[3];
|
|
|
|
FM.m_Offs = 1;
|
|
FM.mfGet4f(Vals);
|
|
mat.m[0][1] = Vals[0];
|
|
mat.m[1][1] = Vals[1];
|
|
mat.m[2][1] = Vals[2];
|
|
mat.m[3][1] = Vals[3];
|
|
|
|
|
|
D3DXMatrixMultiply(&ma, mi, &mat);
|
|
m_pd3dDevice->SetTransform(D3DTS_TEXTURE1, &ma );
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
{
|
|
Vec3d vPos = pObj->GetTranslation();
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Detail Pass %d [Dist: %.3f] (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, fDist, pObj->m_VisId, vPos[0], vPos[1], vPos[2]);
|
|
}
|
|
#endif
|
|
|
|
{
|
|
//PROFILE_FRAME(Draw_ShaderIndexMesh);
|
|
if (m_RP.m_pRE)
|
|
m_RP.m_pRE->mfDraw(sh, NULL);
|
|
else
|
|
EF_DrawIndexedMesh(R_PRIMV_TRIANGLES);
|
|
}
|
|
}
|
|
nObj++;
|
|
if (nObj >= m_RP.m_MergedObjects.Num())
|
|
break;
|
|
}
|
|
EF_FogRestore(bFogOverrided);
|
|
if (m_RP.m_FlagsModificators & (RBMF_TCM | RBMF_TCG))
|
|
EF_CommitTexTransforms(false);
|
|
else
|
|
m_RP.m_FlagsModificators &= ~(RBMF_TCM | RBMF_TCG);
|
|
if (pSaveObj != m_RP.m_pCurObject)
|
|
{
|
|
m_RP.m_pCurObject = pSaveObj;
|
|
m_RP.m_FrameObject++;
|
|
EF_SetObjectTransform(pSaveObj, sh, pSaveObj->m_ObjFlags);
|
|
}
|
|
#endif
|
|
fDist /= 2.0f;
|
|
if (fDistToCam > fDist+1.0f)
|
|
break;
|
|
fUScale *= 2.0f;
|
|
fVScale *= 2.0f;
|
|
}
|
|
|
|
D3DXMatrixIdentity(&mat);
|
|
m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
|
|
m_pd3dDevice->SetTransform(D3DTS_TEXTURE0, &mat);
|
|
m_pd3dDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
|
|
m_pd3dDevice->SetTransform(D3DTS_TEXTURE1, &mat);
|
|
m_pd3dDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU | 1);
|
|
m_RP.m_TexStages[1].TCIndex = 1;
|
|
|
|
EF_SelectTMU(0);
|
|
}
|
|
else
|
|
{
|
|
if (!m_RP.m_VPDetail)
|
|
m_RP.m_VPDetail = CVProgram::mfForName("CGVProgDetail");
|
|
if (!m_RP.m_RCDetail)
|
|
m_RP.m_RCDetail = CPShader::mfForName("CGRCDetailAtten");
|
|
if (m_RP.m_RCDetail)
|
|
m_RP.m_RCDetail->mfSet(true);
|
|
|
|
CCGVProgram_D3D *vpD3D = (CCGVProgram_D3D *)m_RP.m_VPDetail;
|
|
|
|
vpD3D->mfSet(true, NULL, VPF_DONTSETMATRICES);
|
|
vpD3D->mfSetVariables(false, NULL);
|
|
vpD3D->mfSetStateMatrices();
|
|
SCGBind *pBindScale = vpD3D->mfGetParameterBind("DetailScaling");
|
|
SCGBind *pBindTG0 = vpD3D->mfGetParameterBind("TexGen00");
|
|
SCGBind *pBindTG1 = vpD3D->mfGetParameterBind("TexGen01");
|
|
|
|
int n = CLAMP(CV_r_detailnumlayers, 1, 4);
|
|
float fUScale = rt->m_TexModificator.m_Tiling[0];
|
|
float fVScale = rt->m_TexModificator.m_Tiling[1];
|
|
if (!fUScale)
|
|
fUScale = CV_r_detailscale;
|
|
if (!fVScale)
|
|
fVScale = CV_r_detailscale;
|
|
for (i=0; i<n; i++)
|
|
{
|
|
fg.m_fMaxDist = fDist;
|
|
|
|
Vals[0] = fUScale;
|
|
Vals[1] = fVScale;
|
|
Vals[2] = 0;
|
|
Vals[3] = 0;
|
|
if (pBindScale)
|
|
vpD3D->mfParameter4f(pBindScale, Vals);
|
|
|
|
Plane plane;
|
|
|
|
#ifndef PIPE_USE_INSTANCING
|
|
FM.m_Offs = 0;
|
|
FM.mfGet4f(Vals);
|
|
if (pBindTG0)
|
|
vpD3D->mfParameter4f(pBindTG0, Vals);
|
|
|
|
FM.m_Offs = 1;
|
|
FM.mfGet4f(Vals);
|
|
if (pBindTG1)
|
|
vpD3D->mfParameter4f(pBindTG1, Vals);
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Detail Pass %d [Dist: %.3f]\n", m_RP.m_RendPass, fDist);
|
|
#endif
|
|
|
|
// Draw primitives
|
|
EF_Draw(sh, NULL);
|
|
#else
|
|
int bFogOverrided = 0;
|
|
EF_PreDraw(NULL);
|
|
if (m_FS.m_bEnable)
|
|
bFogOverrided = EF_FogCorrection(false, false);
|
|
|
|
CCObject *pSaveObj = m_RP.m_pCurObject;
|
|
CCObject *pObj = pSaveObj;
|
|
int nObj = 0;
|
|
while (true)
|
|
{
|
|
if (sfDistRender[nObj])
|
|
{
|
|
if (nObj)
|
|
{
|
|
m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj];
|
|
m_RP.m_FrameObject++;
|
|
pObj = m_RP.m_pCurObject;
|
|
}
|
|
|
|
FM.m_Offs = 0;
|
|
FM.mfGet4f(Vals);
|
|
if (pBindTG0)
|
|
vpD3D->mfParameter4f(pBindTG0, Vals);
|
|
|
|
FM.m_Offs = 1;
|
|
FM.mfGet4f(Vals);
|
|
if (pBindTG1)
|
|
vpD3D->mfParameter4f(pBindTG1, Vals);
|
|
|
|
vpD3D->mfSetVariables(true, NULL);
|
|
vpD3D->mfSetStateMatrices();
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
{
|
|
Vec3d vPos = pObj->GetTranslation();
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Detail Pass %d [Dist: %.3f] (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, fDist, pObj->m_VisId, vPos[0], vPos[1], vPos[2]);
|
|
}
|
|
#endif
|
|
|
|
{
|
|
//PROFILE_FRAME(Draw_ShaderIndexMesh);
|
|
if (m_RP.m_pRE)
|
|
m_RP.m_pRE->mfDraw(sh, NULL);
|
|
else
|
|
EF_DrawIndexedMesh(R_PRIMV_TRIANGLES);
|
|
}
|
|
}
|
|
nObj++;
|
|
if (nObj >= m_RP.m_MergedObjects.Num())
|
|
break;
|
|
}
|
|
EF_FogRestore(bFogOverrided);
|
|
if (m_RP.m_FlagsModificators & (RBMF_TCM | RBMF_TCG))
|
|
EF_CommitTexTransforms(false);
|
|
else
|
|
m_RP.m_FlagsModificators &= ~(RBMF_TCM | RBMF_TCG);
|
|
if (pSaveObj != m_RP.m_pCurObject)
|
|
{
|
|
m_RP.m_pCurObject = pSaveObj;
|
|
m_RP.m_FrameObject++;
|
|
}
|
|
#endif
|
|
|
|
fDist /= 2.0f;
|
|
if (fDistToCam > fDist+1.0f)
|
|
break;
|
|
fUScale *= 2.0f;
|
|
fVScale *= 2.0f;
|
|
}
|
|
}
|
|
CD3D9TexMan::BindNULL(0);
|
|
gRenDev->m_RP.m_pFogVolume = fb;
|
|
#ifdef PIPE_USE_INSTANCING
|
|
EF_PopMatrix();
|
|
#endif
|
|
}
|
|
|
|
// Draw fur layer passes (used in programmable pipeline shaders only)
|
|
void CD3D9Renderer::EF_DrawFurPasses(SShaderTechnique *hs, SShader *ef, int nStart, int nEnd, EShaderPassType eShPass)
|
|
{
|
|
SShaderPassHW *slw;
|
|
int i;
|
|
|
|
CVProgram *curVP = NULL;
|
|
CVProgram *newVP;
|
|
|
|
m_RP.m_FlagsPerFlush |= RBSI_FURPASS;
|
|
|
|
PROFILE_FRAME(DrawShader_FurPasses);
|
|
|
|
slw = &hs->m_Passes[nStart];
|
|
if (slw->m_TUnits.Num() < 3)
|
|
return;
|
|
CFurMap *fm = (CFurMap *)slw->m_TUnits[2].m_TexPic->m_pFuncMap;
|
|
CFurNormalMap *fnm = (CFurNormalMap *)slw->m_TUnits[0].m_TexPic->m_pFuncMap;
|
|
if (!fm || !fnm)
|
|
return;
|
|
|
|
SParamComp_User user;
|
|
user.m_Name = "furlength";
|
|
float fFurLength = user.mfGet();
|
|
fFurLength = CLAMP(fFurLength, 0.001f, 4.0f);
|
|
|
|
user.m_Name = "furnumlayers";
|
|
int nLayers = (int)user.mfGet();
|
|
nLayers = CLAMP(nLayers, 1, 60);
|
|
fm->Update(nLayers);
|
|
|
|
bool bFurSimulation = (eShPass == eSHP_SimulatedFur);
|
|
|
|
fnm->Update(eShPass, iTimer->GetFrameTime(), slw, bFurSimulation);
|
|
|
|
m_RP.m_CurrPass = slw;
|
|
m_RP.m_FlagsModificators = (m_RP.m_FlagsModificators & ~7) | (slw->m_Flags & 3);
|
|
|
|
EF_SetVertexStreams(slw->m_Pointers, 1);
|
|
|
|
// Set all textures and HW TexGen modes for the current pass (ShadeLayer)
|
|
newVP = slw->m_VProgram;
|
|
if (newVP)
|
|
m_RP.m_FlagsPerFlush |= RBSI_USEVP;
|
|
if (slw->mfSetTextures())
|
|
{
|
|
fnm->Bind(0);
|
|
|
|
// Set vertex program for the current pass if needed
|
|
if (newVP != curVP)
|
|
{
|
|
if (newVP)
|
|
{
|
|
curVP = newVP;
|
|
curVP->mfSet(true, slw, VPF_DONTSETMATRICES);
|
|
}
|
|
else
|
|
curVP = NULL;
|
|
}
|
|
|
|
EF_ApplyMatrixOps(slw->m_MatrixOps, true);
|
|
|
|
if (curVP)
|
|
{
|
|
#ifndef PIPE_USE_INSTANCING
|
|
curVP->mfSetStateMatrices();
|
|
#endif
|
|
curVP->mfSetVariables(false, &slw->m_VPParamsNoObj);
|
|
}
|
|
else
|
|
{
|
|
m_RP.m_CurrentVLights = 0;
|
|
m_RP.m_PersFlags &= ~RBPF_VSNEEDSET;
|
|
}
|
|
|
|
// Set Pixel shaders and Register combiners for the current pass
|
|
if (slw->m_FShader)
|
|
slw->m_FShader->mfSet(true, slw);
|
|
else
|
|
m_RP.m_PersFlags &= ~RBPF_PS1NEEDSET;
|
|
|
|
if (m_RP.m_RendPass || (m_RP.m_ObjFlags & FOB_LIGHTPASS))
|
|
EF_SetState(slw->m_SecondRenderState);
|
|
else
|
|
EF_SetState(slw->m_RenderState);
|
|
#ifndef PIPE_USE_INSTANCING
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Shadow Pass %d [%d Samples]\n", m_RP.m_RendPass, nDeltaCasters);
|
|
#endif
|
|
|
|
EF_Scissor(false, 0, 0, 0, 0);
|
|
|
|
EF_Draw(ef, slw);
|
|
|
|
m_RP.m_RendPass++;
|
|
|
|
#else //PIPE_USE_INSTANCING
|
|
m_RP.m_RendPass++;
|
|
|
|
int bFogOverrided = 0;
|
|
// Unlock all VB (if needed) and set current streams
|
|
EF_PreDraw(slw);
|
|
if (m_FS.m_bEnable)
|
|
bFogOverrided = EF_FogCorrection(false, false);
|
|
|
|
int nObj = 0;
|
|
CCObject *pSaveObj = m_RP.m_pCurObject;
|
|
CCObject *pObj = pSaveObj;
|
|
while (true)
|
|
{
|
|
if (nObj)
|
|
{
|
|
m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj];
|
|
m_RP.m_FrameObject++;
|
|
pObj = m_RP.m_pCurObject;
|
|
|
|
if (!curVP)
|
|
{
|
|
EF_SetObjectTransform(pObj, ef, pObj->m_ObjFlags);
|
|
m_RP.m_CurrentVLights = 0;
|
|
|
|
if (m_RP.m_FrameGTC == m_RP.m_Frame)
|
|
{
|
|
for (int nt=0; nt<gRenDev->m_TexMan->m_nCurStages; nt++)
|
|
{
|
|
if (m_RP.m_pGTC[nt])
|
|
{
|
|
EF_SelectTMU(nt);
|
|
m_RP.m_pGTC[nt]->mfSet(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
EF_Scissor(false, 0, 0, 0, 0);
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
{
|
|
Vec3d vPos = pObj->GetTranslation();
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Fur Pass %d (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, pObj->m_VisId, vPos[0], vPos[1], vPos[2]);
|
|
}
|
|
#endif
|
|
|
|
if (curVP)
|
|
{
|
|
curVP->mfSetStateMatrices();
|
|
curVP->mfSetVariables(true, &slw->m_VPParamsObj);
|
|
}
|
|
if (slw->m_FShader)
|
|
slw->m_FShader->mfSetVariables(true, slw->m_CGFSParamsObj);
|
|
else
|
|
{
|
|
if (slw->m_RGBComps && slw->m_RGBComps->m_Comps[0] && slw->m_RGBComps->m_Comps[0]->m_bDependsOnObject)
|
|
{
|
|
float *vals = slw->m_RGBComps->mfGet();
|
|
UCol color;
|
|
color.bcolor[2] = (byte)(vals[0] * 255.0f);
|
|
color.bcolor[1] = (byte)(vals[1] * 255.0f);
|
|
color.bcolor[0] = (byte)(vals[2] * 255.0f);
|
|
color.bcolor[3] = (byte)(vals[3] * 255.0f);
|
|
m_RP.m_NeedGlobalColor = color;
|
|
}
|
|
EF_CommitTexStageState();
|
|
}
|
|
CCGVProgram_D3D *vpD3D = (CCGVProgram_D3D *)curVP;
|
|
vec4_t v;
|
|
SParamComp_OSLightPos comp;
|
|
m_RP.m_pCurLight = m_RP.m_pActiveDLights[0];
|
|
comp.mfGet4f(v);
|
|
vpD3D->mfParameter4f("LightPos", v);
|
|
float fLodBias = -0.5f;
|
|
m_pd3dDevice->SetSamplerState(2, D3DSAMP_MIPMAPLODBIAS, *((LPDWORD)(&fLodBias)));
|
|
CREOcLeaf *re = (CREOcLeaf *)m_RP.m_pRE;
|
|
CLeafBuffer *lb = re->m_pBuffer;
|
|
v[2] = -lb->m_fMinU;
|
|
v[0] = 1.0f / (lb->m_fMaxU + v[2]);
|
|
v[3] = -lb->m_fMinV;
|
|
v[1] = 1.0f / (lb->m_fMaxV + v[3]);
|
|
vpD3D->mfParameter4f("ScaleBiasTC", v);
|
|
|
|
for (i=0; i<nLayers; i++)
|
|
{
|
|
m_RP.m_StatNumPasses++;
|
|
float layer = float(i+1) / nLayers;
|
|
float length = fFurLength * layer;
|
|
float scale = -fFurLength * (1.0f*layer*layer + 0.4f*layer);
|
|
fm->Bind(layer, 2);
|
|
float vModifiers[4];
|
|
vModifiers[0] = length;
|
|
vModifiers[1] = 0.0f;
|
|
vModifiers[2] = 0.0f;
|
|
vModifiers[3] = scale;
|
|
vpD3D->mfParameter4f("Modifiers", vModifiers);
|
|
|
|
{
|
|
//PROFILE_FRAME(Draw_ShaderIndexMesh);
|
|
if (m_RP.m_pRE)
|
|
m_RP.m_pRE->mfDraw(ef, slw);
|
|
else
|
|
EF_DrawIndexedMesh(R_PRIMV_TRIANGLES);
|
|
}
|
|
}
|
|
m_pd3dDevice->SetSamplerState(2, D3DSAMP_MIPMAPLODBIAS, 0);
|
|
nObj++;
|
|
if (nObj >= m_RP.m_MergedObjects.Num())
|
|
break;
|
|
}
|
|
EF_FogRestore(bFogOverrided);
|
|
if (!CVProgram::m_LastVP)
|
|
{
|
|
if (m_RP.m_FlagsModificators & (RBMF_TCM | RBMF_TCG))
|
|
EF_CommitTexTransforms(false);
|
|
}
|
|
else
|
|
m_RP.m_FlagsModificators &= ~(RBMF_TCM | RBMF_TCG);
|
|
if (pSaveObj != m_RP.m_pCurObject)
|
|
{
|
|
m_RP.m_pCurObject = pSaveObj;
|
|
m_RP.m_FrameObject++;
|
|
if (!curVP)
|
|
EF_SetObjectTransform(pSaveObj, ef, pSaveObj->m_ObjFlags);
|
|
}
|
|
#endif
|
|
slw->mfResetTextures();
|
|
EF_ApplyMatrixOps(slw->m_MatrixOps, false);
|
|
}
|
|
m_RP.m_pCurLight = NULL;
|
|
}
|
|
|
|
struct SShadowLight
|
|
{
|
|
list2<ShadowMapLightSourceInstance> *pSmLI;
|
|
CDLight *pDL;
|
|
};
|
|
|
|
static bool sbHasDot3LM;
|
|
static _inline int Compare(SShadowLight &a, SShadowLight &b)
|
|
{
|
|
if (a.pSmLI->Count() > b.pSmLI->Count())
|
|
return -1;
|
|
if (a.pSmLI->Count() < b.pSmLI->Count())
|
|
return 1;
|
|
if (sbHasDot3LM)
|
|
{
|
|
if ((a.pDL->m_Flags & DLF_LM) < (b.pDL->m_Flags & DLF_LM))
|
|
return -1;
|
|
if ((a.pDL->m_Flags & DLF_LM) > (b.pDL->m_Flags & DLF_LM))
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#include <IEntityRenderState.h>
|
|
|
|
int CD3D9Renderer::EF_DrawMultiShadowPasses(SShaderTechnique *hs, SShader *ef, int nStart)
|
|
{
|
|
int i, j;
|
|
int nStartAmb = -1;
|
|
int nEndAmb = -1;
|
|
int nStartShadow = -1;
|
|
int nEndShadow = -1;
|
|
int nStartLight = -1;
|
|
int nEndLight = -1;
|
|
int nEnd = -1;
|
|
nStart++;
|
|
if (m_RP.m_pCurObject->m_ObjFlags & FOB_SELECTED)
|
|
{
|
|
int nnn = 0;
|
|
}
|
|
bool bMultiLights = false;
|
|
for (i=nStart; i<hs->m_Passes.Num(); i++)
|
|
{
|
|
switch (hs->m_Passes[i].m_ePassType)
|
|
{
|
|
case eSHP_MultiLights:
|
|
bMultiLights = true;
|
|
case eSHP_SpecularLight:
|
|
case eSHP_DiffuseLight:
|
|
case eSHP_Light:
|
|
if (nStartLight < 0)
|
|
nStartLight = i;
|
|
else
|
|
nEndLight = i;
|
|
break;
|
|
case eSHP_General:
|
|
if (nStartAmb < 0)
|
|
nStartAmb = i;
|
|
else
|
|
nEndAmb = i;
|
|
break;
|
|
case eSHP_Shadow:
|
|
if (nStartShadow < 0)
|
|
nStartShadow = i;
|
|
else
|
|
nEndShadow = i;
|
|
break;
|
|
default:
|
|
nEnd = i;
|
|
}
|
|
}
|
|
if (nEnd < 0)
|
|
nEnd = i-1;
|
|
|
|
list2<ShadowMapLightSourceInstance> * lsources = (list2<ShadowMapLightSourceInstance>*)m_RP.m_pCurObject->m_pShadowCasters;
|
|
if (!lsources || !lsources->Count())
|
|
return nEnd;
|
|
int nCaster = 0;
|
|
/*if (ef->m_eSort != eS_TerrainShadowPass)
|
|
{
|
|
if (!CRenderer::CV_r_selfshadow || !(m_Features & RFT_SHADOWMAP_SELFSHADOW))
|
|
{
|
|
if( lsources->Get(0)->m_pLS->GetShadowMapFrustum()->pOwner == lsources->Get(0)->m_pReceiver &&
|
|
!(lsources->Get(0)->m_pLS->GetShadowMapFrustum()->dwFlags & SMFF_ACTIVE_SHADOW_MAP))
|
|
nCaster++; // skip self shadowing pass
|
|
}
|
|
}*/
|
|
|
|
if (nEndLight < 0)
|
|
nEndLight = nStartLight;
|
|
if (nEndShadow < 0)
|
|
nEndShadow = nStartShadow;
|
|
if (nEndAmb < 0)
|
|
nEndAmb = nStartAmb;
|
|
assert(nStartShadow>=0);
|
|
assert(nStartLight>=0);
|
|
|
|
int nFrustrums = 0;
|
|
list2<ShadowMapLightSourceInstance> SmLI[16];
|
|
SShadowLight SL[16];
|
|
int nLights = m_RP.m_NumActiveDLights;
|
|
bool bHasDot3LM = m_RP.m_pShaderResources && m_RP.m_pCurObject->m_nLMDirId;
|
|
|
|
for (i=0; i<nLights; i++)
|
|
{
|
|
SL[i].pSmLI = &SmLI[i];
|
|
SL[i].pDL = m_RP.m_pActiveDLights[i];
|
|
int nLightID = SL[i].pDL->m_Id;
|
|
for (j=nCaster; j<lsources->Count(); j++)
|
|
{
|
|
ShadowMapLightSourceInstance *Inst = lsources->Get(j);
|
|
if (Inst->m_pLS->nDLightId == nLightID)
|
|
SmLI[i].Add(*Inst);
|
|
}
|
|
}
|
|
sbHasDot3LM = bHasDot3LM;
|
|
::Sort(&SL[0], nLights);
|
|
int nStartLightWithoutSC = -1;
|
|
m_RP.m_FlagsPerFlush &= ~RBSI_ALPHATEST;
|
|
for (i=0; i<nLights; i++)
|
|
{
|
|
if (SL[i].pSmLI->Count())
|
|
{
|
|
m_RP.m_pCurObject->m_pShadowCasters = SL[i].pSmLI;
|
|
m_RP.m_pActiveDLights[0] = SL[i].pDL;
|
|
m_RP.m_NumActiveDLights = 1;
|
|
m_RP.m_pCurLight = SL[i].pDL;
|
|
// Draw shadows in back-buffer alpha-channel
|
|
EF_DrawShadowPasses(hs, ef, nStartShadow, nEndShadow, true);
|
|
if (bHasDot3LM && (SL[i].pDL->m_Flags & DLF_LM))
|
|
{ // Shadow maps on light-map case
|
|
// Specular pass
|
|
if (bMultiLights)
|
|
EF_DrawLightPasses_PS30(hs, ef, nStartLight, nEndLight, true);
|
|
else
|
|
EF_DrawLightPasses(hs, ef, nStartLight, nEndLight, true);
|
|
// LM pass
|
|
EF_DrawGeneralPasses(hs, ef, false, nStartAmb, nEndAmb, true);
|
|
}
|
|
else
|
|
{
|
|
// Shadow maps on dynamically lighted object case
|
|
if (bMultiLights)
|
|
EF_DrawLightPasses_PS30(hs, ef, nStartLight, nEndLight, true);
|
|
else
|
|
EF_DrawLightPasses(hs, ef, nStartLight, nEndLight, true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (nStartLightWithoutSC < 0)
|
|
nStartLightWithoutSC = i;
|
|
m_RP.m_pActiveDLights[i-nStartLightWithoutSC] = SL[i].pDL;
|
|
}
|
|
}
|
|
if (nStartLightWithoutSC >= 0)
|
|
{
|
|
// Draw light sources without shadow-casters
|
|
m_RP.m_NumActiveDLights = nLights-nStartLightWithoutSC;
|
|
EF_DrawLightPasses(hs, ef, nStartLight, nEndLight, false);
|
|
}
|
|
m_RP.m_pCurObject->m_pShadowCasters = lsources;
|
|
for (i=0; i<m_RP.m_NumActiveDLights; i++)
|
|
{
|
|
m_RP.m_pActiveDLights[i] = SL[i].pDL;
|
|
}
|
|
m_RP.m_NumActiveDLights = nLights;
|
|
|
|
return nEnd;
|
|
}
|
|
|
|
// Draw shadow map passes (used in programmable pipeline shaders only)
|
|
void CD3D9Renderer::EF_DrawShadowPasses(SShaderTechnique *hs, SShader *ef, int nStart, int nEnd, bool bDstAlpha)
|
|
{
|
|
SShaderPassHW *slw;
|
|
int i;
|
|
|
|
if ((m_RP.m_ObjFlags & FOB_LIGHTPASS) && (ef->m_Flags & EF_USELIGHTS))
|
|
return;
|
|
|
|
m_RP.m_nCurLight = 0;
|
|
CVProgram *curVP = NULL;
|
|
CVProgram *newVP;
|
|
|
|
list2<ShadowMapLightSourceInstance> * lsources = (list2<ShadowMapLightSourceInstance>*)m_RP.m_pCurObject->m_pShadowCasters;
|
|
if (!lsources || !lsources->Count())
|
|
return;
|
|
m_RP.m_FlagsPerFlush |= RBSI_SHADOWPASS;
|
|
|
|
PROFILE_FRAME(DrawShader_ShadowPasses);
|
|
|
|
CDLight *pSaveLight = m_RP.m_pCurLight;
|
|
|
|
int nCaster = 0;
|
|
if (ef->m_eSort != eS_TerrainShadowPass)
|
|
{
|
|
if (!CRenderer::CV_r_selfshadow || !(m_Features & RFT_SHADOWMAP_SELFSHADOW))
|
|
{
|
|
if( lsources->Get(0)->m_pLS->GetShadowMapFrustum()->pOwner == lsources->Get(0)->m_pReceiver &&
|
|
!(lsources->Get(0)->m_pLS->GetShadowMapFrustum()->dwFlags & SMFF_ACTIVE_SHADOW_MAP))
|
|
nCaster++; // skip self shadowing pass
|
|
}
|
|
}
|
|
int nCasters = lsources->Count();
|
|
int nDeltaCasters = 1;
|
|
|
|
int nPass = 0;
|
|
for (; nCaster<nCasters; nCaster+=nDeltaCasters)
|
|
{
|
|
m_RP.m_nCurStartCaster = nCaster;
|
|
m_RP.m_StatNumPasses++;
|
|
slw = &hs->m_Passes[nStart];
|
|
for (i=nStart; i<=nEnd; i++, slw++)
|
|
{
|
|
int msk;
|
|
bool bUseLight = false;
|
|
if (msk = (slw->m_LightFlags & DLF_LIGHTTYPE_MASK))
|
|
{
|
|
bUseLight = true;
|
|
if (!m_RP.m_NumActiveDLights)
|
|
return;
|
|
m_RP.m_pCurLight = m_RP.m_pActiveDLights[0];
|
|
m_RP.m_nCurLight = m_RP.m_pCurLight->m_Id;
|
|
if (!(msk & (m_RP.m_pCurLight->m_Flags & DLF_LIGHTTYPE_MASK)))
|
|
continue;
|
|
}
|
|
if (slw->m_LMFlags & LMF_SAMPLES)
|
|
{
|
|
if (slw->m_LMFlags & LMF_4SAMPLES)
|
|
{
|
|
if (nCasters-nCaster < 4)
|
|
continue;
|
|
nDeltaCasters = 4;
|
|
}
|
|
else
|
|
if (slw->m_LMFlags & LMF_3SAMPLES)
|
|
{
|
|
if (nCasters-nCaster < 3)
|
|
continue;
|
|
nDeltaCasters = 3;
|
|
}
|
|
else
|
|
if (slw->m_LMFlags & LMF_2SAMPLES)
|
|
{
|
|
if (nCasters-nCaster < 2)
|
|
continue;
|
|
nDeltaCasters = 2;
|
|
}
|
|
else
|
|
if (slw->m_LMFlags & LMF_1SAMPLES)
|
|
{
|
|
if (nCasters-nCaster < 1)
|
|
continue;
|
|
nDeltaCasters = 1;
|
|
}
|
|
}
|
|
m_RP.m_CurrPass = slw;
|
|
|
|
m_RP.m_FlagsModificators = (m_RP.m_FlagsModificators & ~7) | (slw->m_Flags & 3);
|
|
|
|
EF_Eval_TexGen(slw);
|
|
EF_Eval_RGBAGen(slw);
|
|
EF_SetVertexStreams(slw->m_Pointers, 1);
|
|
|
|
// Set all textures and HW TexGen modes for the current pass (ShadeLayer)
|
|
newVP = slw->m_VProgram;
|
|
if (newVP)
|
|
m_RP.m_FlagsPerFlush |= RBSI_USEVP;
|
|
if (slw->mfSetTextures())
|
|
{
|
|
// Set vertex program for the current pass if needed
|
|
if (newVP != curVP)
|
|
{
|
|
if (newVP)
|
|
{
|
|
curVP = newVP;
|
|
curVP->mfSet(true, slw, VPF_DONTSETMATRICES);
|
|
}
|
|
else
|
|
curVP = NULL;
|
|
}
|
|
|
|
EF_ApplyMatrixOps(slw->m_MatrixOps, true);
|
|
|
|
if (curVP)
|
|
{
|
|
#ifndef PIPE_USE_INSTANCING
|
|
curVP->mfSetStateMatrices();
|
|
#endif
|
|
curVP->mfSetVariables(false, &slw->m_VPParamsNoObj);
|
|
}
|
|
else
|
|
{
|
|
m_RP.m_CurrentVLights = 0;
|
|
m_RP.m_PersFlags &= ~RBPF_VSNEEDSET;
|
|
}
|
|
|
|
// Set Pixel shaders and Register combiners for the current pass
|
|
if (slw->m_FShader)
|
|
slw->m_FShader->mfSet(true, slw);
|
|
else
|
|
m_RP.m_PersFlags &= ~RBPF_PS1NEEDSET;
|
|
|
|
int State;
|
|
if (m_RP.m_RendPass || (m_RP.m_ObjFlags & FOB_LIGHTPASS))
|
|
State = slw->m_SecondRenderState;
|
|
else
|
|
State = slw->m_RenderState;
|
|
if (bDstAlpha)
|
|
{
|
|
if (nPass)
|
|
State = (State & ~GS_BLEND_MASK) | GS_BLSRC_ONE | GS_BLDST_ONE;
|
|
nPass++;
|
|
}
|
|
EF_SetState(State);
|
|
|
|
#ifndef PIPE_USE_INSTANCING
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Shadow Pass %d [%d Samples]\n", m_RP.m_RendPass, nDeltaCasters);
|
|
#endif
|
|
|
|
EF_Scissor(false, 0, 0, 0, 0);
|
|
|
|
EF_Draw(ef, slw);
|
|
|
|
m_RP.m_RendPass++;
|
|
|
|
#else //PIPE_USE_INSTANCING
|
|
m_RP.m_RendPass++;
|
|
|
|
// Unlock all VB (if needed) and set current streams
|
|
EF_PreDraw(slw);
|
|
|
|
int bFogOverrided = 0;
|
|
bool bFogDisable = (curVP && (curVP->m_Flags & VPFI_NOFOG));
|
|
bool bFogVP = (m_RP.m_PersFlags & RBPF_HDR) || (curVP && (curVP->m_Flags & VPFI_VS30ONLY));
|
|
bFogOverrided = EF_FogCorrection(bFogDisable, bFogVP);
|
|
|
|
int nObj = 0;
|
|
CCObject *pSaveObj = m_RP.m_pCurObject;
|
|
CCObject *pObj = pSaveObj;
|
|
while (true)
|
|
{
|
|
if (nObj)
|
|
{
|
|
m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj];
|
|
m_RP.m_FrameObject++;
|
|
pObj = m_RP.m_pCurObject;
|
|
|
|
if (!curVP)
|
|
{
|
|
EF_SetObjectTransform(pObj, ef, pObj->m_ObjFlags);
|
|
m_RP.m_CurrentVLights = 0;
|
|
|
|
if (m_RP.m_FrameGTC == m_RP.m_Frame)
|
|
{
|
|
for (int nt=0; nt<gRenDev->m_TexMan->m_nCurStages; nt++)
|
|
{
|
|
if (m_RP.m_pGTC[nt])
|
|
{
|
|
EF_SelectTMU(nt);
|
|
m_RP.m_pGTC[nt]->mfSet(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
EF_Scissor(false, 0, 0, 0, 0);
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
{
|
|
Vec3d vPos = pObj->GetTranslation();
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Shadow Pass %d [%d Samples] (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, nDeltaCasters, pObj->m_VisId, vPos[0], vPos[1], vPos[2]);
|
|
}
|
|
#endif
|
|
|
|
if (curVP)
|
|
{
|
|
curVP->mfSetStateMatrices();
|
|
curVP->mfSetVariables(true, &slw->m_VPParamsObj);
|
|
}
|
|
if (slw->m_FShader)
|
|
slw->m_FShader->mfSetVariables(true, slw->m_CGFSParamsObj);
|
|
else
|
|
{
|
|
if (slw->m_RGBComps && slw->m_RGBComps->m_Comps[0] && slw->m_RGBComps->m_Comps[0]->m_bDependsOnObject)
|
|
{
|
|
float *vals = slw->m_RGBComps->mfGet();
|
|
UCol color;
|
|
color.bcolor[2] = (byte)(vals[0] * 255.0f);
|
|
color.bcolor[1] = (byte)(vals[1] * 255.0f);
|
|
color.bcolor[0] = (byte)(vals[2] * 255.0f);
|
|
color.bcolor[3] = (byte)(vals[3] * 255.0f);
|
|
m_RP.m_NeedGlobalColor = color;
|
|
}
|
|
EF_CommitTexStageState();
|
|
}
|
|
|
|
{
|
|
//PROFILE_FRAME(Draw_ShaderIndexMesh);
|
|
if (m_RP.m_pRE)
|
|
m_RP.m_pRE->mfDraw(ef, slw);
|
|
else
|
|
EF_DrawIndexedMesh(R_PRIMV_TRIANGLES);
|
|
}
|
|
nObj++;
|
|
if (nObj >= m_RP.m_MergedObjects.Num())
|
|
break;
|
|
}
|
|
EF_FogRestore(bFogOverrided);
|
|
if (!CVProgram::m_LastVP)
|
|
{
|
|
if (m_RP.m_FlagsModificators & (RBMF_TCM | RBMF_TCG))
|
|
EF_CommitTexTransforms(false);
|
|
}
|
|
else
|
|
m_RP.m_FlagsModificators &= ~(RBMF_TCM | RBMF_TCG);
|
|
if (pSaveObj != m_RP.m_pCurObject)
|
|
{
|
|
m_RP.m_pCurObject = pSaveObj;
|
|
m_RP.m_FrameObject++;
|
|
if (!curVP)
|
|
EF_SetObjectTransform(pSaveObj, ef, pSaveObj->m_ObjFlags);
|
|
}
|
|
#endif
|
|
}
|
|
slw->mfResetTextures();
|
|
EF_ApplyMatrixOps(slw->m_MatrixOps, false);
|
|
break;
|
|
}
|
|
}
|
|
m_RP.m_nCurStartCaster = 0;
|
|
|
|
m_RP.m_pCurLight = pSaveLight;
|
|
if (m_RP.m_pCurLight)
|
|
m_RP.m_nCurLight = m_RP.m_pCurLight->m_Id;
|
|
}
|
|
|
|
#define INST_PARAM_SIZE 4*sizeof(float)
|
|
|
|
void CD3D9Renderer::EF_DrawInstances(SShader *ef, SShaderPassHW *slw, int nCurInst, int nLastInst, int nUsage, byte bUsage[], int nInstMask)
|
|
{
|
|
int i;
|
|
|
|
if (!nCurInst)
|
|
{
|
|
// Set the stream 3 to be per instance data and iterate once per instance
|
|
m_pd3dDevice->SetStreamSourceFreq(3, 1 | D3DSTREAMSOURCE_INSTANCEDATA);
|
|
int nCompared = 0;
|
|
EF_PreDraw(slw, false);
|
|
int StreamMask = m_RP.m_FlagsModificators&7;
|
|
SVertexDeclaration *vd;
|
|
for (i=0; i<m_RP.m_CustomVD.Num(); i++)
|
|
{
|
|
vd = m_RP.m_CustomVD[i];
|
|
if (vd->StreamMask == StreamMask && vd->VertFormat == m_RP.m_CurVFormat && vd->InstMask == nInstMask)
|
|
break;
|
|
}
|
|
if (i == m_RP.m_CustomVD.Num())
|
|
{
|
|
vd = new SVertexDeclaration;
|
|
m_RP.m_CustomVD.AddElem(vd);
|
|
vd->StreamMask = StreamMask;
|
|
vd->VertFormat = m_RP.m_CurVFormat;
|
|
vd->InstMask = nInstMask;
|
|
vd->m_pDeclaration = NULL;
|
|
for (i=0; i<m_RP.m_D3DFixedPipeline[StreamMask][m_RP.m_CurVFormat].m_Declaration.Num()-1; i++)
|
|
{
|
|
vd->m_Declaration.AddElem(m_RP.m_D3DFixedPipeline[StreamMask][m_RP.m_CurVFormat].m_Declaration[i]);
|
|
}
|
|
D3DVERTEXELEMENT9 ve;
|
|
ve.Stream = 3;
|
|
ve.Type = D3DDECLTYPE_FLOAT4;
|
|
ve.Method = D3DDECLMETHOD_DEFAULT;
|
|
ve.Usage = D3DDECLUSAGE_TEXCOORD;
|
|
for (i=0; i<nUsage; i++)
|
|
{
|
|
ve.Offset = i*INST_PARAM_SIZE;
|
|
ve.UsageIndex = bUsage[i];
|
|
vd->m_Declaration.AddElem(ve);
|
|
}
|
|
ve.Stream = 0xff;
|
|
ve.Type = D3DDECLTYPE_UNUSED;
|
|
ve.Usage = 0;
|
|
ve.UsageIndex = 0;
|
|
ve.Offset = 0;
|
|
vd->m_Declaration.AddElem(ve);
|
|
}
|
|
HRESULT hr;
|
|
if (!vd->m_pDeclaration)
|
|
{
|
|
hr = m_pd3dDevice->CreateVertexDeclaration(&vd->m_Declaration[0], &vd->m_pDeclaration);
|
|
assert (hr == S_OK);
|
|
}
|
|
if (m_pLastVDeclaration != vd->m_pDeclaration)
|
|
{
|
|
m_pLastVDeclaration = vd->m_pDeclaration;
|
|
hr = m_pd3dDevice->SetVertexDeclaration(vd->m_pDeclaration);
|
|
assert (hr == S_OK);
|
|
}
|
|
}
|
|
{
|
|
//PROFILE_FRAME(Draw_ShaderIndexMesh);
|
|
int nPolys = m_nPolygons;
|
|
if (m_RP.m_pRE)
|
|
m_RP.m_pRE->mfDraw(ef, slw);
|
|
else
|
|
EF_DrawIndexedMesh(R_PRIMV_TRIANGLES);
|
|
int nPolysPerInst = m_nPolygons - nPolys;
|
|
m_nPolygons += nPolysPerInst*(nLastInst-nCurInst);
|
|
}
|
|
}
|
|
|
|
void CD3D9Renderer::EF_DrawGeometryInstancing_VS30(SShader *ef, SShaderPassHW *slw, CVProgram *curVP)
|
|
{
|
|
PROFILE_FRAME(DrawShader_GeometryInstancing_VS30);
|
|
|
|
int i, j, n;
|
|
CCGVProgram_D3D *vp = (CCGVProgram_D3D *)curVP;
|
|
int nOffs;
|
|
int nUsage = 1;
|
|
byte bUsage[16];
|
|
Matrix44 m;
|
|
int nCurInst = 0;
|
|
SCGBind bind;
|
|
bind.m_dwBind = 65536;
|
|
bind.m_nBindComponents = 4;
|
|
bind.m_dwFrameCreated = vp->m_dwFrame;
|
|
mathMatrixTranspose(m.GetData(), m_CameraProjMatrix.GetData(), g_CpuFlags);
|
|
vp->mfParameter(&bind, m.GetData(), 4);
|
|
m_RP.m_RotatedMergedObjects.SetUse(0);
|
|
m_RP.m_NonRotatedMergedObjects.SetUse(0);
|
|
int nSimple = 0;
|
|
for (i=0; i<m_RP.m_MergedObjects.Num(); i++)
|
|
{
|
|
CCObject *pObj = m_RP.m_MergedObjects[i];
|
|
if (pObj->m_ObjFlags & FOB_TRANS_ROTATE)
|
|
m_RP.m_RotatedMergedObjects.AddElem(pObj);
|
|
else
|
|
m_RP.m_NonRotatedMergedObjects.AddElem(pObj);
|
|
}
|
|
if (m_RP.m_NonRotatedMergedObjects.Num())
|
|
{
|
|
memset(bUsage, 0, sizeof(bUsage));
|
|
bUsage[0] = 1;
|
|
int nInstMask = 0x2;
|
|
for (j=0; j<vp->m_Params_Inst.Num(); j++)
|
|
{
|
|
bUsage[nUsage] = nUsage+1;
|
|
nInstMask |= 1<<(nUsage+1);
|
|
nUsage++;
|
|
}
|
|
while (nCurInst < m_RP.m_NonRotatedMergedObjects.Num())
|
|
{
|
|
int nLastInst = m_RP.m_NonRotatedMergedObjects.Num() - 1;
|
|
if ((nLastInst-nCurInst+1)*nUsage >= MAX_HWINST_PARAMS)
|
|
nLastInst = nCurInst+(MAX_HWINST_PARAMS/nUsage)-1;
|
|
byte *data = (byte *)m_RP.m_VB_Inst->Lock((nLastInst-nCurInst+1)*nUsage*INST_PARAM_SIZE, nOffs);
|
|
CCObject *curObj = m_RP.m_pCurObject;
|
|
n = 0;
|
|
// Fill the stream 3 for per-instance data
|
|
for (i=nCurInst; i<=nLastInst; i++)
|
|
{
|
|
CCObject *pObj = m_RP.m_NonRotatedMergedObjects[i];
|
|
|
|
/*if (i != nLastInst)
|
|
{
|
|
CCObject *pObj = m_RP.m_NonRotatedMergedObjects[i+1];
|
|
cryPrefetchNTSSE(pObj->m_Matrix.GetData());
|
|
}*/
|
|
|
|
float *fParm = (float *)&data[n*nUsage*INST_PARAM_SIZE];
|
|
n++;
|
|
float *fSrc = pObj->m_Matrix.GetData();
|
|
fParm[0] = fSrc[12]; fParm[1] = fSrc[13]; fParm[2] = fSrc[14]; fParm[3] = fSrc[0];
|
|
fParm += 4;
|
|
|
|
//mathMatrixTranspose((float *)&data[nOffset], m_RP.m_MergedObjects[i]->GetVPMatrix().GetData(), g_CpuFlags);
|
|
//memcpy(&data[n*nUsage*4*sizeof(float)], pObj->GetVPMatrix().GetData(), 4*4*sizeof(float));
|
|
m_RP.m_pCurObject = pObj;
|
|
m_RP.m_FrameObject++;
|
|
for (j=0; j<vp->m_Params_Inst.Num(); j++)
|
|
{
|
|
float *v = vp->m_Params_Inst[j].mfGet();
|
|
fParm[0] = v[0];
|
|
fParm[1] = v[1];
|
|
fParm[2] = v[2];
|
|
fParm[3] = v[3];
|
|
|
|
fParm += 4;
|
|
}
|
|
}
|
|
m_RP.m_pCurObject = curObj;
|
|
m_RP.m_VB_Inst->Unlock();
|
|
|
|
// Set the first stream to be the indexed data and render N instances
|
|
m_pd3dDevice->SetStreamSourceFreq(0, n | D3DSTREAMSOURCE_INDEXEDDATA);
|
|
m_RP.m_VB_Inst->Bind(m_pd3dDevice, 3, nOffs, nUsage*INST_PARAM_SIZE);
|
|
|
|
EF_DrawInstances(ef, slw, nCurInst, nLastInst, nUsage, bUsage, nInstMask);
|
|
nCurInst = nLastInst+1;
|
|
}
|
|
}
|
|
if (m_RP.m_RotatedMergedObjects.Num())
|
|
{
|
|
int nFlags = VPF_DONTSETMATRICES | VPF_INSTANCING_ROTATE;
|
|
curVP->mfSet(true, slw, nFlags);
|
|
|
|
nUsage = 4;
|
|
memset(bUsage, 0, sizeof(bUsage));
|
|
bUsage[0] = 1;
|
|
bUsage[1] = 2;
|
|
bUsage[2] = 3;
|
|
bUsage[3] = 4;
|
|
int nInstMask = 0x1e;
|
|
for (j=0; j<vp->m_Params_Inst.Num(); j++)
|
|
{
|
|
bUsage[nUsage] = nUsage+1;
|
|
nInstMask |= 1<<(nUsage+1);
|
|
nUsage++;
|
|
}
|
|
Matrix44 m;
|
|
int nCurInst = 0;
|
|
SCGBind bind;
|
|
while (nCurInst < m_RP.m_RotatedMergedObjects.Num())
|
|
{
|
|
int nLastInst = m_RP.m_RotatedMergedObjects.Num() - 1;
|
|
if ((nLastInst-nCurInst+1)*nUsage >= MAX_HWINST_PARAMS)
|
|
nLastInst = nCurInst+(MAX_HWINST_PARAMS/nUsage)-1;
|
|
byte *data = (byte *)m_RP.m_VB_Inst->Lock((nLastInst-nCurInst+1)*nUsage*INST_PARAM_SIZE, nOffs);
|
|
CCObject *curObj = m_RP.m_pCurObject;
|
|
n = 0;
|
|
// Fill the stream 3 for per-instance data
|
|
for (i=nCurInst; i<=nLastInst; i++)
|
|
{
|
|
CCObject *pObj = m_RP.m_RotatedMergedObjects[i];
|
|
|
|
float *fParm = (float *)&data[n*nUsage*INST_PARAM_SIZE];
|
|
n++;
|
|
mathMatrixTranspose(fParm, m_RP.m_RotatedMergedObjects[i]->GetVPMatrix().GetData(), g_CpuFlags);
|
|
fParm += 4*4;
|
|
m_RP.m_pCurObject = m_RP.m_RotatedMergedObjects[i];
|
|
|
|
m_RP.m_pCurObject = pObj;
|
|
m_RP.m_FrameObject++;
|
|
for (j=0; j<vp->m_Params_Inst.Num(); j++)
|
|
{
|
|
float *v = vp->m_Params_Inst[j].mfGet();
|
|
fParm[0] = v[0];
|
|
fParm[1] = v[1];
|
|
fParm[2] = v[2];
|
|
fParm[3] = v[3];
|
|
|
|
fParm += 4;
|
|
}
|
|
}
|
|
m_RP.m_pCurObject = curObj;
|
|
m_RP.m_VB_Inst->Unlock();
|
|
|
|
// Set the first stream to be the indexed data and render N instances
|
|
m_pd3dDevice->SetStreamSourceFreq(0, n | D3DSTREAMSOURCE_INDEXEDDATA);
|
|
m_RP.m_VB_Inst->Bind(m_pd3dDevice, 3, nOffs, nUsage*INST_PARAM_SIZE);
|
|
|
|
EF_DrawInstances(ef, slw, nCurInst, nLastInst, nUsage, bUsage, nInstMask);
|
|
nCurInst = nLastInst+1;
|
|
}
|
|
}
|
|
|
|
m_pd3dDevice->SetStreamSource(3, NULL, 0, 0);
|
|
m_pd3dDevice->SetStreamSourceFreq(0, 1);
|
|
}
|
|
|
|
// Draw general/ambient passes (used in FP shaders and in programmable pipeline shaders)
|
|
void CD3D9Renderer::EF_DrawGeneralPasses(SShaderTechnique *hs, SShader *ef, bool bFog, int nStart, int nEnd, bool bDstAlpha)
|
|
{
|
|
SShaderPassHW *slw;
|
|
int i;
|
|
|
|
if ((m_RP.m_ObjFlags & FOB_LIGHTPASS) && (ef->m_Flags & EF_USELIGHTS))
|
|
return;
|
|
if (!bFog && (m_RP.m_ObjFlags & FOB_FOGPASS))
|
|
return;
|
|
|
|
PROFILE_FRAME(DrawShader_GeneralPasses);
|
|
|
|
m_RP.m_nCurLight = 0;
|
|
CVProgram *curVP = NULL;
|
|
CVProgram *newVP;
|
|
|
|
slw = &hs->m_Passes[nStart];
|
|
for (i=nStart; i<=nEnd; i++, slw++)
|
|
{
|
|
m_RP.m_StatNumPasses++;
|
|
m_RP.m_CurrPass = slw;
|
|
|
|
m_RP.m_FlagsModificators = (m_RP.m_FlagsModificators & ~7) | (slw->m_Flags & 3);
|
|
|
|
EF_Eval_DeformVerts(slw->m_Deforms);
|
|
EF_Eval_TexGen(slw);
|
|
EF_Eval_RGBAGen(slw);
|
|
EF_SetVertexStreams(slw->m_Pointers, 1);
|
|
|
|
// Set all textures and HW TexGen modes for the current pass (ShadeLayer)
|
|
newVP = slw->m_VProgram;
|
|
if (newVP)
|
|
m_RP.m_FlagsPerFlush |= RBSI_USEVP;
|
|
if (slw->mfSetTextures())
|
|
{
|
|
bool bInstancing = false;
|
|
|
|
// Set vertex program for the current pass if needed
|
|
if (newVP != curVP)
|
|
{
|
|
if (newVP)
|
|
{
|
|
curVP = newVP;
|
|
int nFlags = VPF_DONTSETMATRICES;
|
|
if (CV_r_geominstancing && m_RP.m_MergedObjects.Num() > 2 && m_bDeviceSupportsInstancing && (curVP->m_Flags & VPFI_SUPPORTS_INSTANCING) && !(m_RP.m_FlagsModificators & RBMF_TCG))
|
|
{
|
|
bInstancing = true;
|
|
nFlags |= VPF_INSTANCING_NOROTATE;
|
|
}
|
|
curVP->mfSet(true, slw, nFlags);
|
|
}
|
|
else
|
|
curVP = NULL;
|
|
}
|
|
|
|
EF_ApplyMatrixOps(slw->m_MatrixOps, true);
|
|
|
|
if (curVP)
|
|
{
|
|
#ifndef PIPE_USE_INSTANCING
|
|
curVP->mfSetStateMatrices();
|
|
#endif
|
|
curVP->mfSetVariables(false, &slw->m_VPParamsNoObj);
|
|
}
|
|
else
|
|
{
|
|
if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_LMaterial && !(ef->m_LMFlags & LMF_DISABLE))
|
|
{
|
|
m_RP.m_pShaderResources->m_LMaterial->mfApply(slw->m_LMFlags);
|
|
if (!(slw->m_LMFlags & (LMF_DISABLE | LMF_HASPSHADER)) && !(m_RP.m_CurrentVLights & 0xff))
|
|
EF_ConstantLightMaterial(m_RP.m_pShaderResources->m_LMaterial, slw->m_LMFlags);
|
|
}
|
|
else
|
|
m_RP.m_CurrentVLights = 0;
|
|
m_RP.m_PersFlags &= ~RBPF_VSNEEDSET;
|
|
}
|
|
|
|
// Set Pixel shaders and Register combiners for the current pass
|
|
if (slw->m_FShader)
|
|
{
|
|
if (!bInstancing)
|
|
slw->m_FShader->mfSet(true, slw, 0);
|
|
else
|
|
slw->m_FShader->mfSet(true, slw, PSF_INSTANCING);
|
|
}
|
|
else
|
|
m_RP.m_PersFlags &= ~RBPF_PS1NEEDSET;
|
|
|
|
// Set Render states for the current pass
|
|
int State;
|
|
if (bFog)
|
|
{
|
|
State = slw->m_RenderState;
|
|
if (m_RP.m_pShader->m_Flags2 & EF2_OPAQUE)
|
|
State |= GS_DEPTHFUNC_EQUAL;
|
|
}
|
|
else
|
|
if (m_RP.m_pCurObject->m_RenderState)
|
|
State = m_RP.m_pCurObject->m_RenderState;
|
|
else
|
|
if (m_RP.m_RendPass || (m_RP.m_ObjFlags & FOB_LIGHTPASS))
|
|
State = slw->m_SecondRenderState;
|
|
else
|
|
State = slw->m_RenderState;
|
|
if (bDstAlpha)
|
|
State = (State & ~GS_BLEND_MASK) | GS_BLSRC_DSTALPHA | GS_BLDST_ONEMINUSDSTALPHA;
|
|
EF_SetState(State);
|
|
#ifndef PIPE_USE_INSTANCING
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
{
|
|
if (bFog)
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Fog Pass %d\n", m_RP.m_RendPass);
|
|
else
|
|
Logv(SRendItem::m_RecurseLevel, "+++ General Pass %d\n", m_RP.m_RendPass);
|
|
}
|
|
#endif
|
|
|
|
m_RP.m_pCurObject->SetScissor();
|
|
|
|
EF_Draw(ef, slw);
|
|
|
|
m_RP.m_RendPass++;
|
|
|
|
#else //PIPE_USE_INSTANCING
|
|
HRESULT h;
|
|
m_RP.m_RendPass++;
|
|
|
|
int bFogOverrided = 0;
|
|
bool bFogDisable = bFog || (curVP && (curVP->m_Flags & VPFI_NOFOG));
|
|
bool bFogVP = (m_RP.m_PersFlags & RBPF_HDR) || (curVP && (curVP->m_Flags & VPFI_VS30ONLY));
|
|
bFogOverrided = EF_FogCorrection(bFogDisable, bFogVP);
|
|
|
|
// Assume if HW supports PS3.0, VS3.0 are supported as well
|
|
if (bInstancing)
|
|
{
|
|
// Using geometry instancing approach
|
|
EF_DrawGeometryInstancing_VS30(ef, slw, curVP);
|
|
}
|
|
else
|
|
{
|
|
// Unlock all VB (if needed) and set current streams
|
|
EF_PreDraw(slw);
|
|
|
|
int nObj = 0;
|
|
CCObject *pSaveObj = m_RP.m_pCurObject;
|
|
CCObject *pObj = pSaveObj;
|
|
while (true)
|
|
{
|
|
if (nObj)
|
|
{
|
|
m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj];
|
|
m_RP.m_FrameObject++;
|
|
pObj = m_RP.m_pCurObject;
|
|
|
|
if (m_RP.m_FlagsModificators & (RBMF_LMTCUSED | RBMF_BENDINFOUSED))
|
|
{
|
|
if (pObj->m_pLMTCBufferO && pObj->m_pLMTCBufferO->m_pVertexBuffer)
|
|
{
|
|
int nOffs;
|
|
IDirect3DVertexBuffer9 *pBuf = (IDirect3DVertexBuffer9 *)pObj->m_pLMTCBufferO->m_pVertexBuffer->GetStream(VSF_GENERAL, &nOffs);
|
|
h = m_pd3dDevice->SetStreamSource( 2, pBuf, nOffs, m_VertexSize[pObj->m_pLMTCBufferO->m_pVertexBuffer->m_vertexformat]);
|
|
}
|
|
}
|
|
if (!curVP)
|
|
{
|
|
EF_SetObjectTransform(pObj, ef, pObj->m_ObjFlags);
|
|
if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_LMaterial && !(ef->m_LMFlags & LMF_DISABLE))
|
|
m_RP.m_pShaderResources->m_LMaterial->mfApply(slw->m_LMFlags);
|
|
else
|
|
m_RP.m_CurrentVLights = 0;
|
|
|
|
if (m_RP.m_FrameGTC == m_RP.m_Frame)
|
|
{
|
|
for (int nt=0; nt<gRenDev->m_TexMan->m_nCurStages; nt++)
|
|
{
|
|
if (m_RP.m_pGTC[nt])
|
|
{
|
|
EF_SelectTMU(nt);
|
|
m_RP.m_pGTC[nt]->mfSet(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pObj->SetScissor();
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
{
|
|
Vec3d vPos = pObj->GetTranslation();
|
|
if (bFog)
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Fog Pass %d (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, pObj->m_VisId, vPos[0], vPos[1], vPos[2]);
|
|
else
|
|
Logv(SRendItem::m_RecurseLevel, "+++ General Pass %d (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, pObj->m_VisId, vPos[0], vPos[1], vPos[2]);
|
|
}
|
|
#endif
|
|
|
|
// Set per-object alpha-blending
|
|
if (pObj->m_ObjFlags & FOB_HASALPHA)
|
|
pObj->SetAlphaState(slw->m_FShader, State);
|
|
|
|
if (curVP)
|
|
{
|
|
curVP->mfSetStateMatrices();
|
|
curVP->mfSetVariables(true, &slw->m_VPParamsObj);
|
|
}
|
|
|
|
if (slw->m_FShader)
|
|
slw->m_FShader->mfSetVariables(true, slw->m_CGFSParamsObj);
|
|
else
|
|
{
|
|
if (slw->m_RGBComps && slw->m_RGBComps->m_Comps[0] && slw->m_RGBComps->m_Comps[0]->m_bDependsOnObject)
|
|
{
|
|
float *vals = slw->m_RGBComps->mfGet();
|
|
UCol color;
|
|
color.bcolor[2] = (byte)(vals[0] * 255.0f);
|
|
color.bcolor[1] = (byte)(vals[1] * 255.0f);
|
|
color.bcolor[0] = (byte)(vals[2] * 255.0f);
|
|
color.bcolor[3] = (byte)(vals[3] * 255.0f);
|
|
m_RP.m_NeedGlobalColor = color;
|
|
}
|
|
EF_CommitTexStageState();
|
|
}
|
|
|
|
{
|
|
//PROFILE_FRAME(Draw_ShaderIndexMesh);
|
|
if (m_RP.m_pRE)
|
|
m_RP.m_pRE->mfDraw(ef, slw);
|
|
else
|
|
EF_DrawIndexedMesh(R_PRIMV_TRIANGLES);
|
|
}
|
|
nObj++;
|
|
if (nObj >= m_RP.m_MergedObjects.Num())
|
|
break;
|
|
}
|
|
EF_FogRestore(bFogOverrided);
|
|
if (!CVProgram::m_LastVP)
|
|
{
|
|
if (m_RP.m_FlagsModificators & (RBMF_TCM | RBMF_TCG))
|
|
EF_CommitTexTransforms(false);
|
|
}
|
|
else
|
|
m_RP.m_FlagsModificators &= ~(RBMF_TCM | RBMF_TCG);
|
|
if (pSaveObj != m_RP.m_pCurObject)
|
|
{
|
|
m_RP.m_pCurObject = pSaveObj;
|
|
m_RP.m_FrameObject++;
|
|
if (!curVP)
|
|
EF_SetObjectTransform(pSaveObj, ef, pSaveObj->m_ObjFlags);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
slw->mfResetTextures();
|
|
EF_ApplyMatrixOps(slw->m_MatrixOps, false);
|
|
}
|
|
}
|
|
|
|
// Draw light passes (up to 4 light sources per single pass)
|
|
void CD3D9Renderer::EF_DrawLightPasses_PS30(SShaderTechnique *hs, SShader *ef, int nStart, int nEnd, bool bDstAlpha)
|
|
{
|
|
SShaderPassHW *slw;
|
|
int i;
|
|
|
|
m_RP.m_nCurLight = 0;
|
|
CVProgram *curVP = NULL;
|
|
|
|
PROFILE_FRAME(DrawShader_MultiLight_Passes);
|
|
|
|
int nLight;
|
|
int nLights = m_RP.m_NumActiveDLights;
|
|
|
|
// make sure for each pass not more then 1 projected light
|
|
if (gRenDev->m_RP.m_pCurObject->m_ObjFlags & FOB_SELECTED)
|
|
{
|
|
int nnn = 0;
|
|
}
|
|
|
|
int nStencState = 0;
|
|
bool bStencState = m_RP.m_pStateShader && m_RP.m_pStateShader->m_State && m_RP.m_pStateShader->m_State->m_Stencil;
|
|
|
|
slw = &hs->m_Passes[nStart];
|
|
CDLight *ProjLights[16];
|
|
int nProjLights = 0;
|
|
CDLight *OtherLights[16];
|
|
int nOtherLights = 0;
|
|
CDLight *StencLights[16];
|
|
int nStencLights = 0;
|
|
bool bHasLM = m_RP.m_pCurObject->m_nLMId != 0;
|
|
bool bHasAmb = ((m_RP.m_ObjFlags & FOB_LIGHTPASS) == 0);
|
|
if (bDstAlpha || m_RP.m_RendPass)
|
|
{
|
|
bHasAmb = false;
|
|
}
|
|
for (nLight=0; nLight<nLights; nLight++)
|
|
{
|
|
CDLight *dl = m_RP.m_pActiveDLights[nLight];
|
|
// ignore LM light sources for diffuse only materials with LM but without specular
|
|
if (bHasLM && (dl->m_Flags & DLF_LM) && (slw->m_LMFlags & LMF_NOSPECULAR))
|
|
continue;
|
|
if (bStencState && (dl->m_Flags & DLF_CASTSHADOW_VOLUME))
|
|
StencLights[nStencLights++] = dl;
|
|
else
|
|
if (dl->m_Flags & DLF_PROJECT)
|
|
ProjLights[nProjLights++] = dl;
|
|
else
|
|
OtherLights[nOtherLights++] = dl;
|
|
}
|
|
if (!bHasAmb && !nOtherLights && !nProjLights && !nStencLights)
|
|
return;
|
|
float fFP = 0.334f;
|
|
if (!(m_Features & RFT_HW_PS30))
|
|
fFP = 0.5f;
|
|
float fFO = 1.0f;
|
|
int nO = 0;
|
|
int nP = 0;
|
|
float fO = 0;
|
|
float fP = 0;
|
|
int nMaxLights = (m_Features & RFT_HW_PS30) ? NUM_PPLIGHTS_PERPASS_PS30 : NUM_PPLIGHTS_PERPASS_PS2X;
|
|
int nAmbLights = nMaxLights;
|
|
if (bHasAmb)
|
|
{
|
|
for (i=nStart; i<=nEnd; i++, slw++)
|
|
{
|
|
if (slw->m_LMFlags & LMF_HASAMBIENT)
|
|
{
|
|
if (slw->m_LMFlags & LMF_HASDOT3LM)
|
|
{
|
|
if (!m_RP.m_pShaderResources || !m_RP.m_pCurObject->m_nLMDirId)
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
nAmbLights = slw->m_nAmbMaxLights;
|
|
}
|
|
nAmbLights = min(nAmbLights, nMaxLights);
|
|
slw = &hs->m_Passes[nStart];
|
|
for (i=0; i<nStencLights; i++)
|
|
{
|
|
m_RP.m_LPasses[i].nProjectors = 0;
|
|
m_RP.m_LPasses[i].nLights = 1;
|
|
m_RP.m_LPasses[i].pLights[0] = StencLights[i];
|
|
}
|
|
for (; i<32; i++)
|
|
{
|
|
if (nP >= nProjLights && nO >= nOtherLights)
|
|
{
|
|
if (!i && bHasAmb)
|
|
{
|
|
m_RP.m_LPasses[0].nLights = 0;
|
|
m_RP.m_LPasses[0].nProjectors = 0;
|
|
i++;
|
|
}
|
|
break;
|
|
}
|
|
m_RP.m_LPasses[i].nLights = 0;
|
|
m_RP.m_LPasses[i].nProjectors = 0;
|
|
int j = 0;
|
|
while (true)
|
|
{
|
|
fO += fFO;
|
|
if ((int)fO >= nO+1 && nO < nOtherLights)
|
|
{
|
|
m_RP.m_LPasses[i].nLights++;
|
|
m_RP.m_LPasses[i].pLights[j] = OtherLights[nO];
|
|
j++;
|
|
nO++;
|
|
}
|
|
if (nP >= nProjLights && nO >= nOtherLights)
|
|
break;
|
|
if (j == nAmbLights)
|
|
{
|
|
nAmbLights = nMaxLights;
|
|
break;
|
|
}
|
|
if (m_RP.m_LPasses[i].nProjectors == 0)
|
|
{
|
|
fP += fFP;
|
|
if ((int)fP >= nP+1 && nP < nProjLights)
|
|
{
|
|
m_RP.m_LPasses[i].nLights++;
|
|
m_RP.m_LPasses[i].nProjectors++;
|
|
m_RP.m_LPasses[i].pLights[j] = ProjLights[nP];
|
|
j++;
|
|
nP++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (nO >= nOtherLights)
|
|
break;
|
|
}
|
|
if (nP >= nProjLights && nO >= nOtherLights)
|
|
break;
|
|
if (j == nAmbLights)
|
|
{
|
|
nAmbLights = nMaxLights;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int nPasses = i;
|
|
int nPass;
|
|
m_RP.m_nCurLight = 0;
|
|
m_RP.m_PersFlags |= RBPF_MULTILIGHTS;
|
|
for (nPass=0; nPass<nPasses; nPass++)
|
|
{
|
|
m_RP.m_StatNumPasses++;
|
|
m_RP.m_nCurLightPass = nPass;
|
|
SLightPass *lp = &m_RP.m_LPasses[nPass];
|
|
m_RP.m_ShaderLightMask = lp->nLights;
|
|
m_RP.m_pCurLight = NULL;
|
|
int Types[4];
|
|
bool bUseOccl = false;
|
|
for (i=0; i<lp->nLights; i++)
|
|
{
|
|
assert(lp->nLights <= nMaxLights);
|
|
CDLight *dl = lp->pLights[i];
|
|
if (dl->m_Flags & DLF_POINT)
|
|
Types[i] = SLMF_POINT;
|
|
else
|
|
if (dl->m_Flags & DLF_PROJECT)
|
|
{
|
|
Types[i] = SLMF_PROJECTED;
|
|
m_RP.m_pCurLight = dl;
|
|
}
|
|
else
|
|
Types[i] = SLMF_DIRECT;
|
|
if ((dl->m_Flags & DLF_LM) && bHasLM)
|
|
{
|
|
Types[i] |= SLMF_ONLYSPEC;
|
|
if (*(int *)m_RP.m_pCurObject->m_OcclLights != 0)
|
|
{
|
|
byte nLight = dl->m_Id+1;
|
|
if (m_RP.m_pCurObject->m_OcclLights[0] == nLight || m_RP.m_pCurObject->m_OcclLights[1] == nLight || m_RP.m_pCurObject->m_OcclLights[2] == nLight || m_RP.m_pCurObject->m_OcclLights[3] == nLight)
|
|
{
|
|
Types[i] |= SLMF_SPECOCCLUSION;
|
|
bUseOccl = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
switch(lp->nLights)
|
|
{
|
|
case 2:
|
|
if (Types[0] > Types[1])
|
|
{
|
|
Exchange(Types[0], Types[1]);
|
|
Exchange(lp->pLights[0], lp->pLights[1]);
|
|
}
|
|
break;
|
|
case 3:
|
|
if (Types[0] > Types[1])
|
|
{
|
|
Exchange(Types[0], Types[1]);
|
|
Exchange(lp->pLights[0], lp->pLights[1]);
|
|
}
|
|
if (Types[0] > Types[2])
|
|
{
|
|
Exchange(Types[0], Types[2]);
|
|
Exchange(lp->pLights[0], lp->pLights[2]);
|
|
}
|
|
if (Types[1] > Types[2])
|
|
{
|
|
Exchange(Types[1], Types[2]);
|
|
Exchange(lp->pLights[1], lp->pLights[2]);
|
|
}
|
|
break;
|
|
case 4:
|
|
{
|
|
for (int i=0; i<4; i++)
|
|
{
|
|
for (int j=i; j<4; j++)
|
|
{
|
|
if (Types[i] > Types[j])
|
|
{
|
|
Exchange(Types[i], Types[j]);
|
|
Exchange(lp->pLights[i], lp->pLights[j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
for (i=0; i<lp->nLights; i++)
|
|
{
|
|
m_RP.m_ShaderLightMask |= Types[i] << (SLMF_LTYPE_SHIFT + i*4);
|
|
}
|
|
if (lp->nLights == 1 && bStencState)
|
|
{
|
|
nStencState = (lp->pLights[0]->m_Flags & DLF_CASTSHADOW_VOLUME) ? GS_STENCIL : 0;
|
|
}
|
|
for (i=nStart; i<=nEnd; i++, slw++)
|
|
{
|
|
m_RP.m_CurrPass = slw;
|
|
m_RP.m_FlagsModificators = (m_RP.m_FlagsModificators & ~7) | (slw->m_Flags & 3);
|
|
if (slw->m_LMFlags & LMF_HASAMBIENT)
|
|
{
|
|
if (nPass || !bHasAmb)
|
|
continue;
|
|
if (slw->m_LMFlags & LMF_HASDOT3LM)
|
|
{
|
|
if (!m_RP.m_pShaderResources || !m_RP.m_pCurObject->m_nLMDirId)
|
|
continue;
|
|
}
|
|
}
|
|
if ((slw->m_LMFlags & LMF_USEOCCLUSIONMAP) && !bUseOccl)
|
|
continue;
|
|
|
|
EF_Eval_TexGen(slw);
|
|
EF_Eval_RGBAGen(slw);
|
|
EF_SetVertexStreams(slw->m_Pointers, 1);
|
|
|
|
// Set all textures and HW TexGen modes for the current pass (ShadeLayer)
|
|
curVP = slw->m_VProgram;
|
|
if (curVP)
|
|
m_RP.m_FlagsPerFlush |= RBSI_USEVP;
|
|
if (slw->mfSetTextures())
|
|
{
|
|
if (curVP)
|
|
curVP->mfSet(true, slw, VPF_DONTSETMATRICES);
|
|
|
|
EF_ApplyMatrixOps(slw->m_MatrixOps, true);
|
|
|
|
if (curVP)
|
|
{
|
|
#ifndef PIPE_USE_INSTANCING
|
|
curVP->mfSetStateMatrices();
|
|
#endif
|
|
curVP->mfSetVariables(false, &slw->m_VPParamsNoObj);
|
|
}
|
|
else
|
|
{
|
|
m_RP.m_CurrentVLights = 0;
|
|
m_RP.m_PersFlags &= ~RBPF_VSNEEDSET;
|
|
}
|
|
|
|
// Set Pixel shaders and Register combiners for the current pass
|
|
if (slw->m_FShader)
|
|
slw->m_FShader->mfSet(true, slw);
|
|
else
|
|
m_RP.m_PersFlags &= ~RBPF_PS1NEEDSET;
|
|
|
|
int State;
|
|
if (m_RP.m_RendPass || (m_RP.m_ObjFlags & FOB_LIGHTPASS))
|
|
State = slw->m_SecondRenderState;
|
|
else
|
|
State = slw->m_RenderState;
|
|
if (bDstAlpha)
|
|
State = (State & ~GS_BLEND_MASK) | GS_BLSRC_ONEMINUSDSTALPHA | GS_BLDST_ONE | GS_COLMASKONLYRGB;
|
|
EF_SetState(State | nStencState);
|
|
|
|
#ifndef PIPE_USE_INSTANCING
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Light Pass %d [%d Lights]\n", m_RP.m_RendPass, m_RP.m_nCurLights);
|
|
#endif
|
|
|
|
EF_Scissor(false, 0, 0, 0, 0);
|
|
|
|
EF_Draw(ef, slw);
|
|
|
|
m_RP.m_RendPass++;
|
|
|
|
#else //PIPE_USE_INSTANCING
|
|
m_RP.m_RendPass++;
|
|
|
|
int bFogOverrided = 0;
|
|
// Unlock all VB (if needed) and set current streams
|
|
EF_PreDraw(slw);
|
|
bool bFogDisable = (curVP && (curVP->m_Flags & VPFI_NOFOG)) || (m_RP.m_PersFlags & RBPF_HDR);
|
|
bool bFogVP = (m_RP.m_PersFlags & RBPF_HDR) || (curVP && (curVP->m_Flags & VPFI_VS30ONLY));
|
|
bFogOverrided = EF_FogCorrection(bFogDisable, bFogVP);
|
|
|
|
int nObj = 0;
|
|
CCObject *pSaveObj = m_RP.m_pCurObject;
|
|
CCObject *pObj = pSaveObj;
|
|
HRESULT h;
|
|
while (true)
|
|
{
|
|
if (nObj)
|
|
{
|
|
m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj];
|
|
m_RP.m_FrameObject++;
|
|
pObj = m_RP.m_pCurObject;
|
|
|
|
if (m_RP.m_FlagsModificators & (RBMF_LMTCUSED | RBMF_BENDINFOUSED))
|
|
{
|
|
if (pObj->m_pLMTCBufferO && pObj->m_pLMTCBufferO->m_pVertexBuffer)
|
|
{
|
|
int nOffs;
|
|
IDirect3DVertexBuffer9 *pBuf = (IDirect3DVertexBuffer9 *)pObj->m_pLMTCBufferO->m_pVertexBuffer->GetStream(VSF_GENERAL, &nOffs);
|
|
h = m_pd3dDevice->SetStreamSource( 2, pBuf, nOffs, m_VertexSize[pObj->m_pLMTCBufferO->m_pVertexBuffer->m_vertexformat]);
|
|
}
|
|
}
|
|
|
|
if (!curVP)
|
|
{
|
|
EF_SetObjectTransform(pObj, ef, pObj->m_ObjFlags);
|
|
m_RP.m_CurrentVLights = 0;
|
|
|
|
if (m_RP.m_FrameGTC == m_RP.m_Frame)
|
|
{
|
|
for (int nt=0; nt<gRenDev->m_TexMan->m_nCurStages; nt++)
|
|
{
|
|
if (m_RP.m_pGTC[nt])
|
|
{
|
|
EF_SelectTMU(nt);
|
|
m_RP.m_pGTC[nt]->mfSet(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
EF_Scissor(false, 0, 0, 0, 0);
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
{
|
|
Vec3d vPos = pObj->GetTranslation();
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Light Pass %d [%d Lights] (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, lp->nLights, pObj->m_VisId, vPos[0], vPos[1], vPos[2]);
|
|
}
|
|
#endif
|
|
|
|
if (curVP)
|
|
{
|
|
curVP->mfSetStateMatrices();
|
|
curVP->mfSetVariables(true, &slw->m_VPParamsObj);
|
|
}
|
|
// Set per-object alpha-blending
|
|
if (pObj->m_ObjFlags & FOB_HASALPHA)
|
|
pObj->SetAlphaState(slw->m_FShader, State);
|
|
|
|
if (slw->m_FShader)
|
|
slw->m_FShader->mfSetVariables(true, slw->m_CGFSParamsObj);
|
|
else
|
|
{
|
|
if (slw->m_RGBComps && slw->m_RGBComps->m_Comps[0] && slw->m_RGBComps->m_Comps[0]->m_bDependsOnObject)
|
|
{
|
|
float *vals = slw->m_RGBComps->mfGet();
|
|
UCol color;
|
|
color.bcolor[2] = (byte)(vals[0] * 255.0f);
|
|
color.bcolor[1] = (byte)(vals[1] * 255.0f);
|
|
color.bcolor[0] = (byte)(vals[2] * 255.0f);
|
|
color.bcolor[3] = (byte)(vals[3] * 255.0f);
|
|
m_RP.m_NeedGlobalColor = color;
|
|
}
|
|
EF_CommitTexStageState();
|
|
}
|
|
|
|
{
|
|
//PROFILE_FRAME(Draw_ShaderIndexMesh);
|
|
if (m_RP.m_pRE)
|
|
m_RP.m_pRE->mfDraw(ef, slw);
|
|
else
|
|
EF_DrawIndexedMesh(R_PRIMV_TRIANGLES);
|
|
}
|
|
nObj++;
|
|
if (nObj >= m_RP.m_MergedObjects.Num())
|
|
break;
|
|
}
|
|
EF_FogRestore(bFogOverrided);
|
|
if (!CVProgram::m_LastVP)
|
|
{
|
|
if (m_RP.m_FlagsModificators & (RBMF_TCM | RBMF_TCG))
|
|
EF_CommitTexTransforms(false);
|
|
}
|
|
else
|
|
m_RP.m_FlagsModificators &= ~(RBMF_TCM | RBMF_TCG);
|
|
if (pSaveObj != m_RP.m_pCurObject)
|
|
{
|
|
m_RP.m_pCurObject = pSaveObj;
|
|
m_RP.m_FrameObject++;
|
|
if (!curVP)
|
|
EF_SetObjectTransform(pSaveObj, ef, pSaveObj->m_ObjFlags);
|
|
}
|
|
#endif
|
|
}
|
|
slw->mfResetTextures();
|
|
EF_ApplyMatrixOps(slw->m_MatrixOps, false);
|
|
break;
|
|
}
|
|
}
|
|
m_RP.m_ShaderLightMask = 0;
|
|
m_RP.m_nCurLightPass = 0;
|
|
m_RP.m_PersFlags &= ~RBPF_MULTILIGHTS;
|
|
}
|
|
|
|
// Draw light passes - for each light source (used in FP shaders and in programmable pipeline shaders)
|
|
void CD3D9Renderer::EF_DrawLightPasses(SShaderTechnique *hs, SShader *ef, int nStart, int nEnd, bool bDstAlpha)
|
|
{
|
|
int i, l;
|
|
int nl = 0;
|
|
int n;
|
|
|
|
CVProgram *curVP = NULL;
|
|
CVProgram *newVP;
|
|
|
|
PROFILE_FRAME(DrawShader_LightPasses);
|
|
|
|
// Just single pass for transparent objects
|
|
//if (m_RP.m_RendPass && m_RP.m_fCurOpacity != 1.0f)
|
|
// return;
|
|
|
|
int nStencState = 0;
|
|
bool bStencState = m_RP.m_pStateShader && m_RP.m_pStateShader->m_State && m_RP.m_pStateShader->m_State->m_Stencil;
|
|
|
|
//return;
|
|
// For each light source
|
|
for (l=0; l<m_RP.m_NumActiveDLights; l++)
|
|
{
|
|
m_RP.m_pCurLight = m_RP.m_pActiveDLights[l];
|
|
m_RP.m_nCurLight = m_RP.m_pCurLight->m_Id;
|
|
SShaderPassHW* slw = &hs->m_Passes[nStart];
|
|
nl++;
|
|
|
|
// Ignore diffuse passes for specular only light sources
|
|
if ((m_RP.m_pCurLight->m_Flags & DLF_LM) && slw->m_ePassType == eSHP_DiffuseLight)
|
|
{
|
|
if ((m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_Textures[EFTT_LIGHTMAP_DIR]) || m_RP.m_pCurObject->m_nLMId)
|
|
continue;
|
|
}
|
|
|
|
if (bStencState)
|
|
nStencState = (m_RP.m_pCurLight->m_Flags & DLF_CASTSHADOW_VOLUME) ? GS_STENCIL : 0;
|
|
|
|
bool bOnlyLightPass;
|
|
bool bShadowMask = false;
|
|
|
|
n = 0;
|
|
bool bBreak = false;
|
|
// For each layer/pass
|
|
for (i=nStart; i<=nEnd; i++, slw++)
|
|
{
|
|
int msk;
|
|
if (msk = (slw->m_LightFlags & DLF_LIGHTTYPE_MASK))
|
|
{
|
|
if (!(msk & (m_RP.m_pCurLight->m_Flags & DLF_LIGHTTYPE_MASK)))
|
|
continue;
|
|
if (slw->m_LMFlags & LMF_USEOCCLUSIONMAP)
|
|
{
|
|
byte *nOccl = m_RP.m_pCurObject->m_OcclLights;
|
|
if (*(int *)nOccl == 0)
|
|
continue;
|
|
byte nLight = m_RP.m_nCurLight+1;
|
|
if (nLight != nOccl[0] && nLight != nOccl[1] && nLight != nOccl[2] && nLight != nOccl[3])
|
|
continue;
|
|
}
|
|
if (slw->m_LightFlags & DLF_LM)
|
|
{
|
|
// Ignore OnlySpecular passes if light source is non-LM
|
|
if (!(m_RP.m_pCurLight->m_Flags & DLF_LM))
|
|
continue;
|
|
if ((!m_RP.m_pShaderResources || !m_RP.m_pShaderResources->m_Textures[EFTT_LIGHTMAP_DIR]) && !m_RP.m_pCurObject->m_nLMId)
|
|
continue;
|
|
//assert (m_RP.m_pCurLight->m_SpecColor.r!=0 || m_RP.m_pCurLight->m_SpecColor.g!=0 || m_RP.m_pCurLight->m_SpecColor.b!=0);
|
|
// Ignore specular pass if specular is less threshold
|
|
if (m_RP.m_pCurLight->m_SpecColor.r<=0.01f && m_RP.m_pCurLight->m_SpecColor.g<=0.01f && m_RP.m_pCurLight->m_SpecColor.b<=0.01f)
|
|
continue;
|
|
}
|
|
}
|
|
if (slw->m_LMFlags & LMF_NOBUMP)
|
|
{
|
|
if (!m_RP.m_pShaderResources || !m_RP.m_pShaderResources->m_Textures[EFTT_BUMP] || !(m_RP.m_pShaderResources->m_Textures[EFTT_BUMP]->m_TU.m_nFlags & FTU_NOBUMP))
|
|
continue;
|
|
bBreak = true;
|
|
}
|
|
else
|
|
if (bBreak)
|
|
break;
|
|
|
|
if (EF_RejectLightPass(slw))
|
|
continue;
|
|
|
|
bOnlyLightPass = EF_IsOnlyLightPass(slw);
|
|
|
|
if (CV_r_bumpselfshadow && bOnlyLightPass && m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_Textures[EFTT_BUMP] && m_RP.m_pShaderResources->m_Textures[EFTT_BUMP]->m_TU.m_TexPic && m_RP.m_pShaderResources->m_Textures[EFTT_BUMP]->m_TU.m_TexPic->m_pSH)
|
|
{
|
|
EF_DrawLightShadowMask(l);
|
|
curVP = NULL;
|
|
bShadowMask = true;
|
|
}
|
|
|
|
if (!n)
|
|
{
|
|
if (!(m_RP.m_StatLightMask & (1<<m_RP.m_nCurLight)))
|
|
{
|
|
m_RP.m_StatLightMask |= (1<<m_RP.m_nCurLight);
|
|
m_RP.m_StatNumLights++;
|
|
}
|
|
}
|
|
|
|
n++;
|
|
m_RP.m_StatNumLightPasses++;
|
|
|
|
m_RP.m_CurrPass = slw;
|
|
|
|
if (m_RP.m_pCurLightMaterial)
|
|
m_RP.m_pCurLightMaterial->mfApply(slw->m_LMFlags | (l<<LMF_LIGHT_SHIFT));
|
|
else
|
|
m_RP.m_CurrentVLights = 0;
|
|
|
|
m_RP.m_FlagsModificators = (m_RP.m_FlagsModificators & ~15) | (slw->m_Flags & 3);
|
|
if (m_RP.m_pCurObject->m_pLMTCBufferO && m_RP.m_pCurObject->m_pLMTCBufferO->m_pVertexBuffer && m_RP.m_pCurObject->m_pLMTCBufferO->m_pVertexBuffer->m_vertexformat != VERTEX_FORMAT_TEX2F)
|
|
m_RP.m_FlagsModificators |= RBMF_BENDINFOUSED;
|
|
|
|
EF_Eval_TexGen(slw);
|
|
EF_Eval_RGBAGen(slw);
|
|
EF_SetVertexStreams(slw->m_Pointers, 1);
|
|
|
|
// Set all textures and HW TexGen modes for the current pass (ShadeLayer)
|
|
newVP = slw->m_VProgram;
|
|
if (newVP)
|
|
m_RP.m_FlagsPerFlush |= RBSI_USEVP;
|
|
if (slw->mfSetTextures())
|
|
{
|
|
// Set vertex program for the current pass if needed
|
|
if (newVP != curVP)
|
|
{
|
|
if (newVP)
|
|
{
|
|
curVP = newVP;
|
|
curVP->mfSet(true, slw, VPF_DONTSETMATRICES);
|
|
}
|
|
else
|
|
curVP = NULL;
|
|
}
|
|
|
|
EF_ApplyMatrixOps(slw->m_MatrixOps, true);
|
|
|
|
if (!curVP)
|
|
m_RP.m_PersFlags &= ~RBPF_VSNEEDSET;
|
|
else
|
|
{
|
|
#ifndef PIPE_USE_INSTANCING
|
|
curVP->mfSetStateMatrices();
|
|
#endif
|
|
curVP->mfSetVariables(false, &slw->m_VPParamsNoObj);
|
|
}
|
|
|
|
// Set Pixel shaders for the current pass
|
|
if (slw->m_FShader)
|
|
slw->m_FShader->mfSet(true, slw);
|
|
else
|
|
m_RP.m_PersFlags &= ~RBPF_PS1NEEDSET;
|
|
|
|
// Set Render states for the current pass
|
|
int State;
|
|
if (m_RP.m_pCurObject->m_RenderState)
|
|
State = m_RP.m_pCurObject->m_RenderState;
|
|
else
|
|
{
|
|
if (m_RP.m_RendPass || (m_RP.m_ObjFlags & FOB_LIGHTPASS))
|
|
State = slw->m_SecondRenderState;
|
|
else
|
|
State = slw->m_RenderState;
|
|
if (bDstAlpha || bShadowMask)
|
|
State = (State & ~GS_BLEND_MASK) | GS_BLSRC_ONEMINUSDSTALPHA | GS_BLDST_ONE | GS_COLMASKONLYRGB;
|
|
}
|
|
State |= nStencState;
|
|
EF_SetState(State);
|
|
|
|
#ifndef PIPE_USE_INSTANCING
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Light Pass %d [Light %d]\n", m_RP.m_RendPass, l);
|
|
#endif
|
|
|
|
// Set scissor rect
|
|
if (CV_r_scissor)
|
|
{
|
|
if (bOnlyLightPass && m_RP.m_pCurLight->m_sWidth && m_RP.m_pCurLight->m_sHeight)
|
|
EF_Scissor(true, m_RP.m_pCurLight->m_sX, m_RP.m_pCurLight->m_sY, m_RP.m_pCurLight->m_sWidth, m_RP.m_pCurLight->m_sHeight);
|
|
else
|
|
m_RP.m_pCurObject->SetScissor();
|
|
}
|
|
|
|
EF_Draw(ef, slw);
|
|
|
|
m_RP.m_RendPass++;
|
|
|
|
#else //PIPE_USE_INSTANCING
|
|
m_RP.m_RendPass++;
|
|
|
|
int bFogOverrided = 0;
|
|
// Unlock all VB (if needed) and set current streams
|
|
EF_PreDraw(slw);
|
|
bool bFogDisable = (curVP && (curVP->m_Flags & VPFI_NOFOG));
|
|
bool bFogVP = (m_RP.m_PersFlags & RBPF_HDR) || (curVP && (curVP->m_Flags & VPFI_VS30ONLY));
|
|
bFogOverrided = EF_FogCorrection(bFogDisable, bFogVP);
|
|
|
|
int nObj = 0;
|
|
CCObject *pSaveObj = m_RP.m_pCurObject;
|
|
CCObject *pObj = pSaveObj;
|
|
bool bLightSicssorWasSet = false;
|
|
|
|
// Set scissor rect
|
|
if (CV_r_scissor)
|
|
{
|
|
if (bOnlyLightPass && m_RP.m_pCurLight->m_sWidth && m_RP.m_pCurLight->m_sHeight)
|
|
{
|
|
bLightSicssorWasSet = true;
|
|
if (!(m_RP.m_ObjFlags & FOB_NOSCISSOR))
|
|
EF_Scissor(true, m_RP.m_pCurLight->m_sX, m_RP.m_pCurLight->m_sY, m_RP.m_pCurLight->m_sWidth, m_RP.m_pCurLight->m_sHeight);
|
|
else
|
|
EF_Scissor(false, 0, 0, 0, 0);
|
|
}
|
|
else
|
|
pObj->SetScissor();
|
|
}
|
|
while (true)
|
|
{
|
|
if (nObj)
|
|
{
|
|
// Object changed
|
|
m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj];
|
|
pObj = m_RP.m_pCurObject;
|
|
m_RP.m_FrameObject++;
|
|
if (CV_r_scissor && !bLightSicssorWasSet)
|
|
pObj->SetScissor();
|
|
if (m_RP.m_FlagsModificators & (RBMF_LMTCUSED | RBMF_BENDINFOUSED))
|
|
{
|
|
if (pObj->m_pLMTCBufferO && pObj->m_pLMTCBufferO->m_pVertexBuffer)
|
|
{
|
|
int nOffs;
|
|
IDirect3DVertexBuffer9 *pBuf = (IDirect3DVertexBuffer9 *)pObj->m_pLMTCBufferO->m_pVertexBuffer->GetStream(VSF_GENERAL, &nOffs);
|
|
HRESULT h = m_pd3dDevice->SetStreamSource( 2, pBuf, nOffs, m_VertexSize[pObj->m_pLMTCBufferO->m_pVertexBuffer->m_vertexformat]);
|
|
}
|
|
}
|
|
if (!curVP)
|
|
{
|
|
EF_SetObjectTransform(pObj, ef, pObj->m_ObjFlags);
|
|
if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_LMaterial)
|
|
m_RP.m_pShaderResources->m_LMaterial->mfApply(slw->m_LMFlags | (l<<LMF_LIGHT_SHIFT));
|
|
else
|
|
m_RP.m_CurrentVLights = 0;
|
|
|
|
if (m_RP.m_FrameGTC == m_RP.m_Frame)
|
|
{
|
|
for (int nt=0; nt<gRenDev->m_TexMan->m_nCurStages; nt++)
|
|
{
|
|
if (m_RP.m_pGTC[nt])
|
|
{
|
|
EF_SelectTMU(nt);
|
|
m_RP.m_pGTC[nt]->mfSet(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
{
|
|
Vec3d vPos = pObj->GetTranslation();
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Light Pass %d [light %d] (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, l, m_RP.m_pCurObject->m_VisId, vPos[0], vPos[1], vPos[2]);
|
|
}
|
|
#endif
|
|
|
|
// Set per-object alpha-blending
|
|
if (pObj->m_ObjFlags & FOB_HASALPHA)
|
|
pObj->SetAlphaState(slw->m_FShader, State);
|
|
|
|
if (curVP)
|
|
{
|
|
curVP->mfSetStateMatrices();
|
|
curVP->mfSetVariables(true, &slw->m_VPParamsObj);
|
|
}
|
|
|
|
if (slw->m_FShader)
|
|
slw->m_FShader->mfSetVariables(true, slw->m_CGFSParamsObj);
|
|
else
|
|
{
|
|
if (slw->m_RGBComps && slw->m_RGBComps->m_Comps[0] && slw->m_RGBComps->m_Comps[0]->m_bDependsOnObject)
|
|
{ // Set constant color which is depends on object
|
|
float *vals = slw->m_RGBComps->mfGet();
|
|
UCol color;
|
|
color.bcolor[2] = (byte)(vals[0] * 255.0f);
|
|
color.bcolor[1] = (byte)(vals[1] * 255.0f);
|
|
color.bcolor[0] = (byte)(vals[2] * 255.0f);
|
|
color.bcolor[3] = (byte)(vals[3] * 255.0f);
|
|
m_RP.m_NeedGlobalColor = color;
|
|
}
|
|
EF_CommitTexStageState();
|
|
}
|
|
|
|
{
|
|
//PROFILE_FRAME(Draw_ShaderIndexMesh);
|
|
if (m_RP.m_pRE)
|
|
m_RP.m_pRE->mfDraw(ef, slw);
|
|
else
|
|
EF_DrawIndexedMesh(R_PRIMV_TRIANGLES);
|
|
}
|
|
nObj++;
|
|
if (nObj >= m_RP.m_MergedObjects.Num())
|
|
break;
|
|
}
|
|
EF_FogRestore(bFogOverrided);
|
|
if (!CVProgram::m_LastVP)
|
|
{
|
|
if (m_RP.m_FlagsModificators & (RBMF_TCM | RBMF_TCG))
|
|
EF_CommitTexTransforms(false);
|
|
}
|
|
else
|
|
m_RP.m_FlagsModificators &= ~(RBMF_TCM | RBMF_TCG);
|
|
if (pSaveObj != m_RP.m_pCurObject)
|
|
{
|
|
m_RP.m_pCurObject = pSaveObj;
|
|
m_RP.m_FrameObject++;
|
|
if (!curVP)
|
|
EF_SetObjectTransform(pSaveObj, ef, pSaveObj->m_ObjFlags);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
slw->mfResetTextures();
|
|
EF_ApplyMatrixOps(slw->m_MatrixOps, false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//m_RP.m_nCurLight = -1;
|
|
//m_RP.m_pCurLight = NULL;
|
|
}
|
|
|
|
// Draw bump self-shadowing pass using horizon-maps technique (used in programmable pipeline shaders only)
|
|
void CD3D9Renderer::EF_DrawLightShadowMask(int nLight)
|
|
{
|
|
STexPic *pTX = m_RP.m_pShaderResources->m_Textures[EFTT_BUMP]->m_TU.m_TexPic;
|
|
STexShadow *pTSH = pTX->m_pSH;
|
|
EF_SelectTMU(0);
|
|
pTSH->m_pHorizonTex[0]->Set();
|
|
//pTSH->m_pHorizonTex[0]->SaveJPG("Horiz0.jpg", false);
|
|
EF_SelectTMU(1);
|
|
pTSH->m_pBasisTex[0]->Set();
|
|
//pTSH->m_pBasisTex[0]->SaveJPG("Basis0.jpg", false);
|
|
EF_SelectTMU(2);
|
|
pTSH->m_pHorizonTex[1]->Set();
|
|
//pTSH->m_pHorizonTex[1]->SaveJPG("Horiz1.jpg", false);
|
|
EF_SelectTMU(3);
|
|
pTSH->m_pBasisTex[1]->Set();
|
|
//pTSH->m_pBasisTex[1]->SaveJPG("Basis1.jpg", false);
|
|
CTexMan::m_nCurStages = 4;
|
|
EF_SetState(GS_COLMASKONLYALPHA);
|
|
if (!m_RP.m_VPTexShadow)
|
|
m_RP.m_VPTexShadow = CVProgram::mfForName("CGVProgTexShadow");
|
|
if (!m_RP.m_RCTexShadow)
|
|
m_RP.m_RCTexShadow = CPShader::mfForName("CGRCTexShadow");
|
|
|
|
m_RP.m_FlagsModificators = (m_RP.m_FlagsModificators & ~0xf) | RBMF_TANGENTSUSED;
|
|
|
|
m_RP.m_VPTexShadow->mfSet(true, NULL, VPF_DONTSETMATRICES);
|
|
m_RP.m_VPTexShadow->mfSetVariables(false, NULL);
|
|
m_RP.m_RCTexShadow->mfSet(true, NULL);
|
|
#ifndef PIPE_USE_INSTANCING
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Bump shadow pass %d [light %d]\n", m_RP.m_RendPass, nLight);
|
|
#endif
|
|
|
|
m_RP.m_VPTexShadow->mfSetStateMatrices();
|
|
m_RP.m_VPTexShadow->mfSetVariables(true, NULL);
|
|
m_RP.m_RCTexShadow->mfSetVariables(true, NULL);
|
|
EF_Draw(m_RP.m_pShader, NULL);
|
|
#else
|
|
EF_PreDraw(NULL);
|
|
|
|
int nObj = 0;
|
|
CCObject *pSaveObj = m_RP.m_pCurObject;
|
|
CCObject *pObj = pSaveObj;
|
|
while (true)
|
|
{
|
|
if (nObj)
|
|
{
|
|
m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj];
|
|
pObj = m_RP.m_pCurObject;
|
|
m_RP.m_FrameObject++;
|
|
}
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
{
|
|
Vec3d vPos = pObj->GetTranslation();
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Bump shadow pass %d [light %d] (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, nLight, m_RP.m_pCurObject->m_VisId, vPos[0], vPos[1], vPos[2]);
|
|
}
|
|
#endif
|
|
|
|
if (m_RP.m_VPTexShadow)
|
|
{
|
|
m_RP.m_VPTexShadow->mfSetStateMatrices();
|
|
m_RP.m_VPTexShadow->mfSetVariables(true, NULL);
|
|
}
|
|
if (m_RP.m_RCTexShadow)
|
|
m_RP.m_RCTexShadow->mfSetVariables(true, NULL);
|
|
|
|
{
|
|
//PROFILE_FRAME(Draw_ShaderIndexMesh);
|
|
if (m_RP.m_pRE)
|
|
m_RP.m_pRE->mfDraw(m_RP.m_pShader, NULL);
|
|
else
|
|
EF_DrawIndexedMesh(R_PRIMV_TRIANGLES);
|
|
}
|
|
nObj++;
|
|
if (nObj >= m_RP.m_MergedObjects.Num())
|
|
break;
|
|
}
|
|
if (pSaveObj != m_RP.m_pCurObject)
|
|
{
|
|
m_RP.m_pCurObject = pSaveObj;
|
|
m_RP.m_FrameObject++;
|
|
}
|
|
#endif
|
|
|
|
CD3D9TexMan::BindNULL(1);
|
|
}
|
|
|
|
// Draw sub-surface scattering passes (used in programmable pipeline shaders only)
|
|
void CD3D9Renderer::EF_DrawSubsurfacePasses(SShaderTechnique *hs, SShader *ef)
|
|
{
|
|
int l;
|
|
|
|
// For each light source
|
|
for (l=0; l<m_RP.m_NumActiveDLights; l++)
|
|
{
|
|
m_RP.m_pCurLight = m_RP.m_pActiveDLights[l];
|
|
m_RP.m_nCurLight = m_RP.m_pCurLight->m_Id;
|
|
|
|
// Ignore diffuse passes for specular only light sources
|
|
if ((m_RP.m_pCurLight->m_Flags & DLF_LM))
|
|
{
|
|
if ((m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_Textures[EFTT_LIGHTMAP_DIR]) || m_RP.m_pCurObject->m_nLMId)
|
|
continue;
|
|
}
|
|
|
|
//// ignore sun ?
|
|
//if ((m_RP.m_pCurLight->m_Flags & DLF_SUN))
|
|
//{
|
|
// continue;
|
|
//}
|
|
|
|
EF_SetState(GS_BLSRC_ONE | GS_BLDST_ONE);
|
|
//EF_SetState(GS_BLSRC_ONEMINUSDSTALPHA | GS_BLDST_ONE);
|
|
|
|
|
|
CVProgram *m_VP;
|
|
CPShader *m_RC;
|
|
if (!m_RP.m_VPSubSurfaceScatering)
|
|
m_RP.m_VPSubSurfaceScatering= CVProgram::mfForName("CGVProgSubSurface");
|
|
if (!m_RP.m_RCSubSurfaceScatering)
|
|
m_RP.m_RCSubSurfaceScatering= CPShader::mfForName("CGRCSubSurface");
|
|
if (!m_RP.m_VPSubSurfaceScatering_pp)
|
|
m_RP.m_VPSubSurfaceScatering_pp= CVProgram::mfForName("CGVProgSubSurface_pp");
|
|
if (!m_RP.m_RCSubSurfaceScatering_pp)
|
|
m_RP.m_RCSubSurfaceScatering_pp= CPShader::mfForName("CGRCSubSurface_pp");
|
|
|
|
// setup texture stages textures
|
|
STexPic *pSubSurfaceTex = m_RP.m_pShaderResources->m_Textures[EFTT_SUBSURFACE]->m_TU.m_TexPic;
|
|
EF_SelectTMU(0);
|
|
pSubSurfaceTex->Set();
|
|
|
|
STexPic *pBumpTex = m_RP.m_pShaderResources->m_Textures[EFTT_BUMP]->m_TU.m_TexPic;
|
|
if(pBumpTex)
|
|
{
|
|
EF_SelectTMU(1);
|
|
SetLodBias(-1.5);
|
|
pBumpTex->Set();
|
|
}
|
|
|
|
STexPic *pNormalizationCubeMapTex=gRenDev->m_TexMan->m_Text_NormalizeCMap;
|
|
EF_SelectTMU(2);
|
|
pNormalizationCubeMapTex->Set();
|
|
|
|
if(CRenderer::CV_r_subsurface_type==0 || !pBumpTex)
|
|
{
|
|
m_VP=m_RP.m_VPSubSurfaceScatering;
|
|
m_RC=m_RP.m_RCSubSurfaceScatering;
|
|
}
|
|
|
|
// make sure to only use per-pixel subsurface scatering, when model has normal map texture
|
|
if(CRenderer::CV_r_subsurface_type==1 && pBumpTex)
|
|
{
|
|
m_VP=m_RP.m_VPSubSurfaceScatering_pp;
|
|
m_RC=m_RP.m_RCSubSurfaceScatering_pp;
|
|
}
|
|
|
|
if(!m_VP || !m_RC)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_VP->mfSet(true, NULL);
|
|
m_VP->mfSetVariables(false, NULL);
|
|
m_RC->mfSet(true, NULL);
|
|
m_RC->mfSetVariables(false, NULL);
|
|
|
|
#ifndef PIPE_USE_INSTANCING
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Subsurface scattering pass %d [light %d]\n", m_RP.m_RendPass, l);
|
|
#endif
|
|
|
|
m_VP->mfSetVariables(true, NULL);
|
|
m_RC->mfSetVariables(true, NULL);
|
|
EF_Draw(m_RP.m_pShader, NULL);
|
|
#else
|
|
EF_PreDraw(NULL);
|
|
|
|
int nObj = 0;
|
|
CCObject *pSaveObj = m_RP.m_pCurObject;
|
|
CCObject *pObj = pSaveObj;
|
|
while (true)
|
|
{
|
|
if (nObj)
|
|
{
|
|
m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj];
|
|
pObj = m_RP.m_pCurObject;
|
|
m_RP.m_FrameObject++;
|
|
}
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
{
|
|
Vec3d vPos = pObj->GetTranslation();
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Subsurface scattering pass %d [light %d] (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, l, m_RP.m_pCurObject->m_VisId, vPos[0], vPos[1], vPos[2]);
|
|
}
|
|
#endif
|
|
|
|
m_VP->mfSetStateMatrices();
|
|
m_VP->mfSetVariables(true, NULL);
|
|
m_RC->mfSetVariables(true, NULL);
|
|
|
|
{
|
|
//PROFILE_FRAME(Draw_ShaderIndexMesh);
|
|
if (m_RP.m_pRE)
|
|
m_RP.m_pRE->mfDraw(m_RP.m_pShader, NULL);
|
|
else
|
|
EF_DrawIndexedMesh(R_PRIMV_TRIANGLES);
|
|
}
|
|
nObj++;
|
|
if (nObj >= m_RP.m_MergedObjects.Num())
|
|
break;
|
|
}
|
|
if (pSaveObj != m_RP.m_pCurObject)
|
|
{
|
|
m_RP.m_pCurObject = pSaveObj;
|
|
m_RP.m_FrameObject++;
|
|
}
|
|
|
|
EF_SelectTMU(1);
|
|
SetLodBias(0);
|
|
#endif
|
|
}
|
|
CD3D9TexMan::BindNULL(1);
|
|
}
|
|
|
|
// Flush HW shader technique (used in FP shaders and in programmable pipeline shaders)
|
|
void CD3D9Renderer::EF_FlushHW()
|
|
{
|
|
SShader *ef = m_RP.m_pShader;
|
|
int i;
|
|
|
|
int nPolys = m_nPolygons;
|
|
|
|
if (m_RP.m_ObjFlags & FOB_SELECTED)
|
|
{
|
|
int nnn = 0;
|
|
}
|
|
|
|
if (m_RP.m_pRE || (m_RP.m_RendNumIndices && m_RP.m_RendNumVerts))
|
|
{
|
|
if (m_RP.m_pShaderResources)
|
|
m_RP.m_pCurLightMaterial = m_RP.m_pShaderResources->m_LMaterial;
|
|
else
|
|
if (ef->m_Flags2 & EF2_USELIGHTMATERIAL)
|
|
m_RP.m_pCurLightMaterial = &m_RP.m_DefLightMaterial;
|
|
else
|
|
m_RP.m_pCurLightMaterial = NULL;
|
|
|
|
// Set Z-Bias
|
|
if (ef->m_Flags & EF_POLYGONOFFSET)
|
|
{
|
|
if (m_d3dCaps.RasterCaps & (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS))
|
|
{
|
|
float fOffs = (float)CV_d3d9_decaloffset;
|
|
m_pd3dDevice->SetRenderState( D3DRS_DEPTHBIAS, *(DWORD*)(&fOffs) );
|
|
}
|
|
}
|
|
|
|
SShaderTechnique *hs = m_RP.m_pCurTechnique;
|
|
if (!hs)
|
|
return;
|
|
|
|
if (m_RP.m_pRE)
|
|
{
|
|
SRenderShaderResources *Res = m_RP.m_pShaderResources;
|
|
int nFlags = hs->m_Flags;
|
|
if (Res && Res->m_bNeedNormals)
|
|
nFlags |= SHPF_NORMALS;
|
|
if (ef->m_eSort == eS_TerrainLightPass || ef->m_eSort == eS_Terrain)
|
|
nFlags |= FHF_TERRAIN;
|
|
m_RP.m_pRE->mfCheckUpdate(ef->m_VertexFormatId, nFlags);
|
|
}
|
|
|
|
if (ef->m_Flags & EF_NEEDNORMALS)
|
|
EF_EvalNormalsRB(ef);
|
|
EF_Eval_DeformVerts(ef->m_Deforms);
|
|
|
|
// Set culling mode
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_NOCULL))
|
|
{
|
|
if (hs->m_eCull != -1)
|
|
D3DSetCull(hs->m_eCull);
|
|
else
|
|
D3DSetCull(ef->m_eCull);
|
|
}
|
|
|
|
EF_SetVertexStreams(hs->m_Pointers, 1);
|
|
EF_ApplyMatrixOps(hs->m_MatrixOps, true);
|
|
|
|
// Draw shader passes
|
|
bool bLights = false;
|
|
if (hs->m_Passes.Num())
|
|
{
|
|
int nStart = 0;
|
|
EShaderPassType eShPass = m_SHPTable[hs->m_Passes[0].m_ePassType];
|
|
|
|
for (i=1; i<hs->m_Passes.Num(); i++)
|
|
{
|
|
if (m_SHPTable[hs->m_Passes[i].m_ePassType] != eShPass)
|
|
{
|
|
int nEnd = i-1;
|
|
bLights |= EF_DrawPasses(eShPass, hs, ef, nStart, nEnd);
|
|
i = nEnd+1;
|
|
nStart = i;
|
|
if (i >= hs->m_Passes.Num())
|
|
break;
|
|
eShPass = m_SHPTable[hs->m_Passes[i].m_ePassType];
|
|
}
|
|
}
|
|
if (i-nStart > 0)
|
|
{
|
|
int nEnd = i-1;
|
|
bLights |= EF_DrawPasses(eShPass, hs, ef, nStart, nEnd);
|
|
}
|
|
}
|
|
if (bLights)
|
|
{
|
|
if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_Textures[EFTT_SUBSURFACE])
|
|
EF_DrawSubsurfacePasses(hs, ef);
|
|
}
|
|
|
|
// Restore matrix transform states
|
|
EF_ApplyMatrixOps(hs->m_MatrixOps, false);
|
|
|
|
// Reset Z-Bias
|
|
if (ef->m_Flags & EF_POLYGONOFFSET)
|
|
{
|
|
if (m_d3dCaps.RasterCaps & (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS))
|
|
m_pd3dDevice->SetRenderState(D3DRS_DEPTHBIAS, 0);
|
|
}
|
|
|
|
// Draw detail texture passes
|
|
if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_Textures[EFTT_DETAIL_OVERLAY] && CV_r_detailtextures)
|
|
EF_DrawDetailOverlayPasses();
|
|
|
|
// Draw volumetric fog passes
|
|
if (m_RP.m_pFogVolume && CV_r_VolumetricFog)
|
|
EF_DrawFogOverlayPasses();
|
|
}
|
|
}
|
|
|
|
// Set/Restore shader resources overrided states
|
|
bool CD3D9Renderer::EF_SetResourcesState(bool bSet)
|
|
{
|
|
if (m_RP.m_pShader->m_Flags2 & EF2_IGNORERESOURCESTATES)
|
|
return true;
|
|
|
|
bool bRes = true;
|
|
if (bSet)
|
|
{
|
|
if (m_RP.m_pShaderResources->m_ResFlags & MTLFLAG_2SIDED)
|
|
{
|
|
D3DSetCull(eCULL_None);
|
|
m_RP.m_FlagsPerFlush |= RBSI_NOCULL;
|
|
}
|
|
if ((m_RP.m_pShaderResources->m_AlphaRef) && !(m_RP.m_ObjFlags & FOB_FOGPASS))
|
|
{
|
|
if (!(m_CurState & GS_ALPHATEST_MASK))
|
|
m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
|
|
m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF, (DWORD)(m_RP.m_pShaderResources->m_AlphaRef*255.0f));
|
|
m_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
|
|
m_RP.m_FlagsPerFlush |= RBSI_ALPHATEST;
|
|
m_CurState |= GS_ALPHATEST_GEQUAL128;
|
|
}
|
|
if (m_RP.m_pShaderResources->m_Opacity != 1.0f)
|
|
{
|
|
int State = m_CurState &= ~GS_BLEND_MASK;
|
|
byte bCol = (byte)(m_RP.m_pShaderResources->m_Opacity*255.0f);
|
|
if (m_RP.m_pShaderResources->m_ResFlags & MTLFLAG_ADDITIVE)
|
|
{
|
|
State |= GS_BLSRC_ONE | GS_BLDST_ONE;
|
|
State &= ~GS_DEPTHWRITE;
|
|
m_RP.m_FlagsPerFlush |= RBSI_GLOBALRGB;
|
|
m_RP.m_NeedGlobalColor.bcolor[0] = bCol;
|
|
m_RP.m_NeedGlobalColor.bcolor[1] = bCol;
|
|
m_RP.m_NeedGlobalColor.bcolor[2] = bCol;
|
|
}
|
|
else
|
|
{
|
|
State |= GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;
|
|
State &= ~GS_DEPTHWRITE;
|
|
m_RP.m_FlagsPerFlush |= RBSI_GLOBALALPHA;
|
|
m_RP.m_NeedGlobalColor.bcolor[3] = bCol;
|
|
}
|
|
EF_SetState(State);
|
|
m_RP.m_ResourceState = State;
|
|
|
|
m_RP.m_fCurOpacity = m_RP.m_pShaderResources->m_Opacity;
|
|
|
|
m_RP.m_FlagsPerFlush |= RBSI_ALPHABLEND | RBSI_DEPTHWRITE | RBSI_ALPHAGEN;
|
|
m_RP.m_ObjFlags &= ~FOB_LIGHTPASS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((m_RP.m_pShaderResources->m_AlphaRef) && !(m_RP.m_ObjFlags & FOB_FOGPASS))
|
|
{
|
|
switch (m_CurState & GS_ALPHATEST_MASK)
|
|
{
|
|
case GS_ALPHATEST_GREATER0:
|
|
m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
|
|
m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF, 0);
|
|
m_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
|
|
break;
|
|
|
|
case GS_ALPHATEST_LESS128:
|
|
m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
|
|
m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF, 0x80);
|
|
m_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESS);
|
|
break;
|
|
|
|
case GS_ALPHATEST_GEQUAL128:
|
|
m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
|
|
m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF, 0x80);
|
|
m_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
|
|
break;
|
|
|
|
default:
|
|
m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Set overrided shader states from State shader
|
|
void CD3D9Renderer::EF_SetStateShaderState()
|
|
{
|
|
SShader *ef = m_RP.m_pStateShader;
|
|
SEfState *st = ef->m_State;
|
|
|
|
if (st->m_bClearStencil)
|
|
m_pd3dDevice->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 1.0f, 0);
|
|
|
|
if (st->m_Stencil)
|
|
st->m_Stencil->mfSet();
|
|
if (st->m_Flags & ESF_NOCULL)
|
|
{
|
|
D3DSetCull(eCULL_None);
|
|
m_RP.m_FlagsPerFlush |= RBSI_NOCULL;
|
|
}
|
|
else
|
|
if (st->m_Flags & ESF_CULLFRONT)
|
|
{
|
|
D3DSetCull(eCULL_Front);
|
|
m_RP.m_FlagsPerFlush |= RBSI_NOCULL;
|
|
}
|
|
|
|
if (st->m_Flags & ESF_STATE)
|
|
{
|
|
EF_SetState(st->m_State);
|
|
if (st->m_State & GS_NODEPTHTEST)
|
|
m_RP.m_FlagsPerFlush |= RBSI_DEPTHTEST;
|
|
if (st->m_State & (GS_DEPTHFUNC_EQUAL | GS_DEPTHFUNC_GREAT))
|
|
m_RP.m_FlagsPerFlush |= RBSI_DEPTHFUNC;
|
|
}
|
|
bool bSetCol = false;
|
|
UCol Col;
|
|
Col.dcolor = 0;
|
|
if (st->m_Flags & ESF_RGBGEN)
|
|
{
|
|
m_RP.m_FlagsPerFlush |= RBSI_RGBGEN;
|
|
switch (st->m_eEvalRGB)
|
|
{
|
|
case eERGB_Fixed:
|
|
Col.bcolor[0] = st->m_FixedColor[0];
|
|
Col.bcolor[1] = st->m_FixedColor[1];
|
|
Col.bcolor[2] = st->m_FixedColor[2];
|
|
Col.bcolor[3] = st->m_FixedColor[3];
|
|
break;
|
|
}
|
|
bSetCol = true;
|
|
}
|
|
if (st->m_Flags & ESF_ALPHAGEN)
|
|
{
|
|
m_RP.m_FlagsPerFlush |= RBSI_ALPHAGEN;
|
|
switch (st->m_eEvalAlpha)
|
|
{
|
|
case eEALPHA_Fixed:
|
|
Col.bcolor[3] = st->m_FixedColor[3];
|
|
break;
|
|
}
|
|
bSetCol = true;
|
|
}
|
|
if (bSetCol)
|
|
{
|
|
Exchange(Col.bcolor[0], Col.bcolor[3]);
|
|
m_RP.m_NeedGlobalColor = Col;
|
|
}
|
|
if (st->m_Flags & ESF_COLORMASK)
|
|
{
|
|
m_RP.m_FlagsPerFlush |= RBSI_COLORMASK;
|
|
int mask = 0;
|
|
for (int i=0; i<4; i++)
|
|
{
|
|
if (st->m_ColorMask[i])
|
|
mask |= 1<<i;
|
|
}
|
|
m_pd3dDevice->SetRenderState(D3DRS_COLORWRITEENABLE, mask);
|
|
}
|
|
}
|
|
|
|
// Reset overrided shader states from State shader
|
|
void CD3D9Renderer::EF_ResetStateShaderState()
|
|
{
|
|
SShader *ef = m_RP.m_pStateShader;
|
|
SEfState *st = ef->m_State;
|
|
|
|
if (st->m_Flags & ESF_COLORMASK)
|
|
m_pd3dDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0xf);
|
|
|
|
if (st->m_Flags & ESF_POLYLINE)
|
|
m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
|
|
}
|
|
|
|
// Flush current shader
|
|
void CD3D9Renderer::EF_FlushShader()
|
|
{
|
|
SShader *ef = m_RP.m_pShader;
|
|
int i;
|
|
SShaderPass *slw;
|
|
|
|
if (m_RP.m_pRE) // Without buffer fill
|
|
{
|
|
EF_InitEvalFuncs(1); // VP
|
|
if (CV_r_rb_merge < 0)
|
|
return;
|
|
}
|
|
else
|
|
{ // Buffer filling
|
|
EF_InitEvalFuncs(0);
|
|
if (!m_RP.m_RendNumIndices)
|
|
return;
|
|
|
|
if ((ef->m_Flags & EF_FOGSHADER) && !m_RP.m_pFogVolume)
|
|
return;
|
|
|
|
if (m_RP.m_RendNumIndices > m_RP.m_MaxTris*3)
|
|
{
|
|
iLog->Log("CD3D9Renderer::EF_FlushShader: Shader MaxTris hit for batched RenderElements\n");
|
|
m_RP.m_RendNumIndices = m_RP.m_MaxTris*3;
|
|
}
|
|
if (m_RP.m_RendNumVerts > m_RP.m_MaxVerts)
|
|
{
|
|
iLog->Log("CD3D9Renderer::EF_FlushShader: Shader MaxVerts hit for batched RenderElements\n");
|
|
m_RP.m_RendNumVerts = m_RP.m_MaxVerts;
|
|
}
|
|
}
|
|
|
|
m_RP.m_ResourceState = 0;
|
|
if (m_RP.m_pShaderResources)
|
|
{
|
|
if (!EF_SetResourcesState(true))
|
|
return;
|
|
}
|
|
|
|
if (m_RP.m_pStateShader && m_RP.m_pStateShader->m_State)
|
|
EF_SetStateShaderState();
|
|
|
|
bool bDraw2D = false;
|
|
if (!(m_RP.m_Flags & RBF_2D) && (m_RP.m_FlagsPerFlush & RBSI_DRAWAS2D))
|
|
{
|
|
bDraw2D = true;
|
|
Set2DMode(true,800,600);
|
|
}
|
|
|
|
// Draw using HW shader
|
|
if (ef->m_HWTechniques.Num())
|
|
{
|
|
EF_FlushHW();
|
|
if (m_RP.m_pStateShader && m_RP.m_pStateShader->m_State)
|
|
EF_ResetStateShaderState();
|
|
if (m_RP.m_pShaderResources)
|
|
EF_SetResourcesState(false);
|
|
if (bDraw2D)
|
|
Set2DMode(false,800,600);
|
|
return;
|
|
}
|
|
|
|
if ((ef->m_Flags & EF_FOGSHADER) && !m_RP.m_pFogVolume)
|
|
{
|
|
if (m_RP.m_pStateShader && m_RP.m_pStateShader->m_State)
|
|
EF_ResetStateShaderState();
|
|
if (m_RP.m_pShaderResources)
|
|
EF_SetResourcesState(false);
|
|
if (bDraw2D)
|
|
Set2DMode(false,800,600);
|
|
return;
|
|
}
|
|
|
|
// In common shaders we don't have pixel or vertex shaders
|
|
m_RP.m_PersFlags &= ~(RBPF_PS1NEEDSET | RBPF_VSNEEDSET);
|
|
CD3D9TexMan::BindNULL(1);
|
|
EF_SelectTMU(0);
|
|
EF_Scissor(false, 0, 0, 0, 0);
|
|
|
|
if (ef->m_Flags & EF_NEEDNORMALS)
|
|
EF_EvalNormalsRB(ef);
|
|
EF_Eval_DeformVerts(ef->m_Deforms);
|
|
|
|
if (ef->m_Flags & EF_POLYGONOFFSET)
|
|
{
|
|
if (m_d3dCaps.RasterCaps & (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS))
|
|
{
|
|
float fOffs = (float)CV_d3d9_decaloffset;
|
|
m_pd3dDevice->SetRenderState( D3DRS_DEPTHBIAS, *(DWORD*)&fOffs );
|
|
}
|
|
}
|
|
|
|
if (!(m_RP.m_FlagsPerFlush & RBSI_NOCULL))
|
|
D3DSetCull(ef->m_eCull);
|
|
|
|
int nPolys = m_nPolygons;
|
|
|
|
if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_LMaterial)
|
|
m_RP.m_pShaderResources->m_LMaterial->mfApply(ef->m_LMFlags);
|
|
else
|
|
m_RP.m_CurrentVLights = 0;
|
|
|
|
m_RP.m_StatNumPasses += ef->m_Passes.Num();
|
|
slw = &ef->m_Passes[0];
|
|
for (i=0; i<ef->m_Passes.Num(); i++, slw++)
|
|
{
|
|
EF_Eval_TexGen(slw);
|
|
EF_Eval_RGBAGen(slw);
|
|
|
|
// Set all textures and HW TexGen modes for the current pass (ShadeLayer)
|
|
if (slw->mfSetTextures())
|
|
{
|
|
int nState;
|
|
|
|
// Set Render states for the current pass
|
|
if (m_RP.m_RendPass || (m_RP.m_pCurObject->m_ObjFlags & FOB_LIGHTPASS))
|
|
nState = slw->m_SecondRenderState;
|
|
else
|
|
nState = slw->m_RenderState;
|
|
EF_SetState(nState);
|
|
|
|
#ifndef PIPE_USE_INSTANCING
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Pass %d \n", m_RP.m_RendPass);
|
|
#endif
|
|
|
|
// Set scissor rect
|
|
m_RP.m_pCurObject->SetScissor();
|
|
|
|
EF_Draw(ef, slw);
|
|
|
|
m_RP.m_RendPass++;
|
|
|
|
#else //PIPE_USE_INSTANCING
|
|
m_RP.m_RendPass++;
|
|
|
|
int bFogOverrided = 0;
|
|
// Unlock all VB (if needed) and set current streams
|
|
EF_PreDraw(slw);
|
|
if (m_FS.m_bEnable)
|
|
bFogOverrided = EF_FogCorrection(false, false);
|
|
|
|
int nObj = 0;
|
|
CCObject *pSaveObj = m_RP.m_pCurObject;
|
|
CCObject *pObj = pSaveObj;
|
|
bool bLightSicssorWasSet = false;
|
|
|
|
while (true)
|
|
{
|
|
if (nObj)
|
|
{
|
|
// Object changed
|
|
m_RP.m_pCurObject = m_RP.m_MergedObjects[nObj];
|
|
pObj = m_RP.m_pCurObject;
|
|
m_RP.m_FrameObject++;
|
|
EF_SetObjectTransform(pObj, ef, pObj->m_ObjFlags);
|
|
if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_LMaterial)
|
|
m_RP.m_pShaderResources->m_LMaterial->mfApply(ef->m_LMFlags);
|
|
}
|
|
// Set scissor rect
|
|
if (!(m_RP.m_ObjFlags & FOB_NOSCISSOR))
|
|
pObj->SetScissor();
|
|
else
|
|
EF_Scissor(false, 0, 0, 0, 0);
|
|
|
|
// Set per-object alpha blending state
|
|
if (pObj->m_ObjFlags & FOB_HASALPHA)
|
|
pObj->SetAlphaState(NULL, nState);
|
|
|
|
// Commit per-texture states / color ops
|
|
EF_CommitTexStageState();
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CRenderer::CV_r_log >= 3)
|
|
{
|
|
Vec3d vPos = pObj->GetTranslation();
|
|
Logv(SRendItem::m_RecurseLevel, "+++ Pass %d (Obj: %d [%.3f, %.3f, %.3f])\n", m_RP.m_RendPass, m_RP.m_pCurObject->m_VisId, vPos[0], vPos[1], vPos[2]);
|
|
}
|
|
#endif
|
|
{
|
|
//PROFILE_FRAME(Draw_ShaderIndexMesh);
|
|
if (m_RP.m_pRE)
|
|
m_RP.m_pRE->mfDraw(ef, slw);
|
|
else
|
|
EF_DrawIndexedMesh(R_PRIMV_TRIANGLES);
|
|
}
|
|
nObj++;
|
|
if (nObj >= m_RP.m_MergedObjects.Num())
|
|
break;
|
|
}
|
|
EF_FogRestore(bFogOverrided);
|
|
if (!CVProgram::m_LastVP)
|
|
{
|
|
if (m_RP.m_FlagsModificators & (RBMF_TCM | RBMF_TCG))
|
|
EF_CommitTexTransforms(false);
|
|
}
|
|
else
|
|
m_RP.m_FlagsModificators &= ~(RBMF_TCM | RBMF_TCG);
|
|
if (pSaveObj != m_RP.m_pCurObject)
|
|
{
|
|
m_RP.m_pCurObject = pSaveObj;
|
|
m_RP.m_FrameObject++;
|
|
EF_SetObjectTransform(pSaveObj, ef, pSaveObj->m_ObjFlags);
|
|
}
|
|
#endif
|
|
}
|
|
slw->mfResetTextures();
|
|
}
|
|
|
|
if (m_RP.m_pShaderResources && m_RP.m_pShaderResources->m_Textures[EFTT_DETAIL_OVERLAY] && CV_r_detailtextures)
|
|
EF_DrawDetailOverlayPasses();
|
|
|
|
if (m_RP.m_pFogVolume && CV_r_VolumetricFog)
|
|
EF_DrawFogOverlayPasses();
|
|
|
|
if (ef->m_Flags & EF_POLYGONOFFSET)
|
|
{
|
|
if (m_d3dCaps.RasterCaps & (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS))
|
|
m_pd3dDevice->SetRenderState(D3DRS_DEPTHBIAS, 0);
|
|
}
|
|
|
|
if (m_RP.m_pStateShader && m_RP.m_pStateShader->m_State)
|
|
EF_ResetStateShaderState();
|
|
if (m_RP.m_pShaderResources)
|
|
EF_SetResourcesState(false);
|
|
|
|
if (bDraw2D)
|
|
Set2DMode(false,800,600);
|
|
}
|
|
|
|
// Flush current render item
|
|
void CD3D9Renderer::EF_Flush()
|
|
{
|
|
CD3D9Renderer *rd = gcpRendD3D;
|
|
SShader *ef = rd->m_RP.m_pShader;
|
|
if (rd->m_RP.m_ExcludeShader)
|
|
{
|
|
if (!strcmp(rd->m_RP.m_ExcludeShader, ef->m_Name.c_str()))
|
|
return;
|
|
if(rd->m_RP.m_ExcludeShader[0] == '#')
|
|
if (strstr(ef->m_Name.c_str(), rd->m_RP.m_ExcludeShader))
|
|
return;
|
|
}
|
|
|
|
if (rd->m_RP.m_ShowOnlyShader)
|
|
{
|
|
if (strcmp(rd->m_RP.m_ShowOnlyShader, ef->m_Name.c_str()))
|
|
return;
|
|
}
|
|
|
|
//if ((int)rd->m_RP.m_pRE != 0xed45090)
|
|
// return;
|
|
|
|
/*{
|
|
Vec3d vObj = rd->m_RP.m_pCurObject->GetTranslation();
|
|
Vec3d vv = Vec3d(1170.025, 1396.100, 74.500);
|
|
//if ((vv-vObj).GetLength() > 0.1f)
|
|
// return;
|
|
}*/
|
|
|
|
if (ef->m_nPreprocess)
|
|
{
|
|
if(ef->m_nPreprocess & FSPR_PORTAL)
|
|
{
|
|
if (CV_r_portals && (rd->m_RP.m_PersFlags & (RBPF_DRAWPORTAL | RBPF_DRAWMIRROR)))
|
|
return;
|
|
}
|
|
if(ef->m_nPreprocess & FSPR_HEATVIS)
|
|
{
|
|
if (rd->m_RP.m_PersFlags & RBPF_DRAWHEATMAP)
|
|
rd->m_TexMan->EndHeatMap();
|
|
}
|
|
if(ef->m_nPreprocess & FSPR_SCANSCR)
|
|
{
|
|
if (rd->m_RP.m_PersFlags & RBPF_DRAWSCREENMAP)
|
|
rd->m_TexMan->EndScreenMap();
|
|
}
|
|
if(ef->m_nPreprocess & FSPR_SCREENTEXMAP)
|
|
{
|
|
if (rd->m_RP.m_PersFlags & RBPF_DRAWSCREENTEXMAP)
|
|
{
|
|
rd->m_TexMan->EndScreenTexMap();
|
|
// reset flag state
|
|
rd->m_RP.m_PersFlags&= ~RBPF_IGNOREREFRACTED;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (rd->m_LogFile && CV_r_log == 3)
|
|
rd->Logv(SRendItem::m_RecurseLevel, ".. Start Flush: '%s' ..\n", ef->m_Name.c_str());
|
|
#endif
|
|
|
|
rd->m_RP.m_StatNumLightPasses = 0;
|
|
rd->m_RP.m_StatNumLights = 0;
|
|
rd->m_RP.m_StatNumPasses = 0;
|
|
rd->m_RP.m_StatLightMask = 0;
|
|
|
|
rd->m_RP.m_PS.m_NumRendBatches++;
|
|
#ifdef PIPE_USE_INSTANCING
|
|
if (rd->m_RP.m_MergedObjects.Num())
|
|
rd->m_RP.m_PS.m_NumRendItems += rd->m_RP.m_MergedObjects.Num();
|
|
else
|
|
#endif
|
|
rd->m_RP.m_PS.m_NumRendItems++;
|
|
|
|
CCObject *obj = rd->m_RP.m_pCurObject;
|
|
int VPMId, IMId;
|
|
if (!(rd->m_RP.m_ObjFlags & FOB_TRANS_MASK))
|
|
{
|
|
VPMId = rd->m_RP.m_pCurObject->m_VPMatrixId;
|
|
IMId = rd->m_RP.m_pCurObject->m_InvMatrixId;
|
|
rd->m_RP.m_pCurObject->m_VPMatrixId = 0;
|
|
rd->m_RP.m_pCurObject->m_InvMatrixId = 0;
|
|
}
|
|
|
|
/*if (ef->m_eSort == eS_Water)
|
|
{
|
|
obj->m_DynLMMask |= 1;
|
|
}*/
|
|
rd->m_RP.m_DynLMask = CV_r_hwlights ? obj->m_DynLMMask : 0;
|
|
|
|
if (!(ef->m_Flags & EF_HASVSHADER))
|
|
rd->EF_SetObjectTransform(obj, ef, rd->m_RP.m_ObjFlags);
|
|
|
|
if (CV_r_showlight->GetString()[0] != '0')
|
|
{
|
|
for (int i=0; i<rd->m_RP.m_DLights[SRendItem::m_RecurseLevel].Num(); i++)
|
|
{
|
|
CDLight *dl = rd->m_RP.m_DLights[SRendItem::m_RecurseLevel][i];
|
|
if (!dl)
|
|
continue;
|
|
char *str = CV_r_showlight->GetString();
|
|
if (strcmp(str, "0") != 0)
|
|
{
|
|
if (!dl->m_Name || !strstr(dl->m_Name, str))
|
|
rd->m_RP.m_DynLMask &= ~(1<<i);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((ef->m_Flags3 & EF3_CLIPPLANE) && !(rd->m_RP.m_PersFlags & RBPF_SETCLIPPLANE) && !rd->m_RP.m_ClipPlaneEnabled)
|
|
{
|
|
switch (ef->m_Flags3 & EF3_CLIPPLANE)
|
|
{
|
|
case EF3_CLIPPLANE_WATER_FRONT:
|
|
case EF3_CLIPPLANE_WATER_BACK:
|
|
{
|
|
SPlane Pl;
|
|
Pl.m_Normal = Vec3d (0, 0, 1);
|
|
Pl.m_Dist = iSystem->GetI3DEngine()->GetWaterLevel();
|
|
if (ef->m_Flags3 & EF3_CLIPPLANE_WATER_BACK)
|
|
{
|
|
Pl.m_Normal = -Pl.m_Normal;
|
|
Pl.m_Dist = -Pl.m_Dist;
|
|
}
|
|
Pl.m_Dist = -Pl.m_Dist;
|
|
rd->EF_SetClipPlane(true, &Pl.m_Normal.x, false);
|
|
rd->m_RP.m_PersFlags |= RBPF_SETCLIPPLANE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (!(ef->m_Flags3 & EF3_CLIPPLANE) && (rd->m_RP.m_PersFlags & RBPF_SETCLIPPLANE))
|
|
{
|
|
rd->EF_SetClipPlane(false, NULL, false);
|
|
rd->m_RP.m_PersFlags &= ~RBPF_SETCLIPPLANE;
|
|
}
|
|
|
|
#ifdef DO_RENDERLOG
|
|
bool bProfile;
|
|
double time0 = 0;
|
|
int nNumPolys = rd->m_nPolygons;
|
|
if (CRenderer::CV_r_profileshaders || CRenderer::CV_r_log>=2)
|
|
{
|
|
bProfile = true;
|
|
ticks(time0);
|
|
}
|
|
else
|
|
bProfile = false;
|
|
|
|
if (rd->m_LogFile && CV_r_log >= 3)
|
|
rd->Logv(SRendItem::m_RecurseLevel, "\n");
|
|
#endif
|
|
|
|
rd->EF_FlushShader();
|
|
|
|
if (rd->m_RP.m_DynLMask)
|
|
rd->m_RP.m_PS.m_NumLitShaders++;
|
|
|
|
if (!(rd->m_RP.m_ObjFlags & FOB_TRANS_MASK))
|
|
{
|
|
rd->m_RP.m_pCurObject->m_VPMatrixId = VPMId;
|
|
rd->m_RP.m_pCurObject->m_InvMatrixId = IMId;
|
|
}
|
|
|
|
#ifdef DO_RENDERLOG
|
|
nNumPolys = rd->m_nPolygons - nNumPolys;
|
|
|
|
if (bProfile)
|
|
{
|
|
unticks(time0);
|
|
time0 = time0*1000.0*g_SecondsPerCycle;
|
|
}
|
|
|
|
if (CRenderer::CV_r_profileshaders)
|
|
{
|
|
if (CRenderer::CV_r_profileshaders == 1 || (rd->m_RP.m_ObjFlags & FOB_SELECTED))
|
|
{
|
|
SProfInfo pi;
|
|
pi.Time = time0;
|
|
pi.NumPolys = nNumPolys;
|
|
pi.ef = ef;
|
|
pi.m_nItems = 0;
|
|
rd->m_RP.m_Profile.AddElem(pi);
|
|
}
|
|
}
|
|
|
|
|
|
if (rd->m_LogFile)
|
|
{
|
|
if (CV_r_log == 4 && rd->m_RP.m_DynLMask)
|
|
{
|
|
for (int n=0; n<rd->m_RP.m_DLights[SRendItem::m_RecurseLevel].Num(); n++)
|
|
{
|
|
CDLight *dl = rd->m_RP.m_DLights[SRendItem::m_RecurseLevel][n];
|
|
if (rd->m_RP.m_DynLMask & (1<<n))
|
|
rd->Logv(SRendItem::m_RecurseLevel, " Light %d (\"%s\")\n", n, dl->m_Name ? dl->m_Name : "<Unknown>");
|
|
}
|
|
}
|
|
|
|
char *str;
|
|
if (ef->m_HWTechniques.Num())
|
|
str = "FlushHW";
|
|
else
|
|
str = "Flush";
|
|
rd->Logv(SRendItem::m_RecurseLevel, "%s: '%s', (St: %s) Id:%d, ResId:%d, Obj:%d, Tech: %d, Cp: %d, Fog:%d, VF:%d, NL:%d, LPas:%d, Pas:%d (time: %f, %d polys)\n", str, ef->m_Name.c_str(), rd->m_RP.m_pStateShader ? rd->m_RP.m_pStateShader->m_Name.c_str() : "NULL", ef->m_Id, rd->m_RP.m_pShaderResources ? rd->m_RP.m_pShaderResources->m_Id : -1, rd->m_RP.m_pCurObject->m_VisId, rd->m_RP.m_pCurTechnique ? rd->m_RP.m_pCurTechnique->m_Id : -1, rd->m_RP.m_ClipPlaneEnabled, rd->m_RP.m_pFogVolume ? (rd->m_RP.m_pFogVolume-&rd->m_RP.m_FogVolumes[0]) : 0, ef->m_VertexFormatId, rd->m_RP.m_StatNumLights, rd->m_RP.m_StatNumLightPasses, rd->m_RP.m_StatNumPasses, time0, nNumPolys);
|
|
if (rd->m_RP.m_ObjFlags & FOB_SELECTED)
|
|
{
|
|
if (rd->m_RP.m_FlagsPerFlush & RBSI_ALPHATEST)
|
|
rd->Logv(SRendItem::m_RecurseLevel, " %.3f, %.3f, %.3f (0x%x), LM: %d, (AT) (Selected)\n", rd->m_RP.m_pCurObject->m_Matrix(3,0), rd->m_RP.m_pCurObject->m_Matrix(3,1), rd->m_RP.m_pCurObject->m_Matrix(3,2), rd->m_RP.m_pCurObject->m_ObjFlags, rd->m_RP.m_DynLMask);
|
|
else
|
|
if (rd->m_RP.m_FlagsPerFlush & RBSI_ALPHABLEND)
|
|
rd->Logv(SRendItem::m_RecurseLevel, " %.3f, %.3f, %.3f (0x%x) (AB), LM: %d (Dist: %.3f) (Selected)\n", rd->m_RP.m_pCurObject->m_Matrix(3,0), rd->m_RP.m_pCurObject->m_Matrix(3,1), rd->m_RP.m_pCurObject->m_Matrix(3,2), rd->m_RP.m_pCurObject->m_ObjFlags, rd->m_RP.m_DynLMask, rd->m_RP.m_pRE ? rd->m_RP.m_pRE->mfDistanceToCameraSquared(*gRenDev->m_RP.m_pCurObject) : 0);
|
|
else
|
|
rd->Logv(SRendItem::m_RecurseLevel, " %.3f, %.3f, %.3f (0x%x), RE: 0x%x, LM: 0x%x (Selected)\n", rd->m_RP.m_pCurObject->m_Matrix(3,0), rd->m_RP.m_pCurObject->m_Matrix(3,1), rd->m_RP.m_pCurObject->m_Matrix(3,2), rd->m_RP.m_pCurObject->m_ObjFlags, rd->m_RP.m_pRE, rd->m_RP.m_DynLMask);
|
|
}
|
|
else
|
|
{
|
|
if (rd->m_RP.m_FlagsPerFlush & RBSI_ALPHATEST)
|
|
rd->Logv(SRendItem::m_RecurseLevel, " %.3f, %.3f, %.3f (0x%x), LM: %d, (AT)\n", rd->m_RP.m_pCurObject->m_Matrix(3,0), rd->m_RP.m_pCurObject->m_Matrix(3,1), rd->m_RP.m_pCurObject->m_Matrix(3,2), rd->m_RP.m_pCurObject->m_ObjFlags, rd->m_RP.m_DynLMask);
|
|
else
|
|
if (rd->m_RP.m_FlagsPerFlush & RBSI_ALPHABLEND)
|
|
rd->Logv(SRendItem::m_RecurseLevel, " %.3f, %.3f, %.3f (0x%x) (AB), LM: %d (Dist: %.3f)\n", rd->m_RP.m_pCurObject->m_Matrix(3,0), rd->m_RP.m_pCurObject->m_Matrix(3,1), rd->m_RP.m_pCurObject->m_Matrix(3,2), rd->m_RP.m_pCurObject->m_ObjFlags, rd->m_RP.m_DynLMask, rd->m_RP.m_pRE ? rd->m_RP.m_pRE->mfDistanceToCameraSquared(*gRenDev->m_RP.m_pCurObject) : 0);
|
|
else
|
|
rd->Logv(SRendItem::m_RecurseLevel, " %.3f, %.3f, %.3f (0x%x), RE: 0x%x, LM: 0x%x\n", rd->m_RP.m_pCurObject->m_Matrix(3,0), rd->m_RP.m_pCurObject->m_Matrix(3,1), rd->m_RP.m_pCurObject->m_Matrix(3,2), rd->m_RP.m_pCurObject->m_ObjFlags, rd->m_RP.m_pRE, rd->m_RP.m_DynLMask);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Process all render item lists
|
|
void CD3D9Renderer::EF_EndEf3D(int nFlags)
|
|
{
|
|
double time0 = 0;
|
|
ticks(time0);
|
|
|
|
if (m_bDeviceLost)
|
|
{
|
|
SRendItem::m_RecurseLevel--;
|
|
return;
|
|
}
|
|
|
|
assert(SRendItem::m_RecurseLevel >= 1);
|
|
if (SRendItem::m_RecurseLevel < 1)
|
|
{
|
|
iLog->Log("Error: CRenderer::EF_EndEf3D without CRenderer::EF_StartEf");
|
|
return;
|
|
}
|
|
|
|
if (CV_r_nodrawshaders == 1)
|
|
{
|
|
SetClearColor(Vec3d(0,0,0));
|
|
EF_ClearBuffers(false, false, NULL);
|
|
SRendItem::m_RecurseLevel--;
|
|
return;
|
|
}
|
|
|
|
#ifdef USE_HDR
|
|
bool bUseHDR = false;
|
|
if ((nFlags & SHDF_ALLOWHDR) && SRendItem::m_RecurseLevel == 1 && (m_Features & RFT_HW_HDR) && CV_r_hdrrendering && !(m_RP.m_PersFlags & RBPF_MAKESPRITE))
|
|
bUseHDR = true;
|
|
#endif
|
|
m_RP.m_PersFlags &= ~(RBPF_DRAWNIGHTMAP | RBPF_DRAWHEATMAP);
|
|
m_RP.m_RealTime = iTimer->GetCurrTime();
|
|
|
|
if (CV_r_fullbrightness)
|
|
{
|
|
m_RP.m_NeedGlobalColor.dcolor = -1;
|
|
m_RP.m_FlagsPerFlush |= RBSI_RGBGEN | RBSI_ALPHAGEN;
|
|
}
|
|
|
|
if (CV_r_excludeshader->GetString()[0] != '0')
|
|
m_RP.m_ExcludeShader = CV_r_excludeshader->GetString();
|
|
else
|
|
m_RP.m_ExcludeShader = NULL;
|
|
|
|
if (CV_r_showonlyshader->GetString()[0] != '0')
|
|
m_RP.m_ShowOnlyShader = CV_r_showonlyshader->GetString();
|
|
else
|
|
m_RP.m_ShowOnlyShader = NULL;
|
|
|
|
EF_UpdateSplashes(m_RP.m_RealTime);
|
|
EF_AddClientPolys3D();
|
|
EF_AddClientPolys2D();
|
|
|
|
#ifdef USE_HDR
|
|
if (bUseHDR)
|
|
EF_AddEf(0, m_RP.m_pREHDR, CShader::m_ShaderHDRProcess, NULL, NULL, 0, 0, EFSLIST_LAST | eS_HDR);
|
|
#endif
|
|
|
|
SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_PREPROCESS_ID] = SRendItem::m_RendItems[EFSLIST_PREPROCESS_ID].Num();
|
|
SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_STENCIL_ID] = SRendItem::m_RendItems[EFSLIST_STENCIL_ID].Num();
|
|
SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_GENERAL_ID] = SRendItem::m_RendItems[EFSLIST_GENERAL_ID].Num();
|
|
SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_UNSORTED_ID] = SRendItem::m_RendItems[EFSLIST_UNSORTED_ID].Num();
|
|
SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_DISTSORT_ID] = SRendItem::m_RendItems[EFSLIST_DISTSORT_ID].Num();
|
|
SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_LAST_ID] = SRendItem::m_RendItems[EFSLIST_LAST_ID].Num();
|
|
|
|
#ifdef USE_HDR
|
|
CD3D9TexMan *tm = (CD3D9TexMan *)m_TexMan;
|
|
if (bUseHDR)
|
|
{
|
|
if (!tm->m_Text_HDRTarget || tm->m_Text_HDRTarget->m_Width != m_width || tm->m_Text_HDRTarget->m_Height != m_height)
|
|
tm->GenerateHDRMaps();
|
|
// Set float render target for HDR rendering
|
|
if( tm->m_HDR_RT_FSAA )
|
|
{
|
|
assert(!m_pHDRTargetSurf);
|
|
if (!m_pHDRTargetSurf)
|
|
{
|
|
m_pHDRTargetSurf = tm->m_HDR_RT_FSAA;
|
|
m_pHDRTargetSurf->AddRef();
|
|
}
|
|
HRESULT hr = m_pd3dDevice->SetRenderTarget( 0, m_pHDRTargetSurf );
|
|
}
|
|
else
|
|
{
|
|
STexPic *tp = tm->m_Text_HDRTarget;
|
|
LPDIRECT3DTEXTURE9 pTexture = (LPDIRECT3DTEXTURE9)tp->m_RefTex.m_VidTex;
|
|
assert(pTexture);
|
|
assert(!m_pHDRTargetSurf);
|
|
if (!m_pHDRTargetSurf)
|
|
pTexture->GetSurfaceLevel(0, &m_pHDRTargetSurf);
|
|
assert(m_pHDRTargetSurf);
|
|
//D3DSURFACE_DESC dtdsdRT;
|
|
//m_pHDRTargetSurf->GetDesc(&dtdsdRT);
|
|
HRESULT hr = m_pd3dDevice->SetRenderTarget(0, m_pHDRTargetSurf);
|
|
}
|
|
if (m_nHDRType == 2)
|
|
{
|
|
//tp = tm->m_Text_HDRTarget_K;
|
|
//LPDIRECT3DTEXTURE9 pTexture = (LPDIRECT3DTEXTURE9)tp->m_RefTex.m_VidTex;
|
|
//if (!m_pHDRTargetSurf_K)
|
|
// pTexture->GetSurfaceLevel(0, &m_pHDRTargetSurf_K);
|
|
//hr = m_pd3dDevice->SetRenderTarget(1, m_pHDRTargetSurf_K);
|
|
}
|
|
//hr = m_pd3dDevice->SetDepthStencilSurface(m_pTempZBuffer);
|
|
//m_pCurZBuffer = m_pTempZBuffer;
|
|
m_RP.m_PersFlags |= RBPF_HDR;
|
|
}
|
|
else
|
|
if (!CV_r_hdrrendering && tm->m_Text_HDRTarget)
|
|
tm->DestroyHDRMaps();
|
|
#endif
|
|
|
|
EF_RenderPipeLine(EF_Flush);
|
|
|
|
EF_DrawDebugTools();
|
|
EF_RemovePolysFromScene();
|
|
SRendItem::m_RecurseLevel--;
|
|
|
|
unticks(time0);
|
|
m_RP.m_PS.m_fFlushTime += (float)(time0*1000.0*g_SecondsPerCycle);
|
|
}
|
|
|
|
// Process all render item lists
|
|
void CD3D9Renderer::EF_RenderPipeLine(void (*RenderFunc)())
|
|
{
|
|
EF_PipeLine(SRendItem::m_StartRI[SRendItem::m_RecurseLevel-1][EFSLIST_PREPROCESS_ID], SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_PREPROCESS_ID], EFSLIST_PREPROCESS_ID, RenderFunc); // Preprocess and probably sky
|
|
if (!(m_RP.m_PersFlags & RBPF_IGNORERENDERING))
|
|
{
|
|
EF_PipeLine(SRendItem::m_StartRI[SRendItem::m_RecurseLevel-1][EFSLIST_STENCIL_ID], SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_STENCIL_ID], EFSLIST_STENCIL_ID, RenderFunc); // Unsorted list for indoor
|
|
EF_PipeLine(SRendItem::m_StartRI[SRendItem::m_RecurseLevel-1][EFSLIST_GENERAL_ID], SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_GENERAL_ID], EFSLIST_GENERAL_ID, RenderFunc); // Sorted list without preprocess
|
|
EF_PipeLine(SRendItem::m_StartRI[SRendItem::m_RecurseLevel-1][EFSLIST_UNSORTED_ID], SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_UNSORTED_ID], EFSLIST_UNSORTED_ID, RenderFunc); // Unsorted list
|
|
EF_PipeLine(SRendItem::m_StartRI[SRendItem::m_RecurseLevel-1][EFSLIST_DISTSORT_ID], SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_DISTSORT_ID], EFSLIST_DISTSORT_ID, RenderFunc); // Sorted by distance elements
|
|
if (SRendItem::m_RecurseLevel <= 1)
|
|
EF_PipeLine(SRendItem::m_StartRI[SRendItem::m_RecurseLevel-1][EFSLIST_LAST_ID], SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_LAST_ID], EFSLIST_LAST_ID, RenderFunc); // Sorted list without preprocess of all fog passes and screen shaders
|
|
}
|
|
else
|
|
m_RP.m_PersFlags &= ~RBPF_IGNORERENDERING;
|
|
}
|
|
|
|
static char *sDescList[] = {"General", "DistSort", "Preprocess", "Stencil", "Last", "Unsorted"};
|
|
|
|
// Process render items list [nList] from [nums] to [nume]
|
|
// 1. Sorting of the list
|
|
// 2. Preprocess shaders handling
|
|
// 3. Process sorted ordered list of render items
|
|
void CD3D9Renderer::EF_PipeLine(int nums, int nume, int nList, void (*RenderFunc)())
|
|
{
|
|
int i;
|
|
SShader *pShader, *pCurShader, *pShaderState, *pCurShaderState;
|
|
SRenderShaderResources *pRes, *pCurRes;
|
|
int nObject, nCurObject;
|
|
int nFog, nCurFog;
|
|
|
|
if (nume-nums < 1)
|
|
return;
|
|
CheckDeviceLost();
|
|
|
|
m_RP.m_pRenderFunc = RenderFunc;
|
|
|
|
m_RP.m_nCurLightParam = -1;
|
|
m_RP.m_pCurObject = m_RP.m_VisObjects[0];
|
|
m_RP.m_pPrevObject = m_RP.m_pCurObject;
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CV_r_log)
|
|
Logv(SRendItem::m_RecurseLevel, "*** Start frame for list %s ***\n", sDescList[nList]);
|
|
#endif
|
|
|
|
EF_PreRender(1);
|
|
|
|
if (nList==EFSLIST_PREPROCESS_ID || nList==EFSLIST_GENERAL_ID || nList==EFSLIST_LAST_ID)
|
|
{
|
|
{
|
|
PROFILE_FRAME(State_Sorting);
|
|
SRendItem::mfSort(&SRendItem::m_RendItems[nList][nums], nume-nums);
|
|
}
|
|
|
|
// If sort number of the first shader is 1 (eS_Preprocess)
|
|
// run preprocess operations for the current frame
|
|
if ((SRendItem::m_RendItems[nList][nums].SortVal.i.High >> 26) == eS_PreProcess)
|
|
nums += EF_Preprocess(&SRendItem::m_RendItems[nList][0], nums, nume);
|
|
if (m_RP.m_PersFlags & RBPF_IGNORERENDERING)
|
|
return;
|
|
}
|
|
else
|
|
if (nList==EFSLIST_DISTSORT_ID)
|
|
{
|
|
PROFILE_FRAME(State_SortingDist);
|
|
SRendItem::mfSortByDist(&SRendItem::m_RendItems[nList][nums], nume-nums);
|
|
}
|
|
#ifdef PIPE_USE_INSTANCING
|
|
else
|
|
if (nList==EFSLIST_STENCIL_ID)
|
|
{
|
|
PROFILE_FRAME(State_Sorting);
|
|
int nStart = nums;
|
|
for (i=nums; i<nume; i++)
|
|
{
|
|
SRendItemPre *ri = &SRendItem::m_RendItems[nList][i];
|
|
int Type = ri->Item->mfGetType();
|
|
if (Type == eDATA_ClearStencil || Type == eDATA_TriMeshShadow)
|
|
{
|
|
SRendItem::mfSortForStencil(&SRendItem::m_RendItems[nList][nStart], i-nStart);
|
|
do
|
|
{
|
|
i++;
|
|
if (i >= nume)
|
|
break;
|
|
ri = &SRendItem::m_RendItems[nList][i];
|
|
Type = ri->Item->mfGetType();
|
|
} while(Type == eDATA_ClearStencil || Type == eDATA_TriMeshShadow);
|
|
nStart = i;
|
|
i--;
|
|
}
|
|
}
|
|
SRendItem::mfSortForStencil(&SRendItem::m_RendItems[nList][nStart], i-nStart);
|
|
}
|
|
#endif
|
|
|
|
m_RP.m_Flags |= RBF_3D;
|
|
|
|
EF_PreRender(3);
|
|
EF_PushMatrix();
|
|
|
|
/*float plane[4];
|
|
{
|
|
plane[0] = 0;
|
|
plane[1] = 0;
|
|
plane[2] = 1;
|
|
plane[3] = -50;
|
|
EF_SetClipPlane(true, plane, false);
|
|
}*/
|
|
|
|
PROFILE_FRAME(DrawShader_PipeLine);
|
|
|
|
UnINT64 oldVal;
|
|
oldVal.SortVal = -1;
|
|
nCurObject = -2;
|
|
nCurFog = 0;
|
|
pCurShader = NULL;
|
|
pCurShaderState = NULL;
|
|
pCurRes = NULL;
|
|
bool bIgnore = false;
|
|
bool bChanged;
|
|
bool bUseBatching = (RenderFunc == EF_Flush);
|
|
|
|
for (i=nums; i<nume; i++)
|
|
{
|
|
SRendItemPre *ri = &SRendItem::m_RendItems[nList][i];
|
|
CRendElement *pRE = ri->Item;
|
|
#ifndef PIPE_USE_INSTANCING
|
|
if (ri->SortVal.SortVal == oldVal.SortVal)
|
|
{
|
|
if (bIgnore)
|
|
continue;
|
|
// Optimizations: not necessary to check of changing shaders and objects
|
|
// if sort value is the same (contains the same info about shaders, objects, fog volumes, ...)
|
|
{
|
|
//PROFILE_FRAME_TOTAL(Mesh_REPrepare);
|
|
pRE->mfPrepare();
|
|
}
|
|
continue;
|
|
}
|
|
oldVal.SortVal = ri->SortVal.SortVal;
|
|
SRendItem::mfGet(ri->SortVal, &nObject, &pShader, &pShaderState, &nFog, &pRes);
|
|
bChanged = (pCurRes != pRes || pShader != pCurShader || pShaderState != pCurShaderState || nFog != nCurFog);
|
|
#else
|
|
if (oldVal.i.High == ri->SortVal.i.High && !((oldVal.i.Low ^ ri->SortVal.i.Low) & 0x000fffff))
|
|
{
|
|
SRendItem::mfGetObj(ri->SortVal, &nObject);
|
|
bChanged = false;
|
|
}
|
|
else
|
|
{
|
|
SRendItem::mfGet(ri->SortVal, &nObject, &pShader, &pShaderState, &nFog, &pRes);
|
|
bChanged = true;
|
|
}
|
|
oldVal.SortVal = ri->SortVal.SortVal;
|
|
#endif
|
|
if (nObject != nCurObject)
|
|
{
|
|
if (!bChanged && !pShader->m_Deforms && bUseBatching)
|
|
{
|
|
if (EF_TryToMerge(nObject, nCurObject, pRE))
|
|
continue;
|
|
}
|
|
if (pCurShader)
|
|
{
|
|
m_RP.m_pRenderFunc();
|
|
pCurShader = NULL;
|
|
bChanged = true;
|
|
}
|
|
if (!EF_ObjectChange(pShader, pRes, nObject, pRE))
|
|
{
|
|
bIgnore = true;
|
|
continue;
|
|
}
|
|
bIgnore = false;
|
|
nCurObject = nObject;
|
|
}
|
|
|
|
if (bChanged)
|
|
{
|
|
if (pCurShader)
|
|
m_RP.m_pRenderFunc();
|
|
EF_Start(pShader, pShaderState, pRes, nFog, pRE);
|
|
nCurFog = nFog;
|
|
pCurShader = pShader;
|
|
pCurShaderState = pShaderState;
|
|
pCurRes = pRes;
|
|
}
|
|
|
|
{
|
|
//PROFILE_FRAME_TOTAL(Mesh_REPrepare);
|
|
pRE->mfPrepare();
|
|
}
|
|
}
|
|
if (pCurShader)
|
|
m_RP.m_pRenderFunc();
|
|
|
|
//EF_SetClipPlane(false, plane, false);
|
|
|
|
EF_PostRender();
|
|
EF_PopMatrix();
|
|
|
|
|
|
#ifdef DO_RENDERLOG
|
|
if (CV_r_log)
|
|
Logv(SRendItem::m_RecurseLevel, "*** End frame ***\n\n");
|
|
#endif
|
|
}
|
|
|
|
// Draw overlay geometry in wireframe mode
|
|
void CD3D9Renderer::EF_DrawWire()
|
|
{
|
|
if (CV_r_showlines == 1)
|
|
gcpRendD3D->EF_SetState(GS_POLYLINE | GS_NODEPTHTEST);
|
|
else
|
|
if (CV_r_showlines == 2)
|
|
gcpRendD3D->EF_SetState(GS_POLYLINE);
|
|
gcpRendD3D->SetMaterialColor(1,1,1,1);
|
|
gRenDev->m_TexMan->m_Text_White->Set();
|
|
gcpRendD3D->EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0);
|
|
if (gcpRendD3D->m_RP.m_pRE)
|
|
gcpRendD3D->m_RP.m_pRE->mfCheckUpdate(gcpRendD3D->m_RP.m_pShader->m_VertexFormatId, 0);
|
|
int StrVrt;
|
|
|
|
gcpRendD3D->EF_SetObjectTransform(gcpRendD3D->m_RP.m_pCurObject, NULL, gcpRendD3D->m_RP.m_pCurObject->m_ObjFlags);
|
|
|
|
void *verts = (void *)gcpRendD3D->EF_GetPointer(eSrcPointer_Vert, &StrVrt, GL_FLOAT, eSrcPointer_Vert, 0);
|
|
gcpRendD3D->EF_Draw(gcpRendD3D->m_RP.m_pShader, NULL);
|
|
}
|
|
|
|
// Draw geometry normal vectors
|
|
void CD3D9Renderer::EF_DrawNormals()
|
|
{
|
|
HRESULT h;
|
|
float len = CRenderer::CV_r_normalslength;
|
|
int StrVrt, StrNrm;
|
|
//if (gcpRendD3D->m_RP.m_pRE)
|
|
// gcpRendD3D->m_RP.m_pRE->mfCheckUpdate(gcpRendD3D->m_RP.m_pShader->m_VertexFormatId, SHPF_NORMALS);
|
|
byte *verts = (byte *)gcpRendD3D->EF_GetPointer(eSrcPointer_Vert, &StrVrt, GL_FLOAT, eSrcPointer_Vert, FGP_SRC | FGP_REAL);
|
|
byte *norms = (byte *)gcpRendD3D->EF_GetPointer(eSrcPointer_Normal, &StrNrm, GL_FLOAT, eSrcPointer_Normal, FGP_SRC | FGP_REAL);
|
|
if ((INT_PTR)norms > 256 && (INT_PTR)verts > 256)
|
|
{
|
|
gcpRendD3D->EF_SetObjectTransform(gcpRendD3D->m_RP.m_pCurObject, NULL, gcpRendD3D->m_RP.m_pCurObject->m_ObjFlags);
|
|
|
|
int numVerts = gcpRendD3D->m_RP.m_RendNumVerts;
|
|
|
|
gRenDev->m_TexMan->m_Text_White->Set();
|
|
gcpRendD3D->EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0);
|
|
gcpRendD3D->EF_SetState(GS_POLYLINE);
|
|
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F *Verts = new struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F[numVerts*2];
|
|
|
|
uint col0 = 0x000000ff;
|
|
uint col1 = 0x00ffffff;
|
|
|
|
for (int v=0; v<numVerts*2; v+=2,verts+=StrVrt,norms+=StrNrm)
|
|
{
|
|
float *fverts = (float *)verts;
|
|
float *fnorms = (float *)norms;
|
|
Verts[v].xyz.x = fverts[0];
|
|
Verts[v].xyz.y = fverts[1];
|
|
Verts[v].xyz.z = fverts[2];
|
|
Verts[v].color.dcolor = col0;
|
|
|
|
Verts[v+1].xyz.x = fverts[0] + fnorms[0]*len;
|
|
Verts[v+1].xyz.y = fverts[1] + fnorms[1]*len;
|
|
Verts[v+1].xyz.z = fverts[2] + fnorms[2]*len;
|
|
Verts[v+1].color.dcolor = col1;
|
|
}
|
|
gcpRendD3D->EF_SetVertexDeclaration(0, VERTEX_FORMAT_P3F_COL4UB_TEX2F);
|
|
h = gcpRendD3D->m_pd3dDevice->DrawPrimitiveUP(D3DPT_LINELIST, numVerts, Verts, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F));
|
|
delete [] Verts;
|
|
}
|
|
}
|
|
|
|
// Draw geometry tangent vectors
|
|
void CD3D9Renderer::EF_DrawTangents()
|
|
{
|
|
HRESULT h;
|
|
|
|
float len = CRenderer::CV_r_normalslength;
|
|
//if (gcpRendD3D->m_RP.m_pRE)
|
|
// gcpRendD3D->m_RP.m_pRE->mfCheckUpdate(gcpRendD3D->m_RP.m_pShader->m_VertexFormatId, SHPF_TANGENTS);
|
|
int StrVrt, StrTang, StrBinorm, StrTNorm;
|
|
byte *verts = NULL;
|
|
byte *tangs = NULL;
|
|
byte *binorm = NULL;
|
|
byte *tnorm = NULL;
|
|
int flags = 0;
|
|
if (CRenderer::CV_r_showtangents == 1)
|
|
flags = FGP_SRC | FGP_REAL;
|
|
else
|
|
flags = FGP_REAL;
|
|
verts = (byte *)gcpRendD3D->EF_GetPointer(eSrcPointer_Vert, &StrVrt, GL_FLOAT, eSrcPointer_Vert, flags);
|
|
tangs = (byte *)gcpRendD3D->EF_GetPointer(eSrcPointer_Tangent, &StrTang, GL_FLOAT, eSrcPointer_Tangent, flags);
|
|
binorm = (byte *)gcpRendD3D->EF_GetPointer(eSrcPointer_Binormal, &StrBinorm, GL_FLOAT, eSrcPointer_Binormal, flags);
|
|
tnorm = (byte *)gcpRendD3D->EF_GetPointer(eSrcPointer_TNormal, &StrTNorm, GL_FLOAT, eSrcPointer_TNormal, flags);
|
|
if ((INT_PTR)tangs>256 && (INT_PTR)binorm>256 && (INT_PTR)tnorm>256)
|
|
{
|
|
gcpRendD3D->EF_SetObjectTransform(gcpRendD3D->m_RP.m_pCurObject, NULL, gcpRendD3D->m_RP.m_pCurObject->m_ObjFlags);
|
|
|
|
int numVerts = gcpRendD3D->m_RP.m_RendNumVerts;
|
|
|
|
gRenDev->m_TexMan->m_Text_White->Set();
|
|
gcpRendD3D->EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0);
|
|
if (gcpRendD3D->m_polygon_mode == R_SOLID_MODE)
|
|
gcpRendD3D->EF_SetState(GS_POLYLINE | GS_DEPTHWRITE);
|
|
else
|
|
gcpRendD3D->EF_SetState(0);
|
|
struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F *Verts = new struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F[numVerts*6];
|
|
|
|
for (int v=0; v<numVerts; v++,verts+=StrVrt,tangs+=StrTang, binorm+=StrBinorm, tnorm+=StrTNorm)
|
|
{
|
|
uint col0 = 0xffff0000;
|
|
uint col1 = 0xffffffff;
|
|
float *fverts = (float *)verts;
|
|
float *fv = (float *)tangs;
|
|
Verts[v*6+0].xyz.x = fverts[0];
|
|
Verts[v*6+0].xyz.y = fverts[1];
|
|
Verts[v*6+0].xyz.z = fverts[2];
|
|
Verts[v*6+0].color.dcolor = col0;
|
|
|
|
Verts[v*6+1].xyz.x = fverts[0] + fv[0]*len;
|
|
Verts[v*6+1].xyz.y = fverts[1] + fv[1]*len;
|
|
Verts[v*6+1].xyz.z = fverts[2] + fv[2]*len;
|
|
Verts[v*6+1].color.dcolor = col1;
|
|
|
|
col0 = 0x0000ff00;
|
|
col1 = 0x00ffffff;
|
|
fverts = (float *)verts;
|
|
fv = (float *)binorm;
|
|
Verts[v*6+2].xyz.x = fverts[0];
|
|
Verts[v*6+2].xyz.y = fverts[1];
|
|
Verts[v*6+2].xyz.z = fverts[2];
|
|
Verts[v*6+2].color.dcolor = col0;
|
|
|
|
Verts[v*6+3].xyz.x = fverts[0] + fv[0]*len;
|
|
Verts[v*6+3].xyz.y = fverts[1] + fv[1]*len;
|
|
Verts[v*6+3].xyz.z = fverts[2] + fv[2]*len;
|
|
Verts[v*6+3].color.dcolor = col1;
|
|
|
|
col0 = 0x000000ff;
|
|
col1 = 0x00ffffff;
|
|
fverts = (float *)verts;
|
|
fv = (float *)tnorm;
|
|
Verts[v*6+4].xyz.x = fverts[0];
|
|
Verts[v*6+4].xyz.y = fverts[1];
|
|
Verts[v*6+4].xyz.z = fverts[2];
|
|
Verts[v*6+4].color.dcolor = col0;
|
|
|
|
Verts[v*6+5].xyz.x = fverts[0] + fv[0]*len;
|
|
Verts[v*6+5].xyz.y = fverts[1] + fv[1]*len;
|
|
Verts[v*6+5].xyz.z = fverts[2] + fv[2]*len;
|
|
Verts[v*6+5].color.dcolor = col1;
|
|
}
|
|
gcpRendD3D->EF_SetVertexDeclaration(0, VERTEX_FORMAT_P3F_COL4UB_TEX2F);
|
|
h = gcpRendD3D->m_pd3dDevice->DrawPrimitiveUP(D3DPT_LINELIST, numVerts*3, Verts, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F));
|
|
delete [] Verts;
|
|
}
|
|
}
|
|
|
|
// Draw light sources in debug mode
|
|
void CD3D9Renderer::EF_DrawDebugLights()
|
|
{
|
|
static int sFrame = 0;
|
|
if (m_nFrameUpdateID != sFrame)
|
|
{
|
|
int i;
|
|
sFrame = m_nFrameID;
|
|
|
|
gRenDev->m_TexMan->m_Text_White->Set();
|
|
|
|
for (i=0; i<m_RP.m_DLights[SRendItem::m_RecurseLevel].Num(); i++)
|
|
{
|
|
CDLight *dl = m_RP.m_DLights[SRendItem::m_RecurseLevel][i];
|
|
if (!dl)
|
|
continue;
|
|
char *str = CV_r_showlight->GetString();
|
|
if (strcmp(str, "0") != 0)
|
|
{
|
|
if (!dl->m_Name || strcmp(str, dl->m_Name))
|
|
continue;
|
|
}
|
|
SetMaterialColor(dl->m_Color[0], dl->m_Color[1], dl->m_Color[2], dl->m_Color[3]);
|
|
if (dl->m_Flags & DLF_DIRECTIONAL)
|
|
DrawPoint(dl->m_Origin[0], dl->m_Origin[1], dl->m_Origin[2], 10);
|
|
else
|
|
if (dl->m_Flags & DLF_POINT)
|
|
DrawBall(dl->m_Origin[0], dl->m_Origin[1], dl->m_Origin[2], 0.05f);
|
|
if (dl->m_Flags & DLF_PROJECT)
|
|
{
|
|
Vec3d dir, rgt, org;
|
|
EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0);
|
|
EF_SetVertexDeclaration(0, VERTEX_FORMAT_P3F_COL4UB);
|
|
|
|
dir = dl->m_Orientation.m_vForward;
|
|
rgt = dl->m_Orientation.m_vRight;
|
|
float ang = dl->m_fLightFrustumAngle;
|
|
if (ang == 0)
|
|
ang = 45.0f;
|
|
org = dl->m_Origin;
|
|
|
|
dir *= 0.3f;
|
|
|
|
CFColor Col = dl->m_Color;
|
|
|
|
Matrix44 m;
|
|
Vec3d vertex = dir;
|
|
|
|
// vertex = m.GetRotation(rgt, ang)*vertex;
|
|
vertex = Matrix33::CreateRotationAA(ang*gf_DEGTORAD,GetNormalized(rgt)) * vertex; //NOTE: angle need to be in radians
|
|
// Matrix mat = m.GetRotation(dir, 60);
|
|
Matrix44 mat = Matrix33::CreateRotationAA(60*gf_DEGTORAD,GetNormalized(dir)); //NOTE: angle need to be in radians
|
|
Vec3d tmpvertex;
|
|
int ctr;
|
|
|
|
//fill the inside of the light
|
|
EnableTMU(false);
|
|
struct_VERTEX_FORMAT_P3F_COL4UB Verts[32];
|
|
memset(Verts, 0, sizeof(Verts));
|
|
CFColor cl = Col*0.3f;
|
|
int n = 0;
|
|
Verts[n].xyz = org;
|
|
Verts[n].color.dcolor = D3DRGBA(cl[0], cl[1], cl[2], 1.0f);
|
|
n++;
|
|
tmpvertex = org + vertex;
|
|
Verts[n].xyz = tmpvertex;
|
|
Verts[n].color.dcolor = D3DRGBA(Col[0], Col[1], Col[2], 1.0f);
|
|
n++;
|
|
for (ctr=0; ctr<6; ctr++)
|
|
{
|
|
vertex = mat * vertex;
|
|
Vec3d tmpvertex = org + vertex;
|
|
Verts[n].xyz = tmpvertex;
|
|
Verts[n].color.dcolor = D3DRGBA(Col[0], Col[1], Col[2], 1.0f);
|
|
n++;
|
|
}
|
|
m_pd3dDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, n-2, Verts, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB));
|
|
|
|
//draw the inside of the light with lines and the outside filled
|
|
m_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
|
|
SetCullMode(R_CULL_NONE);
|
|
n = 0;
|
|
Verts[n].xyz = org;
|
|
Verts[n].color.dcolor = D3DRGBA(0.3f, 0.3f, 0.3f, 1.0f);
|
|
n++;
|
|
tmpvertex = org + vertex;
|
|
Verts[n].xyz = tmpvertex;
|
|
Verts[n].color.dcolor = D3DRGBA(1.0f, 1.0f, 1.0f, 1.0f);
|
|
n++;
|
|
for (ctr=0; ctr<6; ctr++)
|
|
{
|
|
vertex = mat * vertex;
|
|
Vec3d tmpvertex = org + vertex;
|
|
Verts[n].xyz = tmpvertex;
|
|
Verts[n].color.dcolor = D3DRGBA(1.0f, 1.0f, 1.0f, 1.0f);
|
|
n++;
|
|
}
|
|
m_pd3dDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, n-2, Verts, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB));
|
|
SetCullMode(R_CULL_FRONT);
|
|
m_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
|
|
|
|
//set the color to the color of the light
|
|
Verts[0].xyz = org;
|
|
Verts[0].color.dcolor = D3DRGBA(Col[0], Col[1], Col[2], 1.0f);
|
|
|
|
//draw a point at the origin of the light
|
|
m_pd3dDevice->DrawPrimitiveUP(D3DPT_POINTLIST, 1, Verts, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB));
|
|
|
|
//draw a line in the center of the light
|
|
Verts[0].xyz = org;
|
|
Verts[0].color.dcolor = D3DRGBA(Col[0], Col[1], Col[2], 1.0f);
|
|
|
|
tmpvertex = org + dir;
|
|
Verts[1].xyz = tmpvertex;
|
|
Verts[1].color.dcolor = D3DRGBA(Col[0], Col[1], Col[2], 1.0f);
|
|
m_pd3dDevice->DrawPrimitiveUP(D3DPT_LINELIST, 1, Verts, sizeof(struct_VERTEX_FORMAT_P3F_COL4UB));
|
|
|
|
EnableTMU(true);
|
|
}
|
|
if (CV_r_debuglights == 2 && !(dl->m_Flags & DLF_DIRECTIONAL))
|
|
{
|
|
EF_SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA);
|
|
SetCullMode(R_CULL_NONE);
|
|
SetMaterialColor(dl->m_Color[0], dl->m_Color[1], dl->m_Color[2], 0.25f);
|
|
DrawBall(dl->m_Origin[0], dl->m_Origin[1], dl->m_Origin[2], dl->m_fRadius);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Draw debug geometry/info
|
|
void CD3D9Renderer::EF_DrawDebugTools()
|
|
{
|
|
if (CV_r_showlines)
|
|
EF_RenderPipeLine(EF_DrawWire);
|
|
|
|
if (CV_r_shownormals)
|
|
EF_RenderPipeLine(EF_DrawNormals);
|
|
|
|
if (CV_r_showtangents)
|
|
EF_RenderPipeLine(EF_DrawTangents);
|
|
|
|
if (SRendItem::m_RecurseLevel==1 && CV_r_debuglights)
|
|
EF_DrawDebugLights();
|
|
}
|
|
|
|
|
|
static int __cdecl TimeProfCallback( const VOID* arg1, const VOID* arg2 )
|
|
{
|
|
SProfInfo *pi1 = (SProfInfo *)arg1;
|
|
SProfInfo *pi2 = (SProfInfo *)arg2;
|
|
if (pi1->ef->m_fProfileTime > pi2->ef->m_fProfileTime)
|
|
return -1;
|
|
if (pi1->ef->m_fProfileTime < pi2->ef->m_fProfileTime)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static int __cdecl NameCallback( const VOID* arg1, const VOID* arg2 )
|
|
{
|
|
SProfInfo *pi1 = (SProfInfo *)arg1;
|
|
SProfInfo *pi2 = (SProfInfo *)arg2;
|
|
if (pi1->ef > pi2->ef)
|
|
return -1;
|
|
if (pi1->ef < pi2->ef)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
//#include "FMallocWindows.h"
|
|
|
|
// Print shaders profile info on the screen
|
|
void CD3D9Renderer::EF_PrintProfileInfo()
|
|
{
|
|
double fTime = 0;
|
|
int i;
|
|
if (CV_r_profileshaders)
|
|
{ // group by name
|
|
qsort(&m_RP.m_Profile[0], m_RP.m_Profile.Num(), sizeof(SProfInfo), NameCallback );
|
|
|
|
for(i=0; i<m_RP.m_Profile.Num(); i++)
|
|
{
|
|
// if next is the same
|
|
if( i<(m_RP.m_Profile.Num()-1) && m_RP.m_Profile[i].ef == m_RP.m_Profile[i+1].ef )
|
|
{
|
|
m_RP.m_Profile[i].Time += m_RP.m_Profile[i+1].Time;
|
|
m_RP.m_Profile[i].m_nItems++;
|
|
m_RP.m_Profile[i].NumPolys += m_RP.m_Profile[i+1].NumPolys;
|
|
m_RP.m_Profile.DelElem(i+1);
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
for (i=0; i<m_RP.m_Profile.Num(); i++)
|
|
{
|
|
m_RP.m_Profile[i].ef->m_fProfileTime = (float)(m_RP.m_Profile[i].Time+m_RP.m_Profile[i].ef->m_fProfileTime*50)/51.0f;
|
|
}
|
|
|
|
TextToScreenColor(1,14, 0,2,0,1, "Items: %d, Batches: %d, Obj: %d, DrawCalls: %d, Text: %d, Stat: %d, PShad: %d, VShad: %d", m_RP.m_PS.m_NumRendItems, m_RP.m_PS.m_NumRendBatches, m_RP.m_PS.m_NumRendObjects, m_RP.m_PS.m_NumDrawCalls, m_RP.m_PS.m_NumTextChanges, m_RP.m_PS.m_NumStateChanges, m_RP.m_PS.m_NumPShadChanges, m_RP.m_PS.m_NumVShadChanges);
|
|
TextToScreenColor(1,17, 0,2,0,1, "VShad: %d, PShad: %d, Text: %d, Lit Shaders: %d", m_RP.m_PS.m_NumVShaders, m_RP.m_PS.m_NumPShaders, m_RP.m_PS.m_NumTextures, m_RP.m_PS.m_NumLitShaders);
|
|
TextToScreenColor(1,20, 0,2,0,1, "Preprocess: %8.02f ms, Occl. queries: %8.02f ms", m_RP.m_PS.m_fPreprocessTime, m_RP.m_PS.m_fOcclusionTime);
|
|
TextToScreenColor(1,23, 0,2,0,1, "Skinning: %8.02f ms (Skinned Objects: %d)", m_RP.m_PS.m_fSkinningTime, m_RP.m_PS.m_NumRendSkinnedObjects);
|
|
|
|
int nLine;
|
|
{ // sort by interpolated time and print
|
|
qsort(&m_RP.m_Profile[0], m_RP.m_Profile.Num(), sizeof(SProfInfo), TimeProfCallback );
|
|
|
|
for(nLine=0; nLine<m_RP.m_Profile.Num(); nLine++)
|
|
{
|
|
fTime += m_RP.m_Profile[nLine].Time;
|
|
if (nLine >= 18)
|
|
continue;
|
|
TextToScreenColor(4,(27+(nLine*3)), 1,0,0,1, "%8.02f ms, %5d polys, '%s', %d item(s)",
|
|
m_RP.m_Profile[nLine].ef->m_fProfileTime,
|
|
m_RP.m_Profile[nLine].NumPolys,
|
|
m_RP.m_Profile[nLine].ef->m_Name.c_str(),
|
|
m_RP.m_Profile[nLine].m_nItems+1);
|
|
}
|
|
}
|
|
int nShaders = nLine;
|
|
TextToScreenColor(2,(28+(nLine*3)), 0,2,0,1, "Total unique shaders: %d", nShaders);
|
|
TextToScreenColor(2,(31+(nLine*3)), 0,2,0,1, "Total flush time: %8.02f ms", fTime);
|
|
TextToScreenColor(2,(34+(nLine*3)), 0,2,0,1, "Total shaders processing time: %8.02f ms", m_RP.m_PS.m_fFlushTime);
|
|
|
|
/*{
|
|
int i = 0;
|
|
double timeC = 0;
|
|
double timeSSE = 0;
|
|
|
|
CCamera cam = GetCamera();
|
|
Vec3d camPos = cam.GetPos();
|
|
AABB aabb;
|
|
aabb.min = camPos+Vec3d(-10, -16,-16);
|
|
aabb.max = camPos+Vec3d(16,32,16);
|
|
Vec3d Origin = (aabb.min+aabb.max)*0.5f;
|
|
Vec3d Extent = aabb.max - Origin;
|
|
|
|
ticks(timeC);
|
|
for (i=0; i<100000; i++)
|
|
{
|
|
cam.IsAABBVisible_exact(aabb, NULL);
|
|
}
|
|
unticks(timeC);
|
|
|
|
ticks(timeSSE);
|
|
for (i=0; i<100000; i++)
|
|
{
|
|
cam.IsAABBVisible_exact_SSE(Origin, Extent, NULL);
|
|
}
|
|
unticks(timeSSE);
|
|
|
|
TextToScreenColor(8,(36+(nLine*3)), 0,2,0,1, "TimeC %8.02f ms, TimeSSE %8.02f ms", (float)(timeC*1000.0*m_RP.m_SecondsPerCycle), (float)(timeSSE*1000.0*m_RP.m_SecondsPerCycle));
|
|
}*/
|
|
/*{
|
|
int i = 0;
|
|
double timeC = 0;
|
|
double timeC33 = 0;
|
|
double time3DN = 0;
|
|
double timeSSE = 0;
|
|
_declspec(align(16)) Matrix m, mOut;
|
|
m = m_cam.GetMatrix();
|
|
m_RP.m_pCurObject = m_RP.m_VisObjects[0];
|
|
Matrix33 m31;
|
|
Matrix33 m32;
|
|
m31.SetIdentity33();
|
|
|
|
ticks(timeC33);
|
|
for (i=0; i<100000; i++)
|
|
{
|
|
m31.Invert33();
|
|
}
|
|
unticks(timeC33);
|
|
|
|
ticks(timeC);
|
|
for (i=0; i<100000; i++)
|
|
{
|
|
QQinvertMatrixf(mOut.GetData(), m.GetData());
|
|
}
|
|
unticks(timeC);
|
|
|
|
if (m_Cpu->mCpu[0].mFeatures & CFI_3DNOW)
|
|
{
|
|
ticks(time3DN);
|
|
for (i=0; i<100000; i++)
|
|
{
|
|
invertMatrixf_3DNow(mOut.GetData(), m.GetData());
|
|
}
|
|
unticks(time3DN);
|
|
}
|
|
|
|
ticks(timeSSE);
|
|
for (i=0; i<100000; i++)
|
|
{
|
|
invertMatrixf_SSE(mOut.GetData(), m.GetData());
|
|
}
|
|
unticks(timeSSE);
|
|
|
|
TextToScreenColor(8,(36+(nLine*3)), 0,2,0,1, "TimeC: %8.02f ms, TimeC33: %8.02f ms,, Time3DN: %8.02f ms, TimeSSE: %8.02f ms", (float)(timeC*1000.0*m_RP.m_SecondsPerCycle), (float)(timeC33*1000.0*m_RP.m_SecondsPerCycle), (float)(time3DN*1000.0*m_RP.m_SecondsPerCycle), (float)(timeSSE*1000.0*m_RP.m_SecondsPerCycle));
|
|
}*/
|
|
/*{
|
|
int i = 0;
|
|
double timeC = 0;
|
|
double timeSSE = 0;
|
|
double timeSSENew = 0;
|
|
byte *dataSrc = new byte[1024*1024*10];
|
|
byte *dataDst = new byte[1024*1024*10];
|
|
|
|
ticks(timeC);
|
|
for (i=0; i<10; i++)
|
|
{
|
|
memcpy(dataDst, dataSrc, 1024*1024*10-128);
|
|
}
|
|
unticks(timeC);
|
|
|
|
byte *Dst = (byte *)((int)(dataDst+15)&0xfffffff0);
|
|
byte *Src = (byte *)((int)(dataSrc+15)&0xfffffff0);
|
|
ticks(timeSSE);
|
|
for (i=0; i<10; i++)
|
|
{
|
|
cryMemcpy(Dst, Src, 1024*1024*10-128);
|
|
}
|
|
unticks(timeSSE);
|
|
|
|
ticks(timeSSENew);
|
|
for (i=0; i<10; i++)
|
|
{
|
|
cryMemcpy(Dst, Src, 1024*1024*10-128, 0);
|
|
}
|
|
unticks(timeSSENew);
|
|
|
|
delete [] dataSrc;
|
|
delete [] dataDst;
|
|
|
|
TextToScreenColor(8,(36+(nLine*3)), 0,2,0,1, "TimeC: %8.02f ms, TimeSSE: %8.02f ms", (float)(timeC*1000.0*g_SecondsPerCycle), (float)(timeSSE*1000.0*g_SecondsPerCycle));
|
|
}*/
|
|
/*{
|
|
int i = 0;
|
|
double timeCM10 = 0;
|
|
double timeCF10 = 0;
|
|
double timeCM60 = 0;
|
|
double timeCF60 = 0;
|
|
double timeCM110 = 0;
|
|
double timeCF110 = 0;
|
|
double timeCM510 = 0;
|
|
double timeCF510 = 0;
|
|
double timeCM1010 = 0;
|
|
double timeCF1010 = 0;
|
|
double timeCM5010 = 0;
|
|
double timeCF5010 = 0;
|
|
double timeCM10010 = 0;
|
|
double timeCF10010 = 0;
|
|
double timeCM100010 = 0;
|
|
double timeCF100010 = 0;
|
|
|
|
double timeUM10 = 0;
|
|
double timeUF10 = 0;
|
|
double timeUM60 = 0;
|
|
double timeUF60 = 0;
|
|
double timeUM110 = 0;
|
|
double timeUF110 = 0;
|
|
double timeUM510 = 0;
|
|
double timeUF510 = 0;
|
|
double timeUM1010 = 0;
|
|
double timeUF1010 = 0;
|
|
double timeUM5010 = 0;
|
|
double timeUF5010 = 0;
|
|
double timeUM10010 = 0;
|
|
double timeUF10010 = 0;
|
|
double timeUM100010 = 0;
|
|
double timeUF100010 = 0;
|
|
|
|
static FMallocWindows *pM;
|
|
if (!pM)
|
|
{
|
|
pM = new FMallocWindows;
|
|
pM->Init();
|
|
}
|
|
void *pPtr[1000];
|
|
|
|
ticks(timeCM10);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = malloc(10);
|
|
unticks(timeCM10);
|
|
ticks(timeCF10);
|
|
for (i=0; i<1000; i++)
|
|
free(pPtr[i]);
|
|
unticks(timeCF10);
|
|
|
|
ticks(timeUM10);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = pM->Malloc(10, "Test");
|
|
unticks(timeUM10);
|
|
ticks(timeUF10);
|
|
for (i=0; i<1000; i++)
|
|
pM->Free(pPtr[i]);
|
|
unticks(timeUF10);
|
|
|
|
ticks(timeCM60);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = malloc(60);
|
|
unticks(timeCM60);
|
|
ticks(timeCF60);
|
|
for (i=0; i<1000; i++)
|
|
free(pPtr[i]);
|
|
unticks(timeCF60);
|
|
|
|
ticks(timeUM60);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = pM->Malloc(60, "Test");
|
|
unticks(timeUM60);
|
|
ticks(timeUF60);
|
|
for (i=0; i<1000; i++)
|
|
pM->Free(pPtr[i]);
|
|
unticks(timeUF60);
|
|
|
|
ticks(timeCM110);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = malloc(110);
|
|
unticks(timeCM110);
|
|
ticks(timeCF110);
|
|
for (i=0; i<1000; i++)
|
|
free(pPtr[i]);
|
|
unticks(timeCF110);
|
|
|
|
ticks(timeUM110);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = pM->Malloc(110, "Test");
|
|
unticks(timeUM110);
|
|
ticks(timeUF110);
|
|
for (i=0; i<1000; i++)
|
|
pM->Free(pPtr[i]);
|
|
unticks(timeUF110);
|
|
|
|
ticks(timeCM510);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = malloc(510);
|
|
unticks(timeCM510);
|
|
ticks(timeCF510);
|
|
for (i=0; i<1000; i++)
|
|
free(pPtr[i]);
|
|
unticks(timeCF510);
|
|
|
|
ticks(timeUM510);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = pM->Malloc(510, "Test");
|
|
unticks(timeUM510);
|
|
ticks(timeUF510);
|
|
for (i=0; i<1000; i++)
|
|
pM->Free(pPtr[i]);
|
|
unticks(timeUF510);
|
|
|
|
ticks(timeCM1010);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = malloc(1010);
|
|
unticks(timeCM1010);
|
|
ticks(timeCF1010);
|
|
for (i=0; i<1000; i++)
|
|
free(pPtr[i]);
|
|
unticks(timeCF1010);
|
|
|
|
ticks(timeUM1010);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = pM->Malloc(1010, "Test");
|
|
unticks(timeUM1010);
|
|
ticks(timeUF1010);
|
|
for (i=0; i<1000; i++)
|
|
pM->Free(pPtr[i]);
|
|
unticks(timeUF1010);
|
|
|
|
ticks(timeCM5010);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = malloc(5010);
|
|
unticks(timeCM5010);
|
|
ticks(timeCF5010);
|
|
for (i=0; i<1000; i++)
|
|
free(pPtr[i]);
|
|
unticks(timeCF5010);
|
|
|
|
ticks(timeUM5010);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = pM->Malloc(5010, "Test");
|
|
unticks(timeUM5010);
|
|
ticks(timeUF5010);
|
|
for (i=0; i<1000; i++)
|
|
pM->Free(pPtr[i]);
|
|
unticks(timeUF5010);
|
|
|
|
ticks(timeCM10010);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = malloc(10010);
|
|
unticks(timeCM10010);
|
|
ticks(timeCF10010);
|
|
for (i=0; i<1000; i++)
|
|
free(pPtr[i]);
|
|
unticks(timeCF10010);
|
|
|
|
ticks(timeUM10010);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = pM->Malloc(10010, "Test");
|
|
unticks(timeUM10010);
|
|
ticks(timeUF10010);
|
|
for (i=0; i<1000; i++)
|
|
pM->Free(pPtr[i]);
|
|
unticks(timeUF10010);
|
|
|
|
ticks(timeCM100010);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = malloc(100010);
|
|
unticks(timeCM100010);
|
|
ticks(timeCF100010);
|
|
for (i=0; i<1000; i++)
|
|
free(pPtr[i]);
|
|
unticks(timeCF100010);
|
|
|
|
ticks(timeUM100010);
|
|
for (i=0; i<1000; i++)
|
|
pPtr[i] = pM->Malloc(100010, "Test");
|
|
unticks(timeUM100010);
|
|
ticks(timeUF100010);
|
|
for (i=0; i<1000; i++)
|
|
pM->Free(pPtr[i]);
|
|
unticks(timeUF100010);
|
|
|
|
TextToScreenColor(1,(36+(nLine*3)), 0,2,0,1, "CM_10: %3.02f, CM_60: %3.02f, CM_110: %3.02f, CM_510: %3.02f, CM_1010: %3.02f, CM_5010: %3.02f, CM_10010: %3.02f, CM_100010: %3.02f", (float)(timeCM10*1000.0*g_SecondsPerCycle), (float)(timeCM60*1000.0*g_SecondsPerCycle), (float)(timeCM110*1000.0*g_SecondsPerCycle), (float)(timeCM510*1000.0*g_SecondsPerCycle), (float)(timeCM1010*1000.0*g_SecondsPerCycle), (float)(timeCM5010*1000.0*g_SecondsPerCycle), (float)(timeCM10010*1000.0*g_SecondsPerCycle), (float)(timeCM100010*1000.0*g_SecondsPerCycle));
|
|
TextToScreenColor(1,(40+(nLine*3)), 0,2,0,1, "UM_10: %3.02f, UM_60: %3.02f, UM_110: %3.02f, UM_510: %3.02f, UM_1010: %3.02f, UM_5010: %3.02f, UM_10010: %3.02f, UM_100010: %3.02f", (float)(timeUM10*1000.0*g_SecondsPerCycle), (float)(timeUM60*1000.0*g_SecondsPerCycle), (float)(timeUM110*1000.0*g_SecondsPerCycle), (float)(timeUM510*1000.0*g_SecondsPerCycle), (float)(timeUM1010*1000.0*g_SecondsPerCycle), (float)(timeUM5010*1000.0*g_SecondsPerCycle), (float)(timeUM10010*1000.0*g_SecondsPerCycle), (float)(timeUM100010*1000.0*g_SecondsPerCycle));
|
|
TextToScreenColor(1,(44+(nLine*3)), 0,2,0,1, "CF_10: %3.02f, CF_60: %3.02f, CF_110: %3.02f, CF_510: %3.02f, CF_1010: %3.02f, CF_5010: %3.02f, CF_10010: %3.02f, CF_100010: %3.02f", (float)(timeCF10*1000.0*g_SecondsPerCycle), (float)(timeCF60*1000.0*g_SecondsPerCycle), (float)(timeCF110*1000.0*g_SecondsPerCycle), (float)(timeCF510*1000.0*g_SecondsPerCycle), (float)(timeCF1010*1000.0*g_SecondsPerCycle), (float)(timeCF5010*1000.0*g_SecondsPerCycle), (float)(timeCF10010*1000.0*g_SecondsPerCycle), (float)(timeCF100010*1000.0*g_SecondsPerCycle));
|
|
TextToScreenColor(1,(48+(nLine*3)), 0,2,0,1, "UF_10: %3.02f, UF_60: %3.02f, UF_110: %3.02f, UF_510: %3.02f, UF_1010: %3.02f, UF_5010: %3.02f, UF_10010: %3.02f, UF_100010: %3.02f", (float)(timeUF10*1000.0*g_SecondsPerCycle), (float)(timeUF60*1000.0*g_SecondsPerCycle), (float)(timeUF110*1000.0*g_SecondsPerCycle), (float)(timeUF510*1000.0*g_SecondsPerCycle), (float)(timeUF1010*1000.0*g_SecondsPerCycle), (float)(timeUF5010*1000.0*g_SecondsPerCycle), (float)(timeUF10010*1000.0*g_SecondsPerCycle), (float)(timeUF100010*1000.0*g_SecondsPerCycle));
|
|
}*/
|
|
}
|
|
|
|
void CD3D9Renderer::EF_DrawREPreprocess(SRendItemPreprocess *ris, int Nums)
|
|
{
|
|
int i;
|
|
CCObject *savedObj;
|
|
SShader *Shader, *CurShader, *ShaderState, *CurShaderState;
|
|
SRenderShaderResources *Res, *CurRes;
|
|
int nObject, nCurObject;
|
|
int nFog, nCurFog;
|
|
|
|
if (Nums < 1)
|
|
return;
|
|
|
|
savedObj = m_RP.m_pCurObject;
|
|
m_RP.m_pCurObject = m_RP.m_VisObjects[0];
|
|
m_RP.m_pPrevObject = m_RP.m_pCurObject;
|
|
|
|
EF_PreRender(1);
|
|
|
|
EF_PushMatrix();
|
|
|
|
UnINT64 oldVal;
|
|
oldVal.SortVal = -1;
|
|
nCurObject = -2;
|
|
nCurFog = 0;
|
|
CurShader = NULL;
|
|
CurShaderState = NULL;
|
|
CurRes = NULL;
|
|
|
|
for (i=0; i<Nums; i++)
|
|
{
|
|
SRendItemPreprocess *ri = &ris[i];
|
|
CRendElement *re = ri->Item;
|
|
if (ri->SortVal.SortVal == oldVal.SortVal)
|
|
{
|
|
// Optimizations: not necessary to check of changing shaders and objects
|
|
// if sort value is the same (consist the same info about shaders, objects, fog volumes, ...)
|
|
re->mfPrepare();
|
|
continue;
|
|
}
|
|
oldVal.SortVal = ri->SortVal.SortVal;
|
|
|
|
SRendItem::mfGet(ri->SortVal, &nObject, &Shader, &ShaderState, &nFog, &Res);
|
|
|
|
if (nObject != nCurObject)
|
|
{
|
|
if (CurShader)
|
|
EF_Flush();
|
|
if (!EF_ObjectChange(Shader, Res, nObject, re))
|
|
continue;
|
|
nCurObject = nObject;
|
|
}
|
|
|
|
if (Shader != CurShader, Res != CurRes || ShaderState != CurShaderState || nFog != nCurFog)
|
|
{
|
|
if (CurShader)
|
|
m_RP.m_pRenderFunc();
|
|
|
|
EF_Start(Shader, ShaderState, Res, nFog, re);
|
|
|
|
nCurFog = nFog;
|
|
CurShader = Shader;
|
|
CurShaderState = ShaderState;
|
|
CurRes = Res;
|
|
}
|
|
|
|
re->mfPrepare();
|
|
}
|
|
if (CurShader)
|
|
m_RP.m_pRenderFunc();
|
|
|
|
EF_PostRender();
|
|
|
|
EF_PopMatrix();
|
|
|
|
m_RP.m_pCurObject = savedObj;
|
|
}
|
|
|
|
struct SPreprocess
|
|
{
|
|
int m_nPreprocess;
|
|
int m_Num;
|
|
int m_nObject;
|
|
SShader *m_Shader;
|
|
SRenderShaderResources *m_pRes;
|
|
CRendElement *m_RE;
|
|
};
|
|
|
|
STWarpZone *CD3D9Renderer::EF_SetWarpZone(SWarpSurf *sf, int *NumWarps, STWarpZone Warps[])
|
|
{
|
|
int i;
|
|
STWarpZone *wp;
|
|
Plane p, pl;
|
|
|
|
sf->srf->mfGetPlane(pl);
|
|
if (sf->nobj > 0)
|
|
{
|
|
p = pl;
|
|
CCObject *obj = m_RP.m_VisObjects[sf->nobj];
|
|
pl = TransformPlane(obj->GetMatrix(), p);
|
|
}
|
|
for (i=0; i<NumWarps[0]; i++)
|
|
{
|
|
// if (pl.d == Warps[i].plane.d && pl.n == Warps[i].plane.n)
|
|
if (pl.d == Warps[i].plane.d && IsEquivalent(pl.n,Warps[i].plane.n))
|
|
break;
|
|
}
|
|
if (i == NumWarps[0])
|
|
{
|
|
NumWarps[0]++;
|
|
wp = &Warps[i];
|
|
wp->numSrf = 0;
|
|
wp->plane.d = pl.d;
|
|
wp->plane.n = pl.n;
|
|
}
|
|
EF_UpdateWarpZone(&Warps[i], sf);
|
|
|
|
return &Warps[i];
|
|
}
|
|
|
|
void CD3D9Renderer::EF_UpdateWarpZone(STWarpZone *wp, SWarpSurf *srf)
|
|
{
|
|
if (wp->numSrf == MAX_WARPSURFS)
|
|
return;
|
|
wp->Surfs[wp->numSrf].nobj = srf->nobj;
|
|
wp->Surfs[wp->numSrf].Shader = srf->Shader;
|
|
wp->Surfs[wp->numSrf].srf = srf->srf;
|
|
wp->numSrf++;
|
|
}
|
|
|
|
bool CD3D9Renderer::EF_CalcWarpCamera(STWarpZone *wp, int nObject, CCamera& prevCam, CCamera& newCam)
|
|
{
|
|
Vec3d vPrevPos = prevCam.GetPos();
|
|
Vec3d vPrevAngs = prevCam.GetAngles();
|
|
Vec3d vNewPos, vNewOccPos, vNewAngs;
|
|
bool bMirror = true;
|
|
if (nObject > 0)
|
|
{
|
|
CCObject *pObj = m_RP.m_VisObjects[nObject];
|
|
if (pObj->m_ObjFlags & FOB_PORTAL)
|
|
{
|
|
bMirror = false;
|
|
m_RP.m_PersFlags &= ~RBPF_DRAWMIRROR;
|
|
m_RP.m_PersFlags |= RBPF_DRAWPORTAL;
|
|
vNewPos = Vec3d(pObj->m_Trans2[0], pObj->m_Trans2[1], pObj->m_Trans2[2]);
|
|
vNewOccPos = vNewPos;
|
|
vNewAngs = Vec3d(pObj->m_Angs2[0], pObj->m_Angs2[1], pObj->m_Angs2[2]);
|
|
}
|
|
}
|
|
if (bMirror)
|
|
{
|
|
float fDot = vPrevPos.Dot(wp->plane.n) - wp->plane.d;
|
|
vNewPos = vPrevPos + wp->plane.n * -2.0f*fDot;
|
|
vNewOccPos = vPrevPos + wp->plane.n * -0.99f*fDot;
|
|
|
|
if (fDot < 0)
|
|
m_RP.m_MirrorClipSide = 1;
|
|
else
|
|
m_RP.m_MirrorClipSide = 2;
|
|
|
|
fDot = m_RP.m_CamVecs[0].Dot(wp->plane.n);
|
|
Vec3d vNewDir = m_RP.m_CamVecs[0] + wp->plane.n * -2.0f*fDot;
|
|
|
|
vNewAngs[0] = cry_asinf (vNewDir[2])/M_PI*180.0f;
|
|
vNewAngs[1] = vPrevAngs[1] + 180.0f;
|
|
vNewAngs[2] = -cry_atan2f (vNewDir[0], -vNewDir[1])/M_PI*180.0f;
|
|
|
|
m_RP.m_PersFlags &= ~RBPF_DRAWPORTAL;
|
|
m_RP.m_PersFlags |= RBPF_DRAWMIRROR;
|
|
}
|
|
|
|
newCam.SetPos(vNewPos);
|
|
newCam.SetOccPos(vNewOccPos);
|
|
newCam.SetAngle(vNewAngs);
|
|
if (bMirror)
|
|
newCam.SetScale(Vec3d(-1.0f, 1.0f, 1.0f));
|
|
newCam.Update();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CD3D9Renderer::EF_RenderWarpZone(STWarpZone *wp)
|
|
{
|
|
if (!wp->numSrf)
|
|
return false;
|
|
|
|
CCamera prevCam = GetCamera();
|
|
CCamera newCam = prevCam;
|
|
|
|
int prevFlags = m_RP.m_PersFlags;
|
|
|
|
if (!EF_CalcWarpCamera(wp, wp->Surfs[0].nobj, prevCam, newCam))
|
|
return false;
|
|
|
|
if (m_LogFile)
|
|
Logv(SRendItem::m_RecurseLevel, "\n ********** Start Render Portal **********\n");
|
|
|
|
STWarpZone *prevWarp = m_RP.m_CurWarp;
|
|
m_RP.m_CurWarp = wp;
|
|
|
|
m_matProj->Push();
|
|
EF_PushMatrix();
|
|
|
|
iSystem->SetViewCamera(newCam);
|
|
SetCamera(newCam);
|
|
|
|
float plane[4];
|
|
plane[0] = wp->plane.n[0];
|
|
plane[1] = wp->plane.n[1];
|
|
plane[2] = wp->plane.n[2];
|
|
plane[3] = -wp->plane.d;
|
|
|
|
EF_PushFog();
|
|
EF_SetClipPlane(true, plane, false);
|
|
|
|
I3DEngine *eng = (I3DEngine *)iSystem->GetI3DEngine();
|
|
eng->DrawLowDetail(DLD_TERRAIN_WATER | DLD_DETAIL_TEXTURES | DLD_DETAIL_OBJECTS | DLD_FAR_SPRITES | DLD_ENTITIES);
|
|
|
|
/*unsigned char *pic=new unsigned char [m_width*m_height*4];
|
|
glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, pic);
|
|
WriteTGA(pic, m_width, m_height,"Warp.tga");
|
|
delete [] pic;*/
|
|
|
|
if (m_LogFile)
|
|
Logv(SRendItem::m_RecurseLevel, "\n ********** End Render Portal **********\n");
|
|
|
|
m_RP.m_PersFlags &= ~(RBPF_DRAWMIRROR | RBPF_DRAWPORTAL);
|
|
m_RP.m_PersFlags |= prevFlags & (RBPF_DRAWMIRROR | RBPF_DRAWPORTAL);
|
|
|
|
EF_SetClipPlane(false, plane, false);
|
|
EF_PopFog();
|
|
|
|
m_RP.m_CurWarp = prevWarp;
|
|
|
|
iSystem->SetViewCamera(prevCam);
|
|
SetCamera(prevCam);
|
|
|
|
EF_PopMatrix();
|
|
m_matProj->Pop();
|
|
|
|
return true;
|
|
}
|
|
|
|
void sTransformPlane( float *u, const float *v, const float *m )
|
|
{
|
|
float v0=v[0], v1=v[1], v2=v[2], v3=v[3];
|
|
#define M(row,col) m[col*4+row]
|
|
u[0] = v0 * M(0,0) + v1 * M(1,0) + v2 * M(2,0) + v3 * M(3,0);
|
|
u[1] = v0 * M(0,1) + v1 * M(1,1) + v2 * M(2,1) + v3 * M(3,1);
|
|
u[2] = v0 * M(0,2) + v1 * M(1,2) + v2 * M(2,2) + v3 * M(3,2);
|
|
u[3] = v0 * M(0,3) + v1 * M(1,3) + v2 * M(2,3) + v3 * M(3,3);
|
|
#undef M
|
|
}
|
|
|
|
static _inline int Compare(SPreprocess &a, SPreprocess &b)
|
|
{
|
|
int nPr1 = a.m_nPreprocess;
|
|
int nPr2 = b.m_nPreprocess;
|
|
|
|
if (nPr1 < nPr2)
|
|
return -1;
|
|
if (nPr1 > nPr2)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
// Flush all refracted objects in the list
|
|
void CD3D9Renderer::EF_FlushRefractedObjects(SShader *pSHRefr[], CRendElement *pRERefr[], CCObject *pObjRefr[], int nRefrObjects, int nRefrFlags, int DLDFlags)
|
|
{
|
|
if (nRefrFlags & 2)
|
|
{
|
|
Vec3d Angs = GetCamera().GetAngles();
|
|
Vec3d Pos = GetCamera().GetPos();
|
|
m_RP.m_PersFlags |= RBPF_IGNOREREFRACTED;
|
|
if (nRefrObjects > 1)
|
|
pSHRefr[0] = NULL;
|
|
float fMinDist = 99999.0f;
|
|
int nSelectObj = -1;
|
|
for (int i=0; i<nRefrObjects; i++)
|
|
{
|
|
float fDist = pRERefr[i]->mfMinDistanceToCamera(pObjRefr[i]);
|
|
if (fMinDist > fDist)
|
|
{
|
|
fMinDist = fDist;
|
|
nSelectObj = i;
|
|
}
|
|
}
|
|
if (nSelectObj >= 0)
|
|
{
|
|
m_RP.m_pRE = pRERefr[nSelectObj];
|
|
m_RP.m_pCurObject = pObjRefr[nSelectObj];
|
|
SEnvTexture *cm = gRenDev->m_cEF.mfFindSuitableEnvTex(Pos, Angs, false, DLDFlags, true, pSHRefr[0], NULL, NULL, false, NULL);
|
|
}
|
|
m_RP.m_PersFlags &= ~RBPF_IGNOREREFRACTED;
|
|
}
|
|
|
|
if (nRefrFlags & 1)
|
|
{
|
|
m_RP.m_bDrawToTexture = true;
|
|
m_TexMan->StartRefractMap(TO_REFRACTMAP);
|
|
m_RP.m_PersFlags |= RBPF_ONLYREFRACTED;
|
|
EF_RenderPipeLine(EF_Flush);
|
|
m_RP.m_PersFlags &= ~RBPF_ONLYREFRACTED;
|
|
m_TexMan->EndRefractMap();
|
|
// m_TexMan->StartScreenTexMap(TO_SCREENMAP);
|
|
// EF_RenderPipeLine(EF_Flush);
|
|
// m_TexMan->EndScreenTexMap();
|
|
m_RP.m_bDrawToTexture = false;
|
|
//m_RP.m_PersFlags |= RBPF_ONLYREFRACTED;
|
|
//m_RP.m_PersFlags |= RBPF_IGNORERENDERING;
|
|
}
|
|
}
|
|
|
|
// Current scene preprocess operations (drawing to texture, screen effects initializing, ...)
|
|
int CD3D9Renderer::EF_Preprocess(SRendItemPre *ri, int nums, int nume)
|
|
{
|
|
int i, j;
|
|
SShader *Shader;
|
|
SShader *ShaderState;
|
|
SRenderShaderResources *Res;
|
|
int nObject;
|
|
int nFog;
|
|
|
|
SPreprocess Procs[512];
|
|
int nProcs = 0;
|
|
TArray<SRendItemPreprocess> RIs;
|
|
TArray<SWarpSurf> srfs;
|
|
int nPortals = 0;
|
|
int nRefractedStuff = 0;
|
|
|
|
int NumWarps = 0;
|
|
STWarpZone Warps[MAX_WARPS];
|
|
STWarpZone *wp;
|
|
|
|
double time0 = 0;
|
|
ticks(time0);
|
|
|
|
if (m_LogFile)
|
|
Logv(SRendItem::m_RecurseLevel, "*** Start preprocess frame ***\n");
|
|
|
|
int DLDFlags = 0;
|
|
int nReturn = 0;
|
|
|
|
for (i=nums; i<nume; i++)
|
|
{
|
|
if (nProcs >= 512)
|
|
break;
|
|
SRendItem::mfGet(ri[i].SortVal, &nObject, &Shader, &ShaderState, &nFog, &Res);
|
|
if ((ri[i].SortVal.i.High >> 26) != eS_PreProcess)
|
|
break;
|
|
nReturn++;
|
|
for (j=0; j<32; j++)
|
|
{
|
|
int nMask = 1<<j;
|
|
if (nMask >= FSPR_MAX || nMask > Shader->m_nPreprocess)
|
|
break;
|
|
if (nMask & Shader->m_nPreprocess)
|
|
{
|
|
Procs[nProcs].m_nPreprocess = j;
|
|
Procs[nProcs].m_Num = i;
|
|
Procs[nProcs].m_Shader = Shader;
|
|
Procs[nProcs].m_pRes = Res;
|
|
Procs[nProcs].m_RE = ri[i].Item;
|
|
Procs[nProcs].m_nObject = nObject;
|
|
nProcs++;
|
|
}
|
|
}
|
|
}
|
|
if (!nProcs)
|
|
return 0;
|
|
::Sort(&Procs[0], nProcs);
|
|
|
|
if (m_RP.m_pRenderFunc != EF_Flush)
|
|
return nReturn;
|
|
|
|
int nRefrObjects = 0;
|
|
SShader *pSHRefr[8];
|
|
CRendElement *pRERefr[8];
|
|
CCObject *pObjRefr[8];
|
|
|
|
for (i=0; i<nProcs; i++)
|
|
{
|
|
SPreprocess *pr = &Procs[i];
|
|
if (!pr->m_Shader)
|
|
continue;
|
|
switch (pr->m_nPreprocess)
|
|
{
|
|
case SPRID_SCANCM:
|
|
// Draw environment to cube texture
|
|
if (!m_RP.m_bDrawToTexture)
|
|
{
|
|
CCObject *objIgn = m_RP.m_pIgnoreObject;
|
|
Vec3d Pos;
|
|
m_RP.m_pRE = pr->m_RE;
|
|
if (pr->m_nObject < 0)
|
|
Pos(0,0,0);
|
|
else
|
|
{
|
|
CCObject *obj = m_RP.m_VisObjects[pr->m_nObject];
|
|
if (!IsEquivalent(obj->GetTranslation(), Vec3d(0,0,0)))
|
|
m_RP.m_pIgnoreObject = obj;
|
|
Pos = obj->GetTranslation();
|
|
m_RP.m_pCurObject = obj;
|
|
}
|
|
if (m_LogFile)
|
|
Logv(SRendItem::m_RecurseLevel, "*** Draw environment to cube-map ***\n");
|
|
if (!IsEquivalent(Pos,Vec3d(0,0,0)))
|
|
{
|
|
float fDistToCam = (Pos-m_cam.GetPos()).Length();
|
|
SEnvTexture *cm = gRenDev->m_cEF.mfFindSuitableEnvCMap(Pos, false, pr->m_Shader->m_DLDFlags, fDistToCam);
|
|
}
|
|
m_RP.m_pIgnoreObject = objIgn;
|
|
}
|
|
break;
|
|
case SPRID_SCANLCM:
|
|
// Draw environment to cube texture
|
|
if (!m_RP.m_bDrawToTexture)
|
|
{
|
|
CCObject *obj = m_RP.m_VisObjects[pr->m_nObject];
|
|
if ((obj->m_ObjFlags & FOB_ENVLIGHTING) && CV_r_envlighting)
|
|
{
|
|
CCObject *objIgn = m_RP.m_pIgnoreObject;
|
|
Vec3d Pos;
|
|
m_RP.m_pRE = pr->m_RE;
|
|
if (!IsEquivalent(obj->GetTranslation(), Vec3d(0,0,0)))
|
|
m_RP.m_pIgnoreObject = obj;
|
|
Pos = obj->GetTranslation();
|
|
if (m_LogFile)
|
|
Logv(SRendItem::m_RecurseLevel, "*** Draw environment to light cube-map (%.3f, %.3f, %.3f), Time: %.3f s ***\n", Pos.x, Pos.y, Pos.z, iTimer->GetAsyncCurTime());
|
|
if (!IsEquivalent(Pos,Vec3d(0,0,0)))
|
|
{
|
|
float fDR;
|
|
ICVar * pVarDR = iConsole->GetCVar("e_obj_view_dist_ratio");
|
|
if (pVarDR)
|
|
{
|
|
fDR = pVarDR->GetFVal();
|
|
pVarDR->Set(fDR/3.0f);
|
|
}
|
|
int nDLDFlags = -1;
|
|
nDLDFlags &= ~(DLD_SHADOW_MAPS | DLD_ENTITIES | DLD_FIRST_PERSON_CAMERA_OWNER | DLD_TERRAIN_LIGHT | DLD_PARTICLES | DLD_FAR_SPRITES | DLD_DETAIL_TEXTURES | DLD_DETAIL_OBJECTS);
|
|
float fDistToCam = (Pos-m_cam.GetPos()).Length();
|
|
SEnvTexture *cm = gRenDev->m_cEF.mfFindSuitableEnvLCMap(Pos, false, nDLDFlags, fDistToCam, obj);
|
|
if (pVarDR)
|
|
pVarDR->Set(fDR);
|
|
}
|
|
m_RP.m_pIgnoreObject = objIgn;
|
|
}
|
|
}
|
|
break;
|
|
case SPRID_SCANSCR:
|
|
m_TexMan->StartScreenMap(TO_ENVIRONMENT_SCR);
|
|
break;
|
|
case SPRID_SCANTEXWATER:
|
|
if (!m_RP.m_bDrawToTexture && CV_r_waterreflections)
|
|
{
|
|
if (!(gRenDev->m_TexMan->m_Text_WaterMap->m_Flags & FT_BUILD))
|
|
{
|
|
I3DEngine *eng = (I3DEngine *)iSystem->GetI3DEngine();
|
|
float fTimeUpd = eng->GetDistanceToSectorWithWater();
|
|
fTimeUpd *= CV_r_waterupdateFactor;
|
|
if (fTimeUpd > 0.3f)
|
|
fTimeUpd = 0.3f;
|
|
Vec3d camAngs = GetCamera().GetAngles();
|
|
Vec3d camPos = GetCamera().GetPos();
|
|
float fDistCam = (camPos - m_RP.m_LastWaterPosUpdate).Length();
|
|
float fDistAng = (camAngs - m_RP.m_LastWaterAngleUpdate).Length();
|
|
float fFOV = GetCamera().GetFov();
|
|
if (m_RP.m_fLastWaterUpdate-1.0f > m_RP.m_RealTime)
|
|
m_RP.m_fLastWaterUpdate = m_RP.m_RealTime;
|
|
if (m_RP.m_RealTime-m_RP.m_fLastWaterUpdate > fTimeUpd || fDistCam > CV_r_waterupdateDistance || fDistAng>CV_r_waterupdateDeltaAngle || fFOV != m_RP.m_fLastWaterFOVUpdate)
|
|
{
|
|
m_RP.m_fLastWaterUpdate = m_RP.m_RealTime;
|
|
m_RP.m_LastWaterAngleUpdate = camAngs;
|
|
m_RP.m_fLastWaterFOVUpdate = fFOV;
|
|
m_RP.m_LastWaterPosUpdate = camPos;
|
|
|
|
CCamera tmp_cam = GetCamera();
|
|
Plane Pl;
|
|
Pl.n = Vec3d(0,0,1);
|
|
Pl.d = eng->GetWaterLevel();
|
|
Vec3d vCamPos = tmp_cam.GetPos();
|
|
if ((vCamPos | Pl.n) - Pl.d < 0)
|
|
{
|
|
Pl.d = -Pl.d;
|
|
Pl.n = -Pl.n;
|
|
}
|
|
CCObject *savedObj = m_RP.m_pCurObject;
|
|
CCObject *objIgn = m_RP.m_pIgnoreObject;
|
|
CCObject *obj = NULL;
|
|
if (pr->m_nObject > 0)
|
|
obj = m_RP.m_VisObjects[pr->m_nObject];
|
|
m_RP.m_PersFlags |= RBPF_DONTDRAWSUN;
|
|
m_RP.m_pCurObject = obj;
|
|
if (!IsEquivalent(obj->GetTranslation(), Vec3d(0,0,0)))
|
|
m_RP.m_pIgnoreObject = obj;
|
|
if (m_LogFile)
|
|
Logv(SRendItem::m_RecurseLevel, "*** Draw environment to texture for water reflections ***\n");
|
|
m_TexMan->DrawToTexture(Pl, gRenDev->m_TexMan->m_Text_WaterMap, pr->m_Shader->m_DLDFlags);
|
|
m_RP.m_pCurObject = savedObj;
|
|
m_RP.m_pIgnoreObject = objIgn;
|
|
m_RP.m_PersFlags &= ~RBPF_DONTDRAWSUN;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SPRID_SCANTEX:
|
|
if (!m_RP.m_bDrawToTexture)
|
|
{ // Draw environment to texture
|
|
bool bWater = (pr->m_Shader->m_nPreprocess & FSPR_SCANTEXWATER) != 0;
|
|
bool bDraw = true;
|
|
if (!bWater || CV_r_waterrefractions)
|
|
{
|
|
CCObject *obj = m_RP.m_VisObjects[pr->m_nObject];
|
|
if (pr->m_Shader->m_fUpdateFactor > 0)
|
|
{
|
|
float fDist = pr->m_RE->mfMinDistanceToCamera(obj);
|
|
if (fDist > 0)
|
|
{
|
|
fDist *= pr->m_Shader->m_fUpdateFactor;
|
|
if (fDist > 0.5f)
|
|
fDist = 0.5f;
|
|
if (m_RP.m_pCurObject->m_fLastUpdate-1.0f > m_RP.m_RealTime)
|
|
m_RP.m_pCurObject->m_fLastUpdate = m_RP.m_RealTime;
|
|
if (m_RP.m_RealTime-m_RP.m_pCurObject->m_fLastUpdate < fDist)
|
|
bDraw = false;
|
|
else
|
|
m_RP.m_pCurObject->m_fLastUpdate = m_RP.m_RealTime;
|
|
}
|
|
}
|
|
if (bDraw)
|
|
{
|
|
Vec3d Angs = GetCamera().GetAngles();
|
|
Vec3d Pos = GetCamera().GetPos();
|
|
m_RP.m_pRE = pr->m_RE;
|
|
|
|
bool bReflect = false;
|
|
if ((pr->m_Shader->m_Flags3 & (EF3_CLIPPLANE_FRONT | EF3_REFLECTION)))
|
|
bReflect = true;
|
|
if (bReflect)
|
|
{
|
|
m_RP.m_PersFlags |= RBPF_DONTDRAWSUN;
|
|
m_RP.m_pCurObject = obj;
|
|
m_RP.m_pIgnoreObject = obj;
|
|
SEnvTexture *cm = gRenDev->m_cEF.mfFindSuitableEnvTex(Pos, Angs, false, pr->m_Shader->m_DLDFlags, false, pr->m_Shader, pr->m_pRes, obj, bReflect, pr->m_RE);
|
|
m_RP.m_pIgnoreObject = NULL;
|
|
m_RP.m_PersFlags &= ~RBPF_DONTDRAWSUN;
|
|
}
|
|
else
|
|
{
|
|
nRefractedStuff |= 2;
|
|
DLDFlags |= pr->m_Shader->m_DLDFlags;
|
|
obj->m_ObjFlags |= FOB_REFRACTED;
|
|
pSHRefr[nRefrObjects] = pr->m_Shader;
|
|
pRERefr[nRefrObjects] = pr->m_RE;
|
|
pObjRefr[nRefrObjects] = obj;
|
|
if (nRefrObjects != 7)
|
|
nRefrObjects++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SPRID_RAINOVERLAY:
|
|
if (!m_RP.m_bDrawToTexture)
|
|
m_TexMan->DrawToTextureForRainMap(TO_RAINMAP);
|
|
break;
|
|
case SPRID_REFRACTED:
|
|
if (!m_RP.m_bDrawToTexture)
|
|
{
|
|
nRefractedStuff |= 1;
|
|
CCObject *obj = m_RP.m_VisObjects[pr->m_nObject];
|
|
obj->m_ObjFlags |= FOB_REFRACTED;
|
|
}
|
|
break;
|
|
case SPRID_SCREENTEXMAP:
|
|
EF_FlushRefractedObjects(pSHRefr, pRERefr, pObjRefr, nRefrObjects, nRefractedStuff, DLDFlags);
|
|
nRefractedStuff = 0;
|
|
nRefrObjects = 0;
|
|
// copy screen to texture
|
|
if (!m_RP.m_bDrawToTexture)
|
|
{
|
|
m_TexMan->StartScreenTexMap(TO_SCREENMAP);
|
|
// always skip refractive objects..
|
|
m_RP.m_PersFlags |= RBPF_IGNOREREFRACTED;
|
|
}
|
|
case SPRID_DOFMAP:
|
|
if (!m_RP.m_bDrawToTexture)
|
|
{
|
|
m_TexMan->DrawToTextureForDof(TO_DOFMAP);
|
|
}
|
|
case SPRID_SHADOWMAPGEN:
|
|
{
|
|
CCObject *obj = m_RP.m_VisObjects[pr->m_nObject];
|
|
m_RP.m_pCurObject = obj;
|
|
if (pr->m_RE->mfGetType() == eDATA_OcLeaf || pr->m_RE->mfGetType() == eDATA_ShadowMapGen)
|
|
{
|
|
CREOcLeaf * pRE = (CREOcLeaf*)pr->m_RE;
|
|
//ShadowMapFrustum * pFr = obj->m_pShadowFrustum;
|
|
|
|
// Please never comment this lines !!!
|
|
//if (m_LogFile)
|
|
// Logv(SRendItem::m_RecurseLevel, "*** Prepare shadow maps for REOcLeaf***\n");
|
|
//if(obj && pFr && !m_RP.m_bDrawToTexture)
|
|
// PrepareDepthMap(pFr, false);
|
|
}
|
|
}
|
|
break;
|
|
case SPRID_CORONA:
|
|
if (pr->m_nObject>0 && !m_RP.m_bDrawToTexture)
|
|
{
|
|
if (pr->m_RE->mfGetType() == eDATA_Flare)
|
|
{
|
|
CREFlare *fl = (CREFlare *)pr->m_RE;
|
|
CCObject *obj = m_RP.m_VisObjects[pr->m_nObject];
|
|
if (m_LogFile)
|
|
Logv(SRendItem::m_RecurseLevel, "*** Check corona visibility ***\n");
|
|
bool bVis = fl->mfCheckVis(obj);
|
|
}
|
|
}
|
|
break;
|
|
case SPRID_PORTAL:
|
|
{
|
|
if (!CV_r_portals)
|
|
continue;
|
|
|
|
if (m_RP.m_RecurseLevel+1 >= MAX_PORTAL_RECURSES)
|
|
continue;
|
|
|
|
if (!CV_r_portalsrecursive && m_RP.m_CurWarp)
|
|
continue;
|
|
|
|
if (!m_RP.m_CurWarp)
|
|
{
|
|
nPortals = srfs.Num();
|
|
srfs.AddIndex(1);
|
|
srfs[nPortals].nobj = pr->m_nObject;
|
|
srfs[nPortals].srf = pr->m_RE;
|
|
srfs[nPortals].Shader = pr->m_Shader;
|
|
}
|
|
else
|
|
{
|
|
Plane pl;
|
|
pr->m_RE->mfGetPlane(pl);
|
|
if (m_RP.m_CurWarp->plane.d != pl.d || !IsEquivalent(m_RP.m_CurWarp->plane.n,pl.n))
|
|
{
|
|
nPortals = srfs.Num();
|
|
srfs.AddIndex(1);
|
|
srfs[nPortals].nobj = pr->m_nObject;
|
|
srfs[nPortals].srf = pr->m_RE;
|
|
srfs[nPortals].Shader = pr->m_Shader;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
if (pr->m_nObject < 0)
|
|
continue;
|
|
SRendItemPreprocess rip;
|
|
SRendItemPre *r = &ri[pr->m_Num];
|
|
rip.Item = r->Item;
|
|
rip.m_Object = m_RP.m_VisObjects[pr->m_nObject];
|
|
if (rip.m_Object->m_ObjFlags & FOB_CUBE_MASK)
|
|
RIs.AddElem(rip);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (RIs.Num())
|
|
{
|
|
if (m_LogFile)
|
|
Logv(SRendItem::m_RecurseLevel, "*** Preprocess pipeline ***\n");
|
|
SRendItemPreprocess::mfSort(&RIs[0], RIs.Num());
|
|
EF_DrawREPreprocess(&RIs[0], RIs.Num());
|
|
}
|
|
|
|
EF_FlushRefractedObjects(pSHRefr, pRERefr, pObjRefr, nRefrObjects, nRefractedStuff, DLDFlags);
|
|
|
|
if (srfs.Num())
|
|
{
|
|
for (i=0; i<srfs.Num(); i++)
|
|
{
|
|
EF_SetWarpZone(&srfs[i], &NumWarps, Warps);
|
|
}
|
|
|
|
m_RP.m_RecurseLevel++;
|
|
m_RP.m_WasPortals += NumWarps;
|
|
m_RP.m_CurPortal += NumWarps;
|
|
|
|
for (i=0; i<NumWarps; i++)
|
|
{
|
|
wp = &Warps[i];
|
|
|
|
if (m_LogFile)
|
|
Logv(SRendItem::m_RecurseLevel, "*** Start rendering of warp zone %d ***\n", i);
|
|
EF_RenderWarpZone(wp);
|
|
m_RP.m_CurPortal--;
|
|
|
|
EF_PreRender(1);
|
|
|
|
// Render translucent mirror surface(s)
|
|
int nObj = -1;
|
|
SShader *sh = NULL;
|
|
SRenderShaderResources *Res = NULL;
|
|
for (int j=0; j<wp->numSrf; j++)
|
|
{
|
|
SWarpSurf *ws = &wp->Surfs[j];
|
|
if (nObj != ws->nobj)
|
|
{
|
|
if (sh)
|
|
EF_Flush();
|
|
|
|
if (!EF_ObjectChange(sh, Res, ws->nobj, ws->srf))
|
|
continue;
|
|
nObj = ws->nobj;
|
|
}
|
|
if (ws->Shader != sh || ws->ShaderRes != Res)
|
|
{
|
|
if (sh)
|
|
{
|
|
m_RP.m_pRenderFunc();
|
|
sh = NULL;
|
|
}
|
|
|
|
EF_Start(ws->Shader, NULL, ws->ShaderRes, 0, ws->srf);
|
|
|
|
sh = ws->Shader;
|
|
}
|
|
|
|
ws->srf->mfPrepare();
|
|
}
|
|
if (sh)
|
|
m_RP.m_pRenderFunc();
|
|
}
|
|
m_RP.m_RecurseLevel--;
|
|
}
|
|
|
|
if (m_LogFile)
|
|
Logv(SRendItem::m_RecurseLevel, "*** End preprocess frame ***\n");
|
|
|
|
unticks(time0);
|
|
m_RP.m_PS.m_fPreprocessTime += (float)(time0*1000.0*g_SecondsPerCycle);
|
|
|
|
//ResetToDefault();
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
void CD3D9Renderer::EF_EndEf2D(bool bSort)
|
|
{
|
|
int i;
|
|
SShader *Shader, *CurShader, *ShaderState, *CurShaderState;
|
|
SRenderShaderResources *Res, *CurRes;
|
|
|
|
EF_AddClientPolys2D();
|
|
|
|
SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_PREPROCESS_ID] = SRendItem::m_RendItems[EFSLIST_PREPROCESS_ID].Num();
|
|
SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_STENCIL_ID] = SRendItem::m_RendItems[EFSLIST_STENCIL_ID].Num();
|
|
SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_GENERAL_ID] = SRendItem::m_RendItems[EFSLIST_GENERAL_ID].Num();
|
|
SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_UNSORTED_ID] = SRendItem::m_RendItems[EFSLIST_UNSORTED_ID].Num();
|
|
SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_DISTSORT_ID] = SRendItem::m_RendItems[EFSLIST_DISTSORT_ID].Num();
|
|
SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_LAST_ID] = SRendItem::m_RendItems[EFSLIST_LAST_ID].Num();
|
|
int nums = SRendItem::m_StartRI[SRendItem::m_RecurseLevel-1][EFSLIST_GENERAL_ID];
|
|
int nume = SRendItem::m_EndRI[SRendItem::m_RecurseLevel-1][EFSLIST_GENERAL_ID];
|
|
|
|
if (bSort)
|
|
{
|
|
SRendItem::mfSort(&SRendItem::m_RendItems[0][0], nume);
|
|
// If sort number of the first shader is 1 (eS_Preprocess)
|
|
// run preprocess operations for the current frame
|
|
if ((SRendItem::m_RendItems[0][nums].SortVal.i.High >> 26) == eS_PreProcess)
|
|
nums += EF_Preprocess(&SRendItem::m_RendItems[0][0], nums, nume);
|
|
}
|
|
|
|
EF_PreRender(1);
|
|
//ResetToDefault();
|
|
|
|
CurShader = NULL;
|
|
CurRes = NULL;
|
|
CurShaderState = NULL;
|
|
UnINT64 oldVal;
|
|
oldVal.SortVal = -1;
|
|
m_RP.m_Flags = RBF_2D;
|
|
|
|
for (i=nums; i<nume; i++)
|
|
{
|
|
SRendItemPre *ri = &SRendItem::m_RendItems[0][i];
|
|
CRendElement *re = ri->Item;
|
|
if (ri->SortVal.SortVal == oldVal.SortVal)
|
|
{
|
|
re->mfPrepare();
|
|
continue;
|
|
}
|
|
oldVal.SortVal = ri->SortVal.SortVal;
|
|
|
|
SRendItem::mfGet(ri->SortVal, &Shader, &ShaderState, &Res);
|
|
if (Shader != CurShader || Res != CurRes || ShaderState != CurShaderState)
|
|
{
|
|
if (CurShader)
|
|
m_RP.m_pRenderFunc();
|
|
|
|
EF_Start(Shader, ShaderState, Res, re);
|
|
|
|
CurShader = Shader;
|
|
CurShaderState = ShaderState;
|
|
CurRes = Res;
|
|
}
|
|
|
|
re->mfPrepare();
|
|
}
|
|
if (CurShader)
|
|
m_RP.m_pRenderFunc();
|
|
|
|
EF_PostRender();
|
|
}
|