1
0
forked from 0ad/0ad

#Models receive shadows now, including self-shadows.

This is a huge patch, including:
* add a LitRenderModifier abstract base class for RenderModifiers with
  shadow+light
* add LitRenderModifiers for all types of models
* add STREAM_TEXGENTOUV1 to request generation of shadow map texcoords
  for models
* create facilities to pass the texture matrix from the
  RenderModifier (fragment stage) to the ModelRenderer (vertex stage)
* split ambient and diffuse terms of lighting until further down in the
  pipeline; this is necessary since shadowed regions receive only
ambient light
* small improvement in how RenderPathVertexShader scales to a greater
  number of vertex shaders

This was SVN commit r3690.
This commit is contained in:
prefect 2006-03-26 00:54:20 +00:00
parent 0bd5778536
commit e2bbd9a654
28 changed files with 1292 additions and 330 deletions

View File

@ -0,0 +1,17 @@
vec3 lighting(vec3 normal);
vec3 InstancingNormal(vec3 normal);
vec4 InstancingPosition(vec4 position);
vec4 postouv1(vec4 pos);
void main()
{
vec3 normal = InstancingNormal(gl_Normal);
vec4 worldPos = InstancingPosition(gl_Vertex);
gl_FrontColor = vec4(lighting(normal),1.0) * gl_Color;
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = postouv1(worldPos);
gl_Position = gl_ModelViewProjectionMatrix * worldPos;
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
<Program>
<Shaders>
<Shader type="VERTEX_SHADER">shaders/instancing_lightp.vs</Shader>
<Shader type="VERTEX_SHADER">shaders/instancing_base.vs</Shader>
<Shader type="VERTEX_SHADER">shaders/globallight.vs</Shader>
<Shader type="VERTEX_SHADER">shaders/postouv1.vs</Shader>
</Shaders>
</Program>

View File

@ -0,0 +1,12 @@
vec4 InstancingPosition(vec4 position);
vec4 postouv1(vec4 pos);
void main()
{
vec4 worldPos = InstancingPosition(gl_Vertex);
gl_FrontColor = gl_Color;
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = postouv1(worldPos);
gl_Position = gl_ModelViewProjectionMatrix * worldPos;
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
<Program>
<Shaders>
<Shader type="VERTEX_SHADER">shaders/instancingp.vs</Shader>
<Shader type="VERTEX_SHADER">shaders/instancing_base.vs</Shader>
<Shader type="VERTEX_SHADER">shaders/postouv1.vs</Shader>
</Shaders>
</Program>

View File

@ -0,0 +1,10 @@
vec3 lighting(vec3 normal);
vec4 postouv1(vec4 pos);
void main()
{
gl_FrontColor = vec4(lighting(gl_Normal),1.0) * gl_Color;
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = postouv1(gl_Vertex);
gl_Position = ftransform();
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
<Program>
<Shaders>
<Shader type="VERTEX_SHADER">shaders/model_lightp.vs</Shader>
<Shader type="VERTEX_SHADER">shaders/globallight.vs</Shader>
<Shader type="VERTEX_SHADER">shaders/postouv1.vs</Shader>
</Shaders>
</Program>

View File

@ -0,0 +1,14 @@
uniform vec4 TextureMatrix1;
uniform vec4 TextureMatrix2;
uniform vec4 TextureMatrix3;
vec4 postouv1(vec4 pos)
{
vec3 tmp;
tmp.x = dot(TextureMatrix1, pos);
tmp.y = dot(TextureMatrix2, pos);
tmp.z = dot(TextureMatrix3, pos);
return vec4(tmp, 1.0);
}

View File

@ -92,14 +92,18 @@ struct FixedFunctionModelRendererInternals
/// Previously prepared modeldef
FFModelDef* ffmodeldef;
/// If true, primary color will only contain the diffuse term
bool colorIsDiffuseOnly;
};
// Construction and Destruction
FixedFunctionModelRenderer::FixedFunctionModelRenderer()
FixedFunctionModelRenderer::FixedFunctionModelRenderer(bool colorIsDiffuseOnly)
{
m = new FixedFunctionModelRendererInternals;
m->ffmodeldef = 0;
m->colorIsDiffuseOnly = colorIsDiffuseOnly;
}
FixedFunctionModelRenderer::~FixedFunctionModelRenderer()
@ -159,7 +163,7 @@ void FixedFunctionModelRenderer::UpdateModelData(CModel* model, void* data, u32
VertexArrayIterator<SColor4ub> Color = ffmodel->m_Color.GetIterator<SColor4ub>();
ModelRenderer::BuildColor4ub(model, Normal, Color);
ModelRenderer::BuildColor4ub(model, Normal, Color, m->colorIsDiffuseOnly);
// upload everything to vertex buffer
ffmodel->m_Array.Upload();
@ -178,12 +182,28 @@ void FixedFunctionModelRenderer::DestroyModelData(CModel* UNUSED(model), void* d
// Setup one rendering pass
void FixedFunctionModelRenderer::BeginPass(uint streamflags)
void FixedFunctionModelRenderer::BeginPass(uint streamflags, const CMatrix3D* texturematrix)
{
debug_assert(streamflags == streamflags & (STREAM_POS|STREAM_UV0|STREAM_COLOR|STREAM_TEXGENTOUV1));
glEnableClientState(GL_VERTEX_ARRAY);
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR) glEnableClientState(GL_COLOR_ARRAY);
if (streamflags & STREAM_TEXGENTOUV1)
{
pglActiveTextureARB(GL_TEXTURE1);
pglClientActiveTextureARB(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glMatrixMode(GL_TEXTURE);
glLoadMatrixf(&texturematrix->_11);
glMatrixMode(GL_MODELVIEW);
pglActiveTextureARB(GL_TEXTURE0);
pglClientActiveTextureARB(GL_TEXTURE0);
}
}
@ -192,6 +212,20 @@ void FixedFunctionModelRenderer::EndPass(uint streamflags)
{
if (streamflags & STREAM_UV0) glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY);
if (streamflags & STREAM_TEXGENTOUV1)
{
pglActiveTextureARB(GL_TEXTURE1);
pglClientActiveTextureARB(GL_TEXTURE1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
pglActiveTextureARB(GL_TEXTURE0);
pglClientActiveTextureARB(GL_TEXTURE0);
}
glDisableClientState(GL_VERTEX_ARRAY);
}
@ -226,6 +260,14 @@ void FixedFunctionModelRenderer::RenderModel(uint streamflags, CModel* model, vo
glVertexPointer(3, GL_FLOAT, stride, base + ffmodel->m_Position.offset);
if (streamflags & STREAM_COLOR)
glColorPointer(3, ffmodel->m_Color.type, stride, base + ffmodel->m_Color.offset);
if (streamflags & STREAM_TEXGENTOUV1)
{
pglClientActiveTextureARB(GL_TEXTURE1);
pglActiveTextureARB(GL_TEXTURE1);
glTexCoordPointer(3, GL_FLOAT, stride, base + ffmodel->m_Position.offset);
pglClientActiveTextureARB(GL_TEXTURE0);
pglActiveTextureARB(GL_TEXTURE0);
}
// render the lot
size_t numFaces = mdldef->GetNumFaces();

View File

@ -23,15 +23,21 @@ struct FixedFunctionModelRendererInternals;
class FixedFunctionModelRenderer : public ModelVertexRenderer
{
public:
FixedFunctionModelRenderer();
/**
* FixedFunctionModelRenderer: Constructor.
*
* @param colorIsDiffuseOnly if true, the primary color sent to the fragment stage
* contains only the diffuse term, and not the ambient
*/
FixedFunctionModelRenderer(bool colorIsDiffuseOnly);
~FixedFunctionModelRenderer();
// Implementations
void* CreateModelData(CModel* model);
void UpdateModelData(CModel* model, void* data, u32 updateflags);
void DestroyModelData(CModel* model, void* data);
void BeginPass(uint streamflags);
void BeginPass(uint streamflags, const CMatrix3D* texturematrix);
void EndPass(uint streamflags);
void PrepareModelDef(uint streamflags, CModelDefPtr def);
void RenderModel(uint streamflags, CModel* model, void* data);

View File

@ -76,14 +76,18 @@ struct HWLightingModelRendererInternals
/// Previously prepared modeldef
HWLModelDef* hwlmodeldef;
/// If true, primary color will only contain the diffuse term
bool colorIsDiffuseOnly;
};
// Construction and Destruction
HWLightingModelRenderer::HWLightingModelRenderer()
HWLightingModelRenderer::HWLightingModelRenderer(bool colorIsDiffuseOnly)
{
m = new HWLightingModelRendererInternals;
m->hwlmodeldef = 0;
m->colorIsDiffuseOnly = colorIsDiffuseOnly;
}
HWLightingModelRenderer::~HWLightingModelRenderer()
@ -170,26 +174,76 @@ void HWLightingModelRenderer::DestroyModelData(CModel* UNUSED(model), void* data
// Setup one rendering pass
void HWLightingModelRenderer::BeginPass(uint streamflags)
void HWLightingModelRenderer::BeginPass(uint streamflags, const CMatrix3D* texturematrix)
{
debug_assert(streamflags == (streamflags & (STREAM_POS|STREAM_UV0|STREAM_COLOR|STREAM_TEXGENTOUV1)));
glEnableClientState(GL_VERTEX_ARRAY);
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR)
{
RenderPathVertexShader* rpvs = g_Renderer.m_VertexShader;
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
int idx;
VS_GlobalLight* lightConfig;
ogl_program_use(g_Renderer.m_VertexShader->m_ModelLight);
idx = g_Renderer.m_VertexShader->m_ModelLight_Ambient;
pglUniform3fvARB(idx, 1, &lightEnv.m_UnitsAmbientColor.X);
idx = g_Renderer.m_VertexShader->m_ModelLight_SunDir;
pglUniform3fvARB(idx, 1, &lightEnv.GetSunDir().X);
idx = g_Renderer.m_VertexShader->m_ModelLight_SunColor;
pglUniform3fvARB(idx, 1, &lightEnv.m_SunColor.X);
if (streamflags & STREAM_TEXGENTOUV1)
{
ogl_program_use(rpvs->m_ModelLightP);
lightConfig = &rpvs->m_ModelLightP_Light;
rpvs->m_ModelLightP_PosToUV1.SetMatrix(*texturematrix);
}
else
{
ogl_program_use(rpvs->m_ModelLight);
lightConfig = &rpvs->m_ModelLight_Light;
}
if (m->colorIsDiffuseOnly)
lightConfig->SetAmbient(RGBColor(0,0,0));
else
lightConfig->SetAmbient(lightEnv.m_UnitsAmbientColor);
lightConfig->SetSunDir(lightEnv.GetSunDir());
lightConfig->SetSunColor(lightEnv.m_SunColor);
glEnableClientState(GL_NORMAL_ARRAY);
}
else
{
if (streamflags & STREAM_TEXGENTOUV1)
{
pglActiveTextureARB(GL_TEXTURE1);
float tmp[4];
glEnable(GL_TEXTURE_GEN_S);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
tmp[0] = texturematrix->_11;
tmp[1] = texturematrix->_12;
tmp[2] = texturematrix->_13;
tmp[3] = texturematrix->_14;
glTexGenfv(GL_S, GL_OBJECT_PLANE, tmp);
glEnable(GL_TEXTURE_GEN_T);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
tmp[0] = texturematrix->_21;
tmp[1] = texturematrix->_22;
tmp[2] = texturematrix->_23;
tmp[3] = texturematrix->_24;
glTexGenfv(GL_T, GL_OBJECT_PLANE, tmp);
glEnable(GL_TEXTURE_GEN_R);
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
tmp[0] = texturematrix->_31;
tmp[1] = texturematrix->_32;
tmp[2] = texturematrix->_33;
tmp[3] = texturematrix->_34;
glTexGenfv(GL_R, GL_OBJECT_PLANE, tmp);
pglActiveTextureARB(GL_TEXTURE0);
}
}
}
@ -203,6 +257,19 @@ void HWLightingModelRenderer::EndPass(uint streamflags)
glDisableClientState(GL_NORMAL_ARRAY);
}
else
{
if (streamflags & STREAM_TEXGENTOUV1)
{
pglActiveTextureARB(GL_TEXTURE1);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_TEXTURE_GEN_R);
pglActiveTextureARB(GL_TEXTURE0);
}
}
glDisableClientState(GL_VERTEX_ARRAY);
}

View File

@ -19,22 +19,28 @@ struct HWLightingModelRendererInternals;
/**
* Class HWLightingModelRenderer: Render animated models using vertex
* shaders for lighting.
*
*
* @note You should verify hardware capabilities using IsAvailable
* before creating this model renderer.
*/
class HWLightingModelRenderer : public ModelVertexRenderer
{
public:
HWLightingModelRenderer();
/**
* HWLightingModelRenderer: Constructor.
*
* @param colorIsDiffuseOnly if true, the primary color sent to the fragment stage
* contains only the diffuse term, and not the ambient
*/
HWLightingModelRenderer(bool colorIsDiffuseOnly);
~HWLightingModelRenderer();
// Implementations
void* CreateModelData(CModel* model);
void UpdateModelData(CModel* model, void* data, u32 updateflags);
void DestroyModelData(CModel* model, void* data);
void BeginPass(uint streamflags);
void BeginPass(uint streamflags, const CMatrix3D* texturematrix);
void EndPass(uint streamflags);
void PrepareModelDef(uint streamflags, CModelDefPtr def);
void RenderModel(uint streamflags, CModel* model, void* data);
@ -42,10 +48,10 @@ public:
/**
* IsAvailable: Determines whether this model renderer can be used
* given the OpenGL implementation specific limits.
*
*
* @note Do not attempt to construct a HWLightingModelRenderer object
* when IsAvailable returns false.
*
*
* @return true if the OpenGL implementation can support this
* model renderer.
*/

View File

@ -96,14 +96,21 @@ struct InstancingModelRendererInternals
/// Previously prepared modeldef
IModelDef* imodeldef;
/// If true, primary color will only contain the diffuse term
bool colorIsDiffuseOnly;
/// After BeginPass, this points to the instancing matrix interface
VS_Instancing* instancingConfig;
};
// Construction and Destruction
InstancingModelRenderer::InstancingModelRenderer()
InstancingModelRenderer::InstancingModelRenderer(bool colorIsDiffuseOnly)
{
m = new InstancingModelRendererInternals;
m->imodeldef = 0;
m->colorIsDiffuseOnly = colorIsDiffuseOnly;
}
InstancingModelRenderer::~InstancingModelRenderer()
@ -150,29 +157,58 @@ void InstancingModelRenderer::DestroyModelData(CModel* UNUSED(model), void* UNUS
// Setup one rendering pass.
void InstancingModelRenderer::BeginPass(uint streamflags)
void InstancingModelRenderer::BeginPass(uint streamflags, const CMatrix3D* texturematrix)
{
debug_assert(streamflags == (streamflags & (STREAM_POS|STREAM_UV0|STREAM_COLOR|STREAM_TEXGENTOUV1)));
RenderPathVertexShader* rpvs = g_Renderer.m_VertexShader;
glEnableClientState(GL_VERTEX_ARRAY);
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR)
{
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
int idx;
VS_GlobalLight* lightConfig;
ogl_program_use(g_Renderer.m_VertexShader->m_InstancingLight);
idx = g_Renderer.m_VertexShader->m_InstancingLight_Ambient;
pglUniform3fvARB(idx, 1, &lightEnv.m_UnitsAmbientColor.X);
idx = g_Renderer.m_VertexShader->m_InstancingLight_SunDir;
pglUniform3fvARB(idx, 1, &lightEnv.GetSunDir().X);
idx = g_Renderer.m_VertexShader->m_InstancingLight_SunColor;
pglUniform3fvARB(idx, 1, &lightEnv.m_SunColor.X);
if (streamflags & STREAM_TEXGENTOUV1)
{
ogl_program_use(rpvs->m_InstancingLightP);
lightConfig = &rpvs->m_InstancingLightP_Light;
m->instancingConfig = &rpvs->m_InstancingLightP_Instancing;
rpvs->m_InstancingLightP_PosToUV1.SetMatrix(*texturematrix);
}
else
{
ogl_program_use(rpvs->m_InstancingLight);
lightConfig = &rpvs->m_InstancingLight_Light;
m->instancingConfig = &rpvs->m_InstancingLight_Instancing;
}
if (m->colorIsDiffuseOnly)
lightConfig->SetAmbient(RGBColor(0,0,0));
else
lightConfig->SetAmbient(lightEnv.m_UnitsAmbientColor);
lightConfig->SetSunDir(lightEnv.GetSunDir());
lightConfig->SetSunColor(lightEnv.m_SunColor);
glEnableClientState(GL_NORMAL_ARRAY);
}
else
{
ogl_program_use(g_Renderer.m_VertexShader->m_Instancing);
if (streamflags & STREAM_TEXGENTOUV1)
{
ogl_program_use(rpvs->m_InstancingP);
m->instancingConfig = &rpvs->m_InstancingP_Instancing;
rpvs->m_InstancingP_PosToUV1.SetMatrix(*texturematrix);
}
else
{
ogl_program_use(rpvs->m_Instancing);
m->instancingConfig = &rpvs->m_Instancing_Instancing;
}
}
}
@ -214,23 +250,14 @@ void InstancingModelRenderer::RenderModel(uint streamflags, CModel* model, void*
{
CModelDefPtr mdldef = model->GetModelDef();
const CMatrix3D& mat = model->GetTransform();
RenderPathVertexShader* rpvs = g_Renderer.m_VertexShader;
if (streamflags & STREAM_COLOR)
{
CColor sc = model->GetShadingColor();
glColor3f(sc.r, sc.g, sc.b);
}
pglVertexAttrib4fARB(rpvs->m_InstancingLight_Instancing1, mat._11, mat._12, mat._13, mat._14);
pglVertexAttrib4fARB(rpvs->m_InstancingLight_Instancing2, mat._21, mat._22, mat._23, mat._24);
pglVertexAttrib4fARB(rpvs->m_InstancingLight_Instancing3, mat._31, mat._32, mat._33, mat._34);
}
else
{
pglVertexAttrib4fARB(rpvs->m_Instancing_Instancing1, mat._11, mat._12, mat._13, mat._14);
pglVertexAttrib4fARB(rpvs->m_Instancing_Instancing2, mat._21, mat._22, mat._23, mat._24);
pglVertexAttrib4fARB(rpvs->m_Instancing_Instancing3, mat._31, mat._32, mat._33, mat._34);
}
m->instancingConfig->SetMatrix(mat);
// render the lot
size_t numFaces = mdldef->GetNumFaces();

View File

@ -19,33 +19,39 @@ struct InstancingModelRendererInternals;
/**
* Class InstancingModelRenderer: Render non-animated (but potentially
* moving models) using vertex shaders and minimal state changes.
*
*
* @note You should verify hardware capabilities using IsAvailable
* before creating this model renderer.
*/
class InstancingModelRenderer : public ModelVertexRenderer
{
public:
InstancingModelRenderer();
/**
* InstancingModelRenderer: Constructor.
*
* @param colorIsDiffuseOnly if true, the primary color sent to the fragment stage
* contains only the diffuse term, and not the ambient
*/
InstancingModelRenderer(bool colorIsDiffuseOnly);
~InstancingModelRenderer();
// Implementations
void* CreateModelData(CModel* model);
void UpdateModelData(CModel* model, void* data, u32 updateflags);
void DestroyModelData(CModel* model, void* data);
void BeginPass(uint streamflags);
void BeginPass(uint streamflags, const CMatrix3D* texturematrix);
void EndPass(uint streamflags);
void PrepareModelDef(uint streamflags, CModelDefPtr def);
void RenderModel(uint streamflags, CModel* model, void* data);
/**
* IsAvailable: Determines whether this model renderer can be used
* given the OpenGL implementation specific limits.
*
*
* @note Do not attempt to construct a InstancingModelRenderer object
* when IsAvailable returns false.
*
*
* @return true if the OpenGL implementation can support this
* model renderer.
*/

View File

@ -149,7 +149,8 @@ void ModelRenderer::BuildPositionAndNormals(
void ModelRenderer::BuildColor4ub(
CModel* model,
VertexArrayIterator<CVector3D> Normal,
VertexArrayIterator<SColor4ub> Color)
VertexArrayIterator<SColor4ub> Color,
bool onlyDiffuse)
{
PROFILE( "lighting vertices" );
@ -159,13 +160,27 @@ void ModelRenderer::BuildColor4ub(
CColor shadingColor = model->GetShadingColor();
RGBColor tempcolor;
for (uint j=0; j<numVertices; j++)
if (onlyDiffuse)
{
lightEnv.EvaluateUnit(Normal[j], tempcolor);
tempcolor.X *= shadingColor.r;
tempcolor.Y *= shadingColor.g;
tempcolor.Z *= shadingColor.b;
*(u32*)&Color[j] = ConvertRGBColorTo4ub(tempcolor);
for (uint j=0; j<numVertices; j++)
{
lightEnv.EvaluateDirect(Normal[j], tempcolor);
tempcolor.X *= shadingColor.r;
tempcolor.Y *= shadingColor.g;
tempcolor.Z *= shadingColor.b;
*(u32*)&Color[j] = ConvertRGBColorTo4ub(tempcolor);
}
}
else
{
for (uint j=0; j<numVertices; j++)
{
lightEnv.EvaluateUnit(Normal[j], tempcolor);
tempcolor.X *= shadingColor.r;
tempcolor.Y *= shadingColor.g;
tempcolor.Z *= shadingColor.b;
*(u32*)&Color[j] = ConvertRGBColorTo4ub(tempcolor);
}
}
}
@ -451,8 +466,12 @@ void BatchModelRenderer::Render(RenderModifierPtr modifier, u32 flags)
do
{
uint streamflags = modifier->BeginPass(pass);
const CMatrix3D* texturematrix = 0;
m->vertexRenderer->BeginPass(streamflags);
if (streamflags & STREAM_TEXGENTOUV1)
texturematrix = modifier->GetTexGenMatrix(pass);
m->vertexRenderer->BeginPass(streamflags, texturematrix);
m->RenderAllModels(modifier, flags, pass, streamflags);

View File

@ -23,6 +23,9 @@
class RenderModifier;
typedef boost::shared_ptr<RenderModifier> RenderModifierPtr;
class LitRenderModifier;
typedef boost::shared_ptr<LitRenderModifier> LitRenderModifierPtr;
class ModelVertexRenderer;
typedef boost::shared_ptr<ModelVertexRenderer> ModelVertexRendererPtr;
@ -199,11 +202,14 @@ public:
* @param Color Points to the array that will receive the lit vertex color.
* The array behind the iterator must large enough to hold
* model->GetModelDef()->GetNumVertices() vertices.
* @param onlyDiffuse if true, color will only contain the diffuse term (instead
* of both ambient and diffuse)
*/
static void BuildColor4ub(
CModel* model,
VertexArrayIterator<CVector3D> Normal,
VertexArrayIterator<SColor4ub> Color);
VertexArrayIterator<SColor4ub> Color,
bool onlyDiffuse);
/**
* BuildUV: Copy UV coordinates into the given vertex array.

View File

@ -20,7 +20,7 @@ class CModel;
* Class ModelVertexRenderer: Normal ModelRenderer implementations delegate
* vertex array management and vertex transformation to an implementation of
* ModelVertexRenderer.
*
*
* ModelVertexRenderer implementations should be designed so that one
* instance of the implementation can be used with more than one ModelRenderer
* simultaneously.
@ -29,14 +29,14 @@ class ModelVertexRenderer
{
public:
virtual ~ModelVertexRenderer() { }
/**
* CreateModelData: Create internal data for one model.
*
* ModelRenderer implementations must call this once for every
* model that will later be rendered.
*
*
* ModelVertexRenderer implementations should use this function to
* create per-CModel and per-CModelDef data like vertex arrays.
*
@ -58,11 +58,11 @@ public:
* value of updateflags will be zero.
* This implies that this function will also be called at least once
* between a call to CreateModelData and a call to RenderModel.
*
*
* ModelVertexRenderer implementations should use this function to
* perform software vertex transforms and potentially other per-frame
* calculations.
*
*
* @param model The model.
* @param data Private data as returned by CreateModelData.
* @param updateflags Flags indicating which data has changed during
@ -71,7 +71,7 @@ public:
*/
virtual void UpdateModelData(CModel* model, void* data, u32 updateflags) = 0;
/**
* DestroyModelData: Release all per-model data that has been allocated
* by CreateModelData or UpdateModelData.
@ -80,7 +80,7 @@ public:
* called exactly once for every call to CreateModelData. This can be
* achieved by deriving from CModelRData and calling DestroyModelData
* in the derived class' destructor.
*
*
* ModelVertexRenderer implementations need not track the CModel
* instances for which per-model data has been created.
*
@ -89,7 +89,7 @@ public:
*/
virtual void DestroyModelData(CModel* model, void* data) = 0;
/**
* BeginPass: Setup global OpenGL state for this ModelVertexRenderer.
*
@ -103,12 +103,15 @@ public:
*
* Recursive calls to BeginPass are not allowed, and every BeginPass
* is matched by a corresponding call to EndPass.
*
*
* @param streamflags Vertex streams required by the fragment stage.
* @param texturematrix if texgen is requested in streamflags, this points to the
* texture matrix that must be used to transform vertex positions into texture
* coordinates
*/
virtual void BeginPass(uint streamflags) = 0;
virtual void BeginPass(uint streamflags, const CMatrix3D* texturematrix) = 0;
/**
* EndPass: Cleanup OpenGL state set up by BeginPass.
*
@ -121,11 +124,11 @@ public:
*/
virtual void EndPass(uint streamflags) = 0;
/**
* PrepareModelDef: Setup OpenGL state for rendering of models that
* use the given CModelDef object as base.
*
*
* ModelRenderer implementations must call this function before
* rendering a sequence of models based on the given CModelDef.
* When a ModelRenderer switches back and forth between CModelDefs,
@ -141,7 +144,7 @@ public:
/**
* RenderModel: Invoke the rendering commands for the given model.
*
*
* ModelRenderer implementations must call this function to perform
* the actual rendering.
*

View File

@ -13,6 +13,9 @@
#include "renderer/Renderer.h"
#include "renderer/PlayerRenderer.h"
#include "renderer/ShadowMap.h"
#include "graphics/LightEnv.h"
#include "graphics/Model.h"
#include "ps/CLogger.h"
@ -40,14 +43,14 @@ bool FastPlayerColorRender::IsAvailable()
u32 FastPlayerColorRender::BeginPass(uint pass)
{
debug_assert(pass == 0);
// Nice player color uses a single pass with three texture environments
// Fast player color uses a single pass with three texture environments
// Note: This uses ARB_texture_env_crossbar (which is checked in GameSetup)
//
// We calculate: Result = Color*Texture*(PlayerColor*(1-Texture.a) + 1.0*Texture.a)
// Algebra gives us:
// Result = (1 - ((1 - PlayerColor) * (1 - Texture.a)))*Texture*Color
// TexEnv #0
pglActiveTextureARB(GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
@ -56,7 +59,7 @@ u32 FastPlayerColorRender::BeginPass(uint pass)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_ONE_MINUS_SRC_COLOR);
// Don't care about alpha; set it to something harmless
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE0);
@ -76,7 +79,7 @@ u32 FastPlayerColorRender::BeginPass(uint pass)
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
// TexEnv #2
pglActiveTextureARB(GL_TEXTURE0+2);
glEnable(GL_TEXTURE_2D);
@ -91,7 +94,7 @@ u32 FastPlayerColorRender::BeginPass(uint pass)
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
pglActiveTextureARB(GL_TEXTURE0);
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
@ -106,7 +109,7 @@ bool FastPlayerColorRender::EndPass(uint UNUSED(pass))
pglActiveTextureARB(GL_TEXTURE2);
glDisable(GL_TEXTURE_2D);
pglActiveTextureARB(GL_TEXTURE0);
return true;
}
@ -143,7 +146,7 @@ u32 SlowPlayerColorRender::BeginPass(uint pass)
{
// We calculate: Result = (Color*Texture)*Texture.a + (Color*Texture*PlayerColor)*(1-Texture.a)
// Modulation is done via texture environments, the final interpolation is done via blending
if (pass == 0)
{
// TexEnv #0
@ -154,12 +157,12 @@ u32 SlowPlayerColorRender::BeginPass(uint pass)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
// Don't care about alpha; set it to something harmless
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
// Render it!
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
}
@ -172,12 +175,12 @@ u32 SlowPlayerColorRender::BeginPass(uint pass)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
// Alpha = Opacity of non-player colored layer
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
// TexEnv #1
pglActiveTextureARB(GL_TEXTURE1);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
@ -186,20 +189,20 @@ u32 SlowPlayerColorRender::BeginPass(uint pass)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
// Pass alpha unchanged
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
pglActiveTextureARB(GL_TEXTURE0);
// Setup blending
glEnable(GL_BLEND);
glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_LESS, 1.0);
glDepthMask(0);
// Render it!
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
}
@ -217,7 +220,7 @@ bool SlowPlayerColorRender::EndPass(uint pass)
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glDepthMask(1);
return true;
}
@ -242,3 +245,160 @@ void SlowPlayerColorRender::PrepareModel(uint pass, CModel* model)
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// LitPlayerColorRender
LitPlayerColorRender::LitPlayerColorRender()
{
}
LitPlayerColorRender::~LitPlayerColorRender()
{
}
u32 LitPlayerColorRender::BeginPass(uint pass)
{
debug_assert(GetShadowMap() && GetShadowMap()->GetUseDepthTexture());
if (pass == 0)
{
// First pass: Lay down the material color
// We calculate:
// Material = Texture*(PlayerColor*(1.0-Texture.a) + 1.0*Texture.a))
// = (1 - ((1 - PlayerColor) * (1 - Texture.a)))*Texture
// Incoming Color holds the player color
// Texture 0 holds the model's texture
// TexEnv #0
pglActiveTextureARB(GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_ONE_MINUS_SRC_COLOR);
// Don't care about alpha; set it to something harmless
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
// TexEnv #1
pglActiveTextureARB(GL_TEXTURE0+1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_ONE_MINUS_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
// Don't care about alpha; set it to something harmless
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
pglActiveTextureARB(GL_TEXTURE0);
return STREAM_POS|STREAM_UV0;
}
else
{
// Second pass: Multiply with lighting
//
// We calculate:
// Lighting = Ambient + Diffuse * Shadow
// and modulate with frame buffer contents
//
// Incoming color is diffuse
// Texture 1 is the shadow map
// TexEnv #0
pglActiveTextureARB(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE1);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
// TexEnv #1
pglActiveTextureARB(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &GetLightEnv()->m_UnitsAmbientColor.X);
pglActiveTextureARB(GL_TEXTURE0);
// Blending, Z settings
glEnable(GL_BLEND);
glBlendFunc(GL_DST_COLOR, GL_ZERO);
glDepthMask(0);
return STREAM_POS|STREAM_COLOR|STREAM_TEXGENTOUV1;
}
}
bool LitPlayerColorRender::EndPass(uint pass)
{
if (pass == 0)
{
return false;
}
else
{
// Restore state
pglActiveTextureARB(GL_TEXTURE1);
glDisable(GL_TEXTURE_2D);
pglActiveTextureARB(GL_TEXTURE0);
glDisable(GL_BLEND);
glDepthMask(1);
return true;
}
}
const CMatrix3D* LitPlayerColorRender::GetTexGenMatrix(uint UNUSED(pass))
{
return &GetShadowMap()->GetTextureMatrix();
}
void LitPlayerColorRender::PrepareTexture(uint pass, CTexture* texture)
{
if (pass == 0)
g_Renderer.SetTexture(0, texture);
}
void LitPlayerColorRender::PrepareModel(uint pass, CModel* model)
{
if (pass == 0)
{
// Get the player color
SMaterialColor colour = model->GetMaterial().GetPlayerColor();
// Send the player color
glColor3f(colour.r, colour.g, colour.b);
}
}

View File

@ -32,14 +32,14 @@ public:
bool EndPass(uint pass);
void PrepareTexture(uint pass, CTexture* texture);
void PrepareModel(uint pass, CModel* model);
/**
* IsAvailable: Determines whether this RenderModifier can be used
* given the OpenGL implementation specific limits.
*
*
* @note Do not attempt to construct a FastPlayerColorRender object
* when IsAvailable returns false.
*
*
* @return true if the OpenGL implementation can support this
* RenderModifier.
*/
@ -50,7 +50,7 @@ public:
/**
* Class SlowPlayerColorRender: Render models fully textured and lit
* plus player color using multi-pass.
*
*
* It has the same visual result as FastPlayerColorRender (except for
* potential precision issues due to the multi-passing).
*/
@ -67,4 +67,27 @@ public:
void PrepareModel(uint pass, CModel* model);
};
/**
* Class LitPlayerColorRender: Render models fully textured and lit including shadows
* and player color.
*
* @note Only use a LitPlayerColorRenderer instance when depth texture based shadows
* are supported by the OpenGL implementation (as verified by CRenderer::m_Caps::m_DepthTextureShadows).
*/
class LitPlayerColorRender : public LitRenderModifier
{
public:
LitPlayerColorRender();
~LitPlayerColorRender();
// Implementation
u32 BeginPass(uint pass);
bool EndPass(uint pass);
const CMatrix3D* GetTexGenMatrix(uint pass);
void PrepareTexture(uint pass, CTexture* texture);
void PrepareModel(uint pass, CModel* model);
};
#endif

View File

@ -14,13 +14,17 @@
#include "Vector3D.h"
#include "Vector4D.h"
#include "maths/Matrix3D.h"
#include "ps/CLogger.h"
#include "graphics/Color.h"
#include "graphics/LightEnv.h"
#include "graphics/Model.h"
#include "renderer/RenderModifiers.h"
#include "renderer/Renderer.h"
#include "renderer/ShadowMap.h"
#define LOG_CATEGORY "graphics"
@ -29,11 +33,42 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// RenderModifier implementation
const CMatrix3D* RenderModifier::GetTexGenMatrix(uint UNUSED(pass))
{
debug_warn("GetTexGenMatrix not implemented by a derived RenderModifier");
return 0;
}
void RenderModifier::PrepareModel(uint UNUSED(pass), CModel* UNUSED(model))
{
}
///////////////////////////////////////////////////////////////////////////////////////////////
// LitRenderModifier implementation
LitRenderModifier::LitRenderModifier()
: m_Shadow(0), m_LightEnv(0)
{
}
LitRenderModifier::~LitRenderModifier()
{
}
// Set the shadow map for subsequent rendering
void LitRenderModifier::SetShadowMap(const ShadowMap* shadow)
{
m_Shadow = shadow;
}
// Set the light environment for subsequent rendering
void LitRenderModifier::SetLightEnv(const CLightEnv* lightenv)
{
m_LightEnv = lightenv;
}
///////////////////////////////////////////////////////////////////////////////////////////////
// PlainRenderModifier implementation
@ -69,7 +104,7 @@ u32 PlainRenderModifier::BeginPass(uint pass)
float color[] = { 1.0, 1.0, 1.0, 1.0 };
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
}
@ -77,7 +112,7 @@ bool PlainRenderModifier::EndPass(uint UNUSED(pass))
{
// We didn't modify blend state or higher texenvs, so we don't have
// to reset OpenGL state here.
return true;
}
@ -86,10 +121,90 @@ void PlainRenderModifier::PrepareTexture(uint UNUSED(pass), CTexture* texture)
g_Renderer.SetTexture(0, texture);
}
void PlainRenderModifier::PrepareModel(uint UNUSED(pass), CModel* UNUSED(model))
///////////////////////////////////////////////////////////////////////////////////////////////
// PlainLitRenderModifier implementation
PlainLitRenderModifier::PlainLitRenderModifier()
{
}
PlainLitRenderModifier::~PlainLitRenderModifier()
{
}
u32 PlainLitRenderModifier::BeginPass(uint pass)
{
debug_assert(pass == 0);
debug_assert(GetShadowMap() && GetShadowMap()->GetUseDepthTexture());
// Ambient + Diffuse * Shadow
pglActiveTextureARB(GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE1);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
pglActiveTextureARB(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &GetLightEnv()->m_UnitsAmbientColor.X);
// Incoming color is ambient + diffuse light
pglActiveTextureARB(GL_TEXTURE2);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
pglActiveTextureARB(GL_TEXTURE0);
return STREAM_POS|STREAM_COLOR|STREAM_UV0|STREAM_TEXGENTOUV1;
}
const CMatrix3D* PlainLitRenderModifier::GetTexGenMatrix(uint UNUSED(pass))
{
return &GetShadowMap()->GetTextureMatrix();
}
bool PlainLitRenderModifier::EndPass(uint UNUSED(pass))
{
g_Renderer.BindTexture(1, 0);
g_Renderer.BindTexture(2, 0);
pglActiveTextureARB(GL_TEXTURE0);
pglClientActiveTextureARB(GL_TEXTURE0);
return true;
}
void PlainLitRenderModifier::PrepareTexture(uint UNUSED(pass), CTexture* texture)
{
g_Renderer.SetTexture(0, texture);
}
///////////////////////////////////////////////////////////////////////////////////////////////
// WireframeRenderModifier implementation
@ -106,7 +221,7 @@ WireframeRenderModifier::~WireframeRenderModifier()
u32 WireframeRenderModifier::BeginPass(uint pass)
{
debug_assert(pass == 0);
// first switch on wireframe
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
@ -161,7 +276,7 @@ SolidColorRenderModifier::~SolidColorRenderModifier()
u32 SolidColorRenderModifier::BeginPass(uint UNUSED(pass))
{
g_Renderer.SetTexture(0,0);
return STREAM_POS;
}

View File

@ -16,9 +16,11 @@
#include "ModelRenderer.h"
class CLightEnv;
class CMatrix3D;
class CModel;
class CTexture;
class ShadowMap;
/**
* Class RenderModifier: Some ModelRenderer implementations provide vertex
@ -45,6 +47,19 @@ public:
*/
virtual u32 BeginPass(uint pass) = 0;
/**
* GetTexGenMatrix: If BeginPass returns STREAM_TEXGENTOUVx, the caller must
* call this function to query the texture matrix that will be used to transform
* vertex positions into texture coordinates.
*
* Default implementation raises a runtime error.
*
* @param pass the current pass number (pass == 0 is the first pass)
*
* @return a pointer to the texture matrix for the given pass
*/
virtual const CMatrix3D* GetTexGenMatrix(uint pass);
/**
* EndPass: Cleanup OpenGL state after the given pass. This function
* may indicate that additional passes are needed.
@ -82,6 +97,45 @@ public:
};
/**
* Class LitRenderModifier: Abstract base class for RenderModifiers that apply
* a shadow map.
* LitRenderModifiers expect the diffuse brightness in the primary color (instead of ambient + diffuse).
*/
class LitRenderModifier : public RenderModifier
{
public:
LitRenderModifier();
~LitRenderModifier();
/**
* SetShadowMap: Set the shadow map that will be used for rendering.
* Must be called by the user of the RenderModifier.
*
* The shadow map must be non-null and use depth texturing, or subsequent rendering
* using this RenderModifier will fail.
*
* @param shadow the shadow map
*/
void SetShadowMap(const ShadowMap* shadow);
/**
* SetLightEnv: Set the light environment that will be used for rendering.
* Must be called by the user of the RenderModifier.
*
* @param lightenv the light environment (must be non-null)
*/
void SetLightEnv(const CLightEnv* lightenv);
const ShadowMap* GetShadowMap() const { return m_Shadow; }
const CLightEnv* GetLightEnv() const { return m_LightEnv; }
private:
const ShadowMap* m_Shadow;
const CLightEnv* m_LightEnv;
};
/**
* Class RenderModifierRenderer: Interface to a model renderer that can render
* its models via a RenderModifier that sets up fragment stages.
@ -108,9 +162,28 @@ public:
u32 BeginPass(uint pass);
bool EndPass(uint pass);
void PrepareTexture(uint pass, CTexture* texture);
void PrepareModel(uint pass, CModel* model);
};
/**
* Class PlainLitRenderModifier: Use an opaque color texture for a lit object that is shadowed
* using a depth texture.
* Expects the diffuse brightness in the primary color.
*/
class PlainLitRenderModifier : public LitRenderModifier
{
public:
PlainLitRenderModifier();
~PlainLitRenderModifier();
// Implementation
u32 BeginPass(uint pass);
const CMatrix3D* GetTexGenMatrix(uint pass);
bool EndPass(uint pass);
void PrepareTexture(uint pass, CTexture* texture);
};
/**
* Class WireframeRenderModifier: RenderModifier that renders wireframe models.
*/

View File

@ -8,32 +8,44 @@
#define LOG_CATEGORY "graphics"
void VS_GlobalLight::Init(Handle shader)
{
m_Ambient = ogl_program_get_uniform_location(shader, "ambient");
m_SunDir = ogl_program_get_uniform_location(shader, "sunDir");
m_SunColor = ogl_program_get_uniform_location(shader, "sunColor");
}
void VS_Instancing::Init(Handle shader)
{
m_Instancing1 = ogl_program_get_attrib_location(shader, "Instancing1");
m_Instancing2 = ogl_program_get_attrib_location(shader, "Instancing2");
m_Instancing3 = ogl_program_get_attrib_location(shader, "Instancing3");
}
void VS_PosToUV1::Init(Handle shader)
{
m_TextureMatrix1 = ogl_program_get_uniform_location(shader, "TextureMatrix1");
debug_assert(m_TextureMatrix1 >= 0);
m_TextureMatrix2 = ogl_program_get_uniform_location(shader, "TextureMatrix2");
debug_assert(m_TextureMatrix2 >= 0);
m_TextureMatrix3 = ogl_program_get_uniform_location(shader, "TextureMatrix3");
debug_assert(m_TextureMatrix3 >= 0);
}
RenderPathVertexShader::RenderPathVertexShader()
{
m_ModelLight = 0;
m_ModelLight_Ambient = -1;
m_ModelLight_SunDir = -1;
m_ModelLight_SunColor = -1;
m_ModelLightP = 0;
m_InstancingLight = 0;
m_InstancingLight_Ambient = -1;
m_InstancingLight_SunDir = -1;
m_InstancingLight_SunColor = -1;
m_InstancingLight_Instancing1 = -1;
m_InstancingLight_Instancing2 = -1;
m_InstancingLight_Instancing3 = -1;
m_Instancing = 0;
m_Instancing_Instancing1 = -1;
m_Instancing_Instancing2 = -1;
m_Instancing_Instancing3 = -1;
}
RenderPathVertexShader::~RenderPathVertexShader()
{
if (m_ModelLight)
ogl_program_free(m_ModelLight);
if (m_ModelLightP)
ogl_program_free(m_ModelLightP);
if (m_InstancingLight)
ogl_program_free(m_InstancingLight);
if (m_Instancing)
@ -55,6 +67,13 @@ bool RenderPathVertexShader::Init()
return false;
}
m_ModelLightP = ogl_program_load("shaders/model_lightp.xml");
if (m_ModelLightP < 0)
{
LOG(WARNING, LOG_CATEGORY, "Failed to load shaders/model_lightp.xml: %i\n", (int)m_ModelLightP);
return false;
}
m_InstancingLight = ogl_program_load("shaders/instancing_light.xml");
if (m_InstancingLight < 0)
{
@ -62,6 +81,13 @@ bool RenderPathVertexShader::Init()
return false;
}
m_InstancingLightP = ogl_program_load("shaders/instancing_lightp.xml");
if (m_InstancingLightP < 0)
{
LOG(WARNING, LOG_CATEGORY, "Failed to load shaders/instancing_lightp.xml: %i\n", (int)m_InstancingLightP);
return false;
}
m_Instancing = ogl_program_load("shaders/instancing.xml");
if (m_Instancing < 0)
{
@ -69,6 +95,13 @@ bool RenderPathVertexShader::Init()
return false;
}
m_InstancingP = ogl_program_load("shaders/instancingp.xml");
if (m_InstancingP < 0)
{
LOG(WARNING, LOG_CATEGORY, "Failed to load shaders/instancingp.xml: %i\n", (int)m_InstancingP);
return false;
}
return true;
}
@ -77,27 +110,20 @@ bool RenderPathVertexShader::Init()
// the uniform locations might have changed under us.
void RenderPathVertexShader::BeginFrame()
{
m_ModelLight_Ambient = ogl_program_get_uniform_location(m_ModelLight, "ambient");
m_ModelLight_SunDir = ogl_program_get_uniform_location(m_ModelLight, "sunDir");
m_ModelLight_SunColor = ogl_program_get_uniform_location(m_ModelLight, "sunColor");
m_ModelLight_Light.Init(m_ModelLight);
m_InstancingLight_Ambient = ogl_program_get_uniform_location(
m_InstancingLight, "ambient");
m_InstancingLight_SunDir = ogl_program_get_uniform_location(
m_InstancingLight, "sunDir");
m_InstancingLight_SunColor = ogl_program_get_uniform_location(
m_InstancingLight, "sunColor");
m_InstancingLight_Instancing1 = ogl_program_get_attrib_location(
m_InstancingLight, "Instancing1");
m_InstancingLight_Instancing2 = ogl_program_get_attrib_location(
m_InstancingLight, "Instancing2");
m_InstancingLight_Instancing3 = ogl_program_get_attrib_location(
m_InstancingLight, "Instancing3");
m_ModelLightP_Light.Init(m_ModelLightP);
m_ModelLightP_PosToUV1.Init(m_ModelLightP);
m_Instancing_Instancing1 = ogl_program_get_attrib_location(
m_Instancing, "Instancing1");
m_Instancing_Instancing2 = ogl_program_get_attrib_location(
m_Instancing, "Instancing2");
m_Instancing_Instancing3 = ogl_program_get_attrib_location(
m_Instancing, "Instancing3");
m_InstancingLight_Light.Init(m_InstancingLight);
m_InstancingLight_Instancing.Init(m_InstancingLight);
m_InstancingLightP_Light.Init(m_InstancingLightP);
m_InstancingLightP_Instancing.Init(m_InstancingLightP);
m_InstancingLightP_PosToUV1.Init(m_InstancingLightP);
m_Instancing_Instancing.Init(m_Instancing);
m_InstancingP_Instancing.Init(m_InstancingP);
m_InstancingP_PosToUV1.Init(m_InstancingP);
}

View File

@ -1,6 +1,81 @@
#ifndef __RENDERPATHVERTEXSHADER_H__
#define __RENDERPATHVERTEXSHADER_H__
#include "graphics/LightEnv.h"
// Interface for globallight.vs
struct VS_GlobalLight
{
public:
void Init(Handle shader);
void SetFromLightEnv(const CLightEnv& lightenv, bool units) const
{
SetAmbient(units ? lightenv.m_UnitsAmbientColor : lightenv.m_TerrainAmbientColor);
SetSunDir(lightenv.GetSunDir());
SetSunColor(lightenv.m_SunColor);
}
void SetAmbient(const RGBColor& color) const
{
pglUniform3fvARB(m_Ambient, 1, &color.X);
}
void SetSunDir(const CVector3D& sundir) const
{
pglUniform3fvARB(m_SunDir, 1, &sundir.X);
}
void SetSunColor(const RGBColor& color) const
{
pglUniform3fvARB(m_SunColor, 1, &color.X);
}
private:
GLint m_Ambient;
GLint m_SunDir;
GLint m_SunColor;
};
// Interface for instancing_base.vs
struct VS_Instancing
{
public:
void Init(Handle shader);
void SetMatrix(const CMatrix3D& mat) const
{
pglVertexAttrib4fARB(m_Instancing1, mat._11, mat._12, mat._13, mat._14);
pglVertexAttrib4fARB(m_Instancing2, mat._21, mat._22, mat._23, mat._24);
pglVertexAttrib4fARB(m_Instancing3, mat._31, mat._32, mat._33, mat._34);
}
private:
GLint m_Instancing1;
GLint m_Instancing2;
GLint m_Instancing3;
};
// Interface for postouv1.vs
struct VS_PosToUV1
{
public:
void Init(Handle shader);
void SetMatrix(const CMatrix3D& mat) const
{
pglUniform4fARB(m_TextureMatrix1, mat._11, mat._12, mat._13, mat._14);
pglUniform4fARB(m_TextureMatrix2, mat._21, mat._22, mat._23, mat._24);
pglUniform4fARB(m_TextureMatrix3, mat._31, mat._32, mat._33, mat._34);
}
private:
GLint m_TextureMatrix1;
GLint m_TextureMatrix2;
GLint m_TextureMatrix3;
};
class RenderPathVertexShader
{
public:
@ -15,22 +90,27 @@ public:
public:
Handle m_ModelLight;
GLint m_ModelLight_Ambient;
GLint m_ModelLight_SunDir;
GLint m_ModelLight_SunColor;
VS_GlobalLight m_ModelLight_Light;
Handle m_ModelLightP;
VS_GlobalLight m_ModelLightP_Light;
VS_PosToUV1 m_ModelLightP_PosToUV1;
Handle m_InstancingLight;
GLint m_InstancingLight_Ambient;
GLint m_InstancingLight_SunDir;
GLint m_InstancingLight_SunColor;
GLint m_InstancingLight_Instancing1; // matrix rows
GLint m_InstancingLight_Instancing2;
GLint m_InstancingLight_Instancing3;
VS_GlobalLight m_InstancingLight_Light;
VS_Instancing m_InstancingLight_Instancing;
Handle m_InstancingLightP;
VS_GlobalLight m_InstancingLightP_Light;
VS_Instancing m_InstancingLightP_Instancing;
VS_PosToUV1 m_InstancingLightP_PosToUV1;
Handle m_Instancing;
GLint m_Instancing_Instancing1; // matrix rows
GLint m_Instancing_Instancing2;
GLint m_Instancing_Instancing3;
VS_Instancing m_Instancing_Instancing;
Handle m_InstancingP;
VS_Instancing m_InstancingP_Instancing;
VS_PosToUV1 m_InstancingP_PosToUV1;
};
#endif // __RENDERPATHVERTEXSHADER_H__

View File

@ -185,6 +185,13 @@ AbstractProfileTable* CRendererStatsTable::GetChild(uint UNUSED(row))
///////////////////////////////////////////////////////////////////////////////////
// CRenderer implementation
enum {
AmbientDiffuse = 0,
OnlyDiffuse,
NumVertexTypes
};
/**
* Struct CRendererInternals: Truly hide data that is supposed to be hidden
* in this structure so it won't even appear in header files.
@ -203,6 +210,55 @@ struct CRendererInternals
/// Shadow map
ShadowMap* shadow;
/// Various model renderers
struct Models {
// The following model renderers are aliases for the appropriate real_*
// model renderers (depending on hardware availability and current settings)
// and must be used for actual model submission and rendering
ModelRenderer* Normal;
ModelRenderer* NormalInstancing;
ModelRenderer* Player;
ModelRenderer* PlayerInstancing;
ModelRenderer* Transp;
// "Palette" of available ModelRenderers. Do not use these directly for
// rendering and submission; use the aliases above instead.
ModelRenderer* pal_NormalFF[NumVertexTypes];
ModelRenderer* pal_PlayerFF[NumVertexTypes];
ModelRenderer* pal_NormalHWLit[NumVertexTypes];
ModelRenderer* pal_PlayerHWLit[NumVertexTypes];
ModelRenderer* pal_NormalInstancing[NumVertexTypes];
ModelRenderer* pal_PlayerInstancing[NumVertexTypes];
ModelRenderer* pal_TranspFF[NumVertexTypes];
ModelRenderer* pal_TranspHWLit[NumVertexTypes];
ModelRenderer* pal_TranspSortAll;
ModelVertexRendererPtr VertexFF[NumVertexTypes];
ModelVertexRendererPtr VertexHWLit[NumVertexTypes];
ModelVertexRendererPtr VertexInstancing[NumVertexTypes];
ModelVertexRendererPtr VertexPolygonSort;
// generic RenderModifiers that are supposed to be used directly
RenderModifierPtr ModWireframe;
RenderModifierPtr ModSolidColor;
RenderModifierPtr ModTransparentShadow;
RenderModifierPtr ModTransparentDepthShadow;
// RenderModifiers that are selected from the palette below
RenderModifierPtr ModNormal;
RenderModifierPtr ModPlayer;
RenderModifierPtr ModTransparent;
// Palette of available RenderModifiers
RenderModifierPtr ModPlain;
LitRenderModifierPtr ModPlainLit;
RenderModifierPtr ModPlayerUnlit;
LitRenderModifierPtr ModPlayerLit;
RenderModifierPtr ModTransparentUnlit;
LitRenderModifierPtr ModTransparentLit;
} Model;
CRendererInternals()
: profileTable(g_Renderer.m_Stats)
{
@ -263,47 +319,61 @@ CRenderer::CRenderer()
}
// model rendering
m_Models.VertexFF = ModelVertexRendererPtr(new FixedFunctionModelRenderer);
m->Model.VertexFF[AmbientDiffuse] = ModelVertexRendererPtr(new FixedFunctionModelRenderer(false));
m->Model.VertexFF[OnlyDiffuse] = ModelVertexRendererPtr(new FixedFunctionModelRenderer(true));
if (HWLightingModelRenderer::IsAvailable())
m_Models.VertexHWLit = ModelVertexRendererPtr(new HWLightingModelRenderer);
{
m->Model.VertexHWLit[AmbientDiffuse] = ModelVertexRendererPtr(new HWLightingModelRenderer(false));
m->Model.VertexHWLit[OnlyDiffuse] = ModelVertexRendererPtr(new HWLightingModelRenderer(true));
}
if (InstancingModelRenderer::IsAvailable())
m_Models.VertexInstancing = ModelVertexRendererPtr(new InstancingModelRenderer);
m_Models.VertexPolygonSort = ModelVertexRendererPtr(new PolygonSortModelRenderer);
{
m->Model.VertexInstancing[AmbientDiffuse] = ModelVertexRendererPtr(new InstancingModelRenderer(false));
m->Model.VertexInstancing[OnlyDiffuse] = ModelVertexRendererPtr(new InstancingModelRenderer(true));
}
m->Model.VertexPolygonSort = ModelVertexRendererPtr(new PolygonSortModelRenderer);
m_Models.NormalFF = new BatchModelRenderer(m_Models.VertexFF);
m_Models.PlayerFF = new BatchModelRenderer(m_Models.VertexFF);
m_Models.TranspFF = new SortModelRenderer(m_Models.VertexFF);
if (m_Models.VertexHWLit)
for(int vertexType = 0; vertexType < NumVertexTypes; ++vertexType)
{
m_Models.NormalHWLit = new BatchModelRenderer(m_Models.VertexHWLit);
m_Models.PlayerHWLit = new BatchModelRenderer(m_Models.VertexHWLit);
m_Models.TranspHWLit = new SortModelRenderer(m_Models.VertexHWLit);
m->Model.pal_NormalFF[vertexType] = new BatchModelRenderer(m->Model.VertexFF[vertexType]);
m->Model.pal_PlayerFF[vertexType] = new BatchModelRenderer(m->Model.VertexFF[vertexType]);
m->Model.pal_TranspFF[vertexType] = new SortModelRenderer(m->Model.VertexFF[vertexType]);
if (m->Model.VertexHWLit[vertexType])
{
m->Model.pal_NormalHWLit[vertexType] = new BatchModelRenderer(m->Model.VertexHWLit[vertexType]);
m->Model.pal_PlayerHWLit[vertexType] = new BatchModelRenderer(m->Model.VertexHWLit[vertexType]);
m->Model.pal_TranspHWLit[vertexType] = new SortModelRenderer(m->Model.VertexHWLit[vertexType]);
}
else
{
m->Model.pal_NormalHWLit[vertexType] = NULL;
m->Model.pal_PlayerHWLit[vertexType] = NULL;
m->Model.pal_TranspHWLit[vertexType] = NULL;
}
if (m->Model.VertexInstancing[vertexType])
{
m->Model.pal_NormalInstancing[vertexType] = new BatchModelRenderer(m->Model.VertexInstancing[vertexType]);
m->Model.pal_PlayerInstancing[vertexType] = new BatchModelRenderer(m->Model.VertexInstancing[vertexType]);
}
else
{
m->Model.pal_NormalInstancing[vertexType] = NULL;
m->Model.pal_PlayerInstancing[vertexType] = NULL;
}
}
else
{
m_Models.NormalHWLit = NULL;
m_Models.PlayerHWLit = NULL;
m_Models.TranspHWLit = NULL;
}
if (m_Models.VertexInstancing)
{
m_Models.NormalInstancing = new BatchModelRenderer(m_Models.VertexInstancing);
m_Models.PlayerInstancing = new BatchModelRenderer(m_Models.VertexInstancing);
}
else
{
m_Models.NormalInstancing = NULL;
m_Models.PlayerInstancing = NULL;
}
m_Models.TranspSortAll = new SortModelRenderer(m_Models.VertexPolygonSort);
m_Models.ModWireframe = RenderModifierPtr(new WireframeRenderModifier);
m_Models.ModPlain = RenderModifierPtr(new PlainRenderModifier);
m->Model.pal_TranspSortAll = new SortModelRenderer(m->Model.VertexPolygonSort);
m->Model.ModWireframe = RenderModifierPtr(new WireframeRenderModifier);
m->Model.ModPlain = RenderModifierPtr(new PlainRenderModifier);
m->Model.ModPlainLit = LitRenderModifierPtr(new PlainLitRenderModifier);
SetFastPlayerColor(true);
m_Models.ModSolidColor = RenderModifierPtr(new SolidColorRenderModifier);
m_Models.ModTransparent = RenderModifierPtr(new TransparentRenderModifier);
m_Models.ModTransparentShadow = RenderModifierPtr(new TransparentShadowRenderModifier);
m_Models.ModTransparentDepthShadow = RenderModifierPtr(new TransparentDepthShadowModifier);
m->Model.ModPlayerLit = LitRenderModifierPtr(new LitPlayerColorRender);
m->Model.ModSolidColor = RenderModifierPtr(new SolidColorRenderModifier);
m->Model.ModTransparentUnlit = RenderModifierPtr(new TransparentRenderModifier);
m->Model.ModTransparentLit = LitRenderModifierPtr(new LitTransparentRenderModifier);
m->Model.ModTransparentShadow = RenderModifierPtr(new TransparentShadowRenderModifier);
m->Model.ModTransparentDepthShadow = RenderModifierPtr(new TransparentDepthShadowModifier);
m_ShadowZBias = 0.001f;
@ -319,15 +389,18 @@ CRenderer::CRenderer()
CRenderer::~CRenderer()
{
// model rendering
delete m_Models.NormalFF;
delete m_Models.PlayerFF;
delete m_Models.TranspFF;
delete m_Models.NormalHWLit;
delete m_Models.PlayerHWLit;
delete m_Models.TranspHWLit;
delete m_Models.NormalInstancing;
delete m_Models.PlayerInstancing;
delete m_Models.TranspSortAll;
for(int vertexType = 0; vertexType < NumVertexTypes; ++vertexType)
{
delete m->Model.pal_NormalFF[vertexType];
delete m->Model.pal_PlayerFF[vertexType];
delete m->Model.pal_TranspFF[vertexType];
delete m->Model.pal_NormalHWLit[vertexType];
delete m->Model.pal_PlayerHWLit[vertexType];
delete m->Model.pal_TranspHWLit[vertexType];
delete m->Model.pal_NormalInstancing[vertexType];
delete m->Model.pal_PlayerInstancing[vertexType];
}
delete m->Model.pal_TranspSortAll;
// general
delete m_VertexShader;
@ -514,7 +587,7 @@ void CRenderer::SetRenderPath(RenderPath rp)
{
if (rp == RP_DEFAULT)
{
if (m_Models.NormalHWLit && m_Models.PlayerHWLit)
if (m->Model.pal_NormalHWLit && m->Model.pal_PlayerHWLit)
rp = RP_VERTEXSHADER;
else
rp = RP_FIXED;
@ -522,7 +595,7 @@ void CRenderer::SetRenderPath(RenderPath rp)
if (rp == RP_VERTEXSHADER)
{
if (!m_Models.NormalHWLit || !m_Models.PlayerHWLit)
if (!m->Model.pal_NormalHWLit || !m->Model.pal_PlayerHWLit)
{
LOG(WARNING, LOG_CATEGORY, "Falling back to fixed function\n");
rp = RP_FIXED;
@ -573,9 +646,9 @@ void CRenderer::SetFastPlayerColor(bool fast)
}
if (m_FastPlayerColor)
m_Models.ModPlayer = RenderModifierPtr(new FastPlayerColorRender);
m->Model.ModPlayerUnlit = RenderModifierPtr(new FastPlayerColorRender);
else
m_Models.ModPlayer = RenderModifierPtr(new SlowPlayerColorRender);
m->Model.ModPlayerUnlit = RenderModifierPtr(new SlowPlayerColorRender);
}
//////////////////////////////////////////////////////////////////////////////////////////
@ -598,8 +671,65 @@ void CRenderer::BeginFrame()
// init per frame stuff
m->shadow->SetupFrame(m_CullCamera, m_LightEnv->GetSunDir());
// choose model renderers for this frame
int vertexType;
if (m_Options.m_Shadows && m->shadow->GetUseDepthTexture())
{
vertexType = OnlyDiffuse;
m->Model.ModNormal = m->Model.ModPlainLit;
m->Model.ModPlainLit->SetShadowMap(m->shadow);
m->Model.ModPlainLit->SetLightEnv(m_LightEnv);
m->Model.ModPlayer = m->Model.ModPlayerLit;
m->Model.ModPlayerLit->SetShadowMap(m->shadow);
m->Model.ModPlayerLit->SetLightEnv(m_LightEnv);
m->Model.ModTransparent = m->Model.ModTransparentLit;
m->Model.ModTransparentLit->SetShadowMap(m->shadow);
m->Model.ModTransparentLit->SetLightEnv(m_LightEnv);
}
else
{
vertexType = AmbientDiffuse;
m->Model.ModNormal = m->Model.ModPlain;
m->Model.ModPlayer = m->Model.ModPlayerUnlit;
m->Model.ModTransparent = m->Model.ModTransparentUnlit;
}
if (m_Options.m_RenderPath == RP_VERTEXSHADER)
{
if (m->Model.pal_NormalInstancing)
m->Model.NormalInstancing = m->Model.pal_NormalInstancing[vertexType];
else
m->Model.NormalInstancing = m->Model.pal_NormalHWLit[vertexType];
m->Model.Normal = m->Model.pal_NormalHWLit[vertexType];
if (m->Model.pal_PlayerInstancing)
m->Model.PlayerInstancing = m->Model.pal_PlayerInstancing[vertexType];
else
m->Model.PlayerInstancing = m->Model.pal_PlayerHWLit[vertexType];
m->Model.Player = m->Model.pal_PlayerHWLit[vertexType];
}
else
{
m->Model.NormalInstancing = m->Model.pal_NormalFF[vertexType];
m->Model.Normal = m->Model.pal_NormalFF[vertexType];
m->Model.PlayerInstancing = m->Model.pal_PlayerFF[vertexType];
m->Model.Player = m->Model.pal_PlayerFF[vertexType];
}
if (m_SortAllTransparent)
m->Model.Transp = m->Model.pal_TranspSortAll;
else if (m_Options.m_RenderPath == RP_VERTEXSHADER)
m->Model.Transp = m->Model.pal_TranspHWLit[vertexType];
else
m->Model.Transp = m->Model.pal_TranspFF[vertexType];
}
//////////////////////////////////////////////////////////////////////////////////////////
// SetClearColor: set color used to clear screen in BeginFrame()
void CRenderer::SetClearColor(u32 color)
@ -620,10 +750,10 @@ void CRenderer::RenderShadowMap()
glColor3f(shadowTransp, shadowTransp, shadowTransp);
// Figure out transparent rendering strategy
RenderModifierPtr transparentShadows = m_Models.ModTransparentShadow;
RenderModifierPtr transparentShadows = m->Model.ModTransparentShadow;
if (m->shadow->GetUseDepthTexture())
transparentShadows = m_Models.ModTransparentDepthShadow;
transparentShadows = m->Model.ModTransparentDepthShadow;
// Render all closed models (i.e. models where rendering back faces will produce
// the correct result)
@ -637,22 +767,14 @@ void CRenderer::RenderShadowMap()
// Render models that aren't closed
glDisable(GL_CULL_FACE);
m_Models.NormalFF->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
m_Models.PlayerFF->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
if (m_Models.NormalHWLit)
m_Models.NormalHWLit->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
if (m_Models.PlayerHWLit)
m_Models.PlayerHWLit->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
if (m_Models.NormalInstancing)
m_Models.NormalInstancing->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
if (m_Models.PlayerInstancing)
m_Models.PlayerInstancing->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
m->Model.Normal->Render(m->Model.ModSolidColor, MODELFLAG_CASTSHADOWS);
if (m->Model.Normal != m->Model.NormalInstancing)
m->Model.NormalInstancing->Render(m->Model.ModSolidColor, MODELFLAG_CASTSHADOWS);
m->Model.Player->Render(m->Model.ModSolidColor, MODELFLAG_CASTSHADOWS);
if (m->Model.Player != m->Model.PlayerInstancing)
m->Model.PlayerInstancing->Render(m->Model.ModSolidColor, MODELFLAG_CASTSHADOWS);
m_Models.TranspFF->Render(transparentShadows, MODELFLAG_CASTSHADOWS);
if (m_Models.TranspHWLit)
m_Models.TranspHWLit->Render(transparentShadows, MODELFLAG_CASTSHADOWS);
m_Models.TranspSortAll->Render(transparentShadows, MODELFLAG_CASTSHADOWS);
m->Model.Transp->Render(transparentShadows, MODELFLAG_CASTSHADOWS);
glEnable(GL_CULL_FACE);
@ -722,31 +844,23 @@ void CRenderer::RenderModels()
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
m_Models.NormalFF->Render(m_Models.ModPlain, 0);
m_Models.PlayerFF->Render(m_Models.ModPlayer, 0);
if (m_Models.NormalHWLit)
m_Models.NormalHWLit->Render(m_Models.ModPlain, 0);
if (m_Models.PlayerHWLit)
m_Models.PlayerHWLit->Render(m_Models.ModPlayer, 0);
if (m_Models.NormalInstancing)
m_Models.NormalInstancing->Render(m_Models.ModPlain, 0);
if (m_Models.PlayerInstancing)
m_Models.PlayerInstancing->Render(m_Models.ModPlayer, 0);
m->Model.Normal->Render(m->Model.ModNormal, 0);
m->Model.Player->Render(m->Model.ModPlayer, 0);
if (m->Model.Normal != m->Model.NormalInstancing)
m->Model.NormalInstancing->Render(m->Model.ModNormal, 0);
if (m->Model.Player != m->Model.PlayerInstancing)
m->Model.PlayerInstancing->Render(m->Model.ModPlayer, 0);
if (m_ModelRenderMode==WIREFRAME) {
// switch wireframe off again
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
} else if (m_ModelRenderMode==EDGED_FACES) {
m_Models.NormalFF->Render(m_Models.ModWireframe, 0);
m_Models.PlayerFF->Render(m_Models.ModWireframe, 0);
if (m_Models.NormalHWLit)
m_Models.NormalHWLit->Render(m_Models.ModWireframe, 0);
if (m_Models.PlayerHWLit)
m_Models.PlayerHWLit->Render(m_Models.ModWireframe, 0);
if (m_Models.NormalInstancing)
m_Models.NormalInstancing->Render(m_Models.ModWireframe, 0);
if (m_Models.PlayerInstancing)
m_Models.PlayerInstancing->Render(m_Models.ModWireframe, 0);
m->Model.Normal->Render(m->Model.ModWireframe, 0);
m->Model.Player->Render(m->Model.ModWireframe, 0);
if (m->Model.Normal != m->Model.NormalInstancing)
m->Model.NormalInstancing->Render(m->Model.ModWireframe, 0);
if (m->Model.Player != m->Model.PlayerInstancing)
m->Model.PlayerInstancing->Render(m->Model.ModWireframe, 0);
}
}
@ -759,19 +873,13 @@ void CRenderer::RenderTransparentModels()
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
m_Models.TranspFF->Render(m_Models.ModTransparent, 0);
if (m_Models.TranspHWLit)
m_Models.TranspHWLit->Render(m_Models.ModTransparent, 0);
m_Models.TranspSortAll->Render(m_Models.ModTransparent, 0);
m->Model.Transp->Render(m->Model.ModTransparent, 0);
if (m_ModelRenderMode==WIREFRAME) {
// switch wireframe off again
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
} else if (m_ModelRenderMode==EDGED_FACES) {
m_Models.TranspFF->Render(m_Models.ModWireframe, 0);
if (m_Models.TranspHWLit)
m_Models.TranspHWLit->Render(m_Models.ModWireframe, 0);
m_Models.TranspSortAll->Render(m_Models.ModWireframe, 0);
m->Model.Transp->Render(m->Model.ModWireframe, 0);
}
}
@ -788,20 +896,13 @@ void CRenderer::FlushFrame()
// Prepare model renderers
PROFILE_START("prepare models");
m_Models.NormalFF->PrepareModels();
m_Models.PlayerFF->PrepareModels();
m_Models.TranspFF->PrepareModels();
if (m_Models.NormalHWLit)
m_Models.NormalHWLit->PrepareModels();
if (m_Models.PlayerHWLit)
m_Models.PlayerHWLit->PrepareModels();
if (m_Models.TranspHWLit)
m_Models.TranspHWLit->PrepareModels();
if (m_Models.NormalInstancing)
m_Models.NormalInstancing->PrepareModels();
if (m_Models.PlayerInstancing)
m_Models.PlayerInstancing->PrepareModels();
m_Models.TranspSortAll->PrepareModels();
m->Model.Normal->PrepareModels();
m->Model.Player->PrepareModels();
if (m->Model.Normal != m->Model.NormalInstancing)
m->Model.NormalInstancing->PrepareModels();
if (m->Model.Player != m->Model.PlayerInstancing)
m->Model.PlayerInstancing->PrepareModels();
m->Model.Transp->PrepareModels();
PROFILE_END("prepare models");
PROFILE_START("prepare terrain");
@ -862,20 +963,13 @@ void CRenderer::FlushFrame()
m->terrainRenderer->EndFrame();
// Finish model renderers
m_Models.NormalFF->EndFrame();
m_Models.PlayerFF->EndFrame();
m_Models.TranspFF->EndFrame();
if (m_Models.NormalHWLit)
m_Models.NormalHWLit->EndFrame();
if (m_Models.PlayerHWLit)
m_Models.PlayerHWLit->EndFrame();
if (m_Models.TranspHWLit)
m_Models.TranspHWLit->EndFrame();
if (m_Models.NormalInstancing)
m_Models.NormalInstancing->EndFrame();
if (m_Models.PlayerInstancing)
m_Models.PlayerInstancing->EndFrame();
m_Models.TranspSortAll->EndFrame();
m->Model.Normal->EndFrame();
m->Model.Player->EndFrame();
if (m->Model.Normal != m->Model.NormalInstancing)
m->Model.NormalInstancing->EndFrame();
if (m->Model.Player != m->Model.PlayerInstancing)
m->Model.PlayerInstancing->EndFrame();
m->Model.Transp->EndFrame();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -968,36 +1062,21 @@ void CRenderer::Submit(CModel* model)
if (model->GetMaterial().IsPlayer())
{
if (m_Options.m_RenderPath == RP_VERTEXSHADER)
{
if (canUseInstancing && m_Models.PlayerInstancing)
m_Models.PlayerInstancing->Submit(model);
else
m_Models.PlayerHWLit->Submit(model);
}
if (canUseInstancing)
m->Model.PlayerInstancing->Submit(model);
else
m_Models.PlayerFF->Submit(model);
m->Model.Player->Submit(model);
}
else if (model->GetMaterial().UsesAlpha())
{
if (m_SortAllTransparent)
m_Models.TranspSortAll->Submit(model);
else if (m_Options.m_RenderPath == RP_VERTEXSHADER)
m_Models.TranspHWLit->Submit(model);
else
m_Models.TranspFF->Submit(model);
m->Model.Transp->Submit(model);
}
else
{
if (m_Options.m_RenderPath == RP_VERTEXSHADER)
{
if (canUseInstancing && m_Models.NormalInstancing)
m_Models.NormalInstancing->Submit(model);
else
m_Models.NormalHWLit->Submit(model);
}
if (canUseInstancing)
m->Model.NormalInstancing->Submit(model);
else
m_Models.NormalFF->Submit(model);
m->Model.Normal->Submit(model);
}
}

View File

@ -53,6 +53,7 @@ enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES };
#define STREAM_UV2 0x20
#define STREAM_UV3 0x40
#define STREAM_POSTOUV0 0x80
#define STREAM_TEXGENTOUV1 0x100
//////////////////////////////////////////////////////////////////////////////////////////
// SVertex3D: simple 3D vertex declaration
@ -429,33 +430,6 @@ protected:
*/
bool m_DisableCopyShadow;
// Various model renderers
struct Models {
ModelRenderer* NormalFF;
ModelRenderer* PlayerFF;
ModelRenderer* NormalHWLit;
ModelRenderer* PlayerHWLit;
ModelRenderer* NormalInstancing;
ModelRenderer* PlayerInstancing;
ModelRenderer* TranspFF;
ModelRenderer* TranspHWLit;
ModelRenderer* TranspSortAll;
ModelVertexRendererPtr VertexFF;
ModelVertexRendererPtr VertexHWLit;
ModelVertexRendererPtr VertexInstancing;
ModelVertexRendererPtr VertexPolygonSort;
RenderModifierPtr ModWireframe;
RenderModifierPtr ModPlain;
RenderModifierPtr ModPlayer;
RenderModifierPtr ModSolidColor;
RenderModifierPtr ModTransparent;
RenderModifierPtr ModTransparentShadow;
RenderModifierPtr ModTransparentDepthShadow;
} m_Models;
public:
/**
* m_ShadowZBias: Z bias used when rendering shadows into a depth texture.

View File

@ -346,12 +346,12 @@ void ShadowMap::EndRender()
///////////////////////////////////////////////////////////////////////////////////////////////////
// Retrieve the texture handle and texture matrix for shadowing
GLuint ShadowMap::GetTexture()
GLuint ShadowMap::GetTexture() const
{
return m->Texture;
}
const CMatrix3D& ShadowMap::GetTextureMatrix()
const CMatrix3D& ShadowMap::GetTextureMatrix() const
{
return m->TextureMatrix;
}
@ -359,7 +359,7 @@ const CMatrix3D& ShadowMap::GetTextureMatrix()
///////////////////////////////////////////////////////////////////////////////////////////////////
// Using depth textures vs. a simple luminance map
bool ShadowMap::GetUseDepthTexture()
bool ShadowMap::GetUseDepthTexture() const
{
return m->UseDepthTexture;
}

View File

@ -45,7 +45,7 @@ public:
*
* @return whether shadow rendering uses depth textures
*/
bool GetUseDepthTexture();
bool GetUseDepthTexture() const;
/**
* SetUseDepthTexture: Set whether shadowing should use depth textures.
@ -109,7 +109,7 @@ public:
*
* @return the texture name of the shadow map texture
*/
GLuint GetTexture();
GLuint GetTexture() const;
/**
* GetTextureMatrix: Retrieve the world-space to shadow map texture coordinates
@ -118,7 +118,7 @@ public:
* @return the matrix that transforms world-space coordinates into homogenous
* shadow map texture coordinates
*/
const CMatrix3D& GetTextureMatrix();
const CMatrix3D& GetTextureMatrix() const;
/**
* RenderDebugDisplay: Visualize shadow mapping calculations to help in

View File

@ -21,12 +21,14 @@
#include "Vector3D.h"
#include "Vector4D.h"
#include "graphics/LightEnv.h"
#include "graphics/Model.h"
#include "graphics/ModelDef.h"
#include "ps/Profile.h"
#include "renderer/Renderer.h"
#include "renderer/ShadowMap.h"
#include "renderer/TransparencyRenderer.h"
#include "renderer/VertexArray.h"
@ -235,7 +237,7 @@ void PolygonSortModelRenderer::UpdateModelData(CModel* model, void* data, u32 up
VertexArrayIterator<SColor4ub> Color = psmdl->m_Color.GetIterator<SColor4ub>();
ModelRenderer::BuildColor4ub(model, Normal, Color);
ModelRenderer::BuildColor4ub(model, Normal, Color, false);
// upload everything to vertex buffer
psmdl->m_Array.Upload();
@ -266,8 +268,10 @@ void PolygonSortModelRenderer::DestroyModelData(CModel* UNUSED(model), void* dat
// Prepare for one rendering pass
void PolygonSortModelRenderer::BeginPass(uint streamflags)
void PolygonSortModelRenderer::BeginPass(uint streamflags, const CMatrix3D* UNUSED(texturematrix))
{
debug_assert(streamflags == streamflags & (STREAM_POS|STREAM_COLOR|STREAM_UV0));
glEnableClientState(GL_VERTEX_ARRAY);
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
@ -477,10 +481,14 @@ void SortModelRenderer::Render(RenderModifierPtr modifier, u32 flags)
do
{
u32 streamflags = modifier->BeginPass(pass);
const CMatrix3D* texturematrix = 0;
CModelDefPtr lastmdef;
CTexture* lasttex = 0;
m->vertexRenderer->BeginPass(streamflags);
if (streamflags & STREAM_TEXGENTOUV1)
texturematrix = modifier->GetTexGenMatrix(pass);
m->vertexRenderer->BeginPass(streamflags, texturematrix);
for(std::vector<SModel*>::iterator it = m->models.begin(); it != m->models.end(); ++it)
{
@ -608,6 +616,143 @@ void TransparentRenderModifier::PrepareModel(uint UNUSED(pass), CModel* UNUSED(m
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// LitTransparentRenderModifier implementation
LitTransparentRenderModifier::LitTransparentRenderModifier()
{
}
LitTransparentRenderModifier::~LitTransparentRenderModifier()
{
}
u32 LitTransparentRenderModifier::BeginPass(uint pass)
{
debug_assert(GetShadowMap() && GetShadowMap()->GetUseDepthTexture());
if (pass == 0)
{
// First pass: Put down Z for opaque parts of the model,
// don't touch the color buffer.
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
// just pass through texture's alpha
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
// Set the proper LOD bias
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER,0.975f);
// render everything with color writes off to setup depth buffer correctly
glColorMask(0,0,0,0);
return STREAM_POS|STREAM_UV0;
}
else
{
// Second pass: Put down color, disable Z write
glColorMask(1,1,1,1);
glDepthMask(0);
// Ambient + Diffuse * Shadow
pglActiveTextureARB(GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE1);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
pglActiveTextureARB(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &GetLightEnv()->m_UnitsAmbientColor.X);
// Incoming color is ambient + diffuse light
pglActiveTextureARB(GL_TEXTURE2);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
pglActiveTextureARB(GL_TEXTURE0);
glAlphaFunc(GL_GREATER,0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
// Set the proper LOD bias
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
return STREAM_POS|STREAM_COLOR|STREAM_UV0|STREAM_TEXGENTOUV1;
}
}
bool LitTransparentRenderModifier::EndPass(uint pass)
{
if (pass == 0)
return false; // multi-pass
pglActiveTextureARB(GL_TEXTURE1);
glDisable(GL_TEXTURE_2D);
pglActiveTextureARB(GL_TEXTURE2);
glDisable(GL_TEXTURE_2D);
pglActiveTextureARB(GL_TEXTURE0);
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glDepthMask(1);
return true;
}
const CMatrix3D* LitTransparentRenderModifier::GetTexGenMatrix(uint UNUSED(pass))
{
return &GetShadowMap()->GetTextureMatrix();
}
void LitTransparentRenderModifier::PrepareTexture(uint UNUSED(pass), CTexture* texture)
{
g_Renderer.SetTexture(0, texture);
}
void LitTransparentRenderModifier::PrepareModel(uint UNUSED(pass), CModel* UNUSED(model))
{
// No per-model setup necessary
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// TransparentShadowRenderModifier implementation

View File

@ -40,7 +40,7 @@ public:
void UpdateModelData(CModel* model, void* data, u32 updateflags);
void DestroyModelData(CModel* model, void* data);
void BeginPass(uint streamflags);
void BeginPass(uint streamflags, const CMatrix3D* texturematrix);
void EndPass(uint streamflags);
void PrepareModelDef(uint streamflags, CModelDefPtr def);
void RenderModel(uint streamflags, CModel* model, void* data);
@ -100,6 +100,30 @@ public:
};
/**
* Class LitTransparentRenderModifier: Modifier for transparent models,
* including alpha blending and shadowed lighting.
*
* @note Use only when depth textures are used for shadows and thus supported by the OpenGL
* implementation.
*/
class LitTransparentRenderModifier : public LitRenderModifier
{
public:
LitTransparentRenderModifier();
~LitTransparentRenderModifier();
// Implementation
u32 BeginPass(uint pass);
bool EndPass(uint pass);
const CMatrix3D* GetTexGenMatrix(uint pass);
void PrepareTexture(uint pass, CTexture* texture);
void PrepareModel(uint pass, CModel* model);
};
/**
* Class TransparentShadowRenderModifier: Use to render shadow data for
* transparent models into a luminance map.