1
0
forked from 0ad/0ad

Refactor model rendering to perform vertex setup in ModelVertexRenderer.

Sort all transparent models by distance to camera (however, do not sort
polygons by default).

This was SVN commit r3096.
This commit is contained in:
prefect 2005-11-05 23:15:23 +00:00
parent 139c48e733
commit 0346ba1b18
14 changed files with 749 additions and 598 deletions

View File

@ -90,15 +90,6 @@ struct FixedFunctionModelRendererInternals
/// Transformed vertex normals - required for recalculating lighting on skinned models
std::vector<CVector3D> normals;
/// Currently used RenderModifier
RenderModifierPtr modifier;
/// Current rendering pass
uint pass;
/// Streamflags required in this pass
uint streamflags;
/// Previously prepared modeldef
FFModelDef* ffmodeldef;
};
@ -108,6 +99,7 @@ struct FixedFunctionModelRendererInternals
FixedFunctionModelRenderer::FixedFunctionModelRenderer()
{
m = new FixedFunctionModelRendererInternals;
m->ffmodeldef = 0;
}
FixedFunctionModelRenderer::~FixedFunctionModelRenderer()
@ -115,34 +107,6 @@ FixedFunctionModelRenderer::~FixedFunctionModelRenderer()
delete m;
}
// Render submitted models.
void FixedFunctionModelRenderer::Render(RenderModifierPtr modifier, u32 flags)
{
if (!BatchModelRenderer::HaveSubmissions())
return;
// Save for later
m->modifier = modifier;
glEnableClientState(GL_VERTEX_ARRAY);
m->pass = 0;
do
{
m->streamflags = modifier->BeginPass(m->pass);
if (m->streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (m->streamflags & STREAM_COLOR) glEnableClientState(GL_COLOR_ARRAY);
RenderAllModels(flags);
if (m->streamflags & STREAM_UV0) glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (m->streamflags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY);
} while(!modifier->EndPass(m->pass++));
glDisableClientState(GL_VERTEX_ARRAY);
}
// Build model data (and modeldef data if necessary)
void* FixedFunctionModelRenderer::CreateModelData(CModel* model)
@ -191,11 +155,11 @@ void FixedFunctionModelRenderer::UpdateModelData(CModel* model, void* data, u32
VertexArrayIterator<CVector3D> Position = ffmodel->m_Position.GetIterator<CVector3D>();
VertexArrayIterator<CVector3D> Normal = VertexArrayIterator<CVector3D>((char*)&m->normals[0], sizeof(CVector3D));
BuildPositionAndNormals(model, Position, Normal);
ModelRenderer::BuildPositionAndNormals(model, Position, Normal);
VertexArrayIterator<SColor4ub> Color = ffmodel->m_Color.GetIterator<SColor4ub>();
BuildColor4ub(model, Normal, Color);
ModelRenderer::BuildColor4ub(model, Normal, Color);
// upload everything to vertex buffer
ffmodel->m_Array.Upload();
@ -213,14 +177,34 @@ void FixedFunctionModelRenderer::DestroyModelData(CModel* UNUSED(model), void* d
}
// Setup one rendering pass
void FixedFunctionModelRenderer::BeginPass(uint streamflags)
{
glEnableClientState(GL_VERTEX_ARRAY);
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR) glEnableClientState(GL_COLOR_ARRAY);
}
// Cleanup one rendering pass
void FixedFunctionModelRenderer::EndPass(uint streamflags)
{
if (streamflags & STREAM_UV0) glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
// Prepare UV coordinates for this modeldef
void FixedFunctionModelRenderer::PrepareModelDef(CModelDefPtr def)
void FixedFunctionModelRenderer::PrepareModelDef(uint streamflags, CModelDefPtr def)
{
m->ffmodeldef = (FFModelDef*)def->GetRenderData(m);
debug_assert(m->ffmodeldef);
if (m->streamflags & STREAM_UV0)
if (streamflags & STREAM_UV0)
{
u8* base = m->ffmodeldef->m_Array.Bind();
GLsizei stride = (GLsizei)m->ffmodeldef->m_Array.GetStride();
@ -230,18 +214,9 @@ void FixedFunctionModelRenderer::PrepareModelDef(CModelDefPtr def)
}
// Call the modifier to prepare the given texture
void FixedFunctionModelRenderer::PrepareTexture(CTexture* texture)
{
m->modifier->PrepareTexture(m->pass, texture);
}
// Render one model
void FixedFunctionModelRenderer::RenderModel(CModel* model, void* data)
void FixedFunctionModelRenderer::RenderModel(uint streamflags, CModel* model, void* data)
{
m->modifier->PrepareModel(m->pass, model);
CModelDefPtr mdldef = model->GetModelDef();
FFModel* ffmodel = (FFModel*)data;
@ -249,7 +224,7 @@ void FixedFunctionModelRenderer::RenderModel(CModel* model, void* data)
GLsizei stride = (GLsizei)ffmodel->m_Array.GetStride();
glVertexPointer(3, GL_FLOAT, stride, base + ffmodel->m_Position.offset);
if (m->streamflags & STREAM_COLOR)
if (streamflags & STREAM_COLOR)
glColorPointer(3, ffmodel->m_Color.type, stride, base + ffmodel->m_Color.offset);
// render the lot

View File

@ -2,8 +2,8 @@
* =========================================================================
* File : FixedFunctionModelRenderer.h
* Project : Pyrogenesis
* Description : BatchModelRenderer that uses only fixed function pipeline
* : to render animated models, capable of using RenderModifier.
* Description : ModelVertexRenderer that uses only fixed function pipeline
* : to render animated models.
*
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
* =========================================================================
@ -12,45 +12,29 @@
#ifndef FIXEDFUNCTIONMODELRENDERER_H
#define FIXEDFUNCTIONMODELRENDERER_H
#include "renderer/ModelRenderer.h"
#include "renderer/ModelVertexRenderer.h"
struct FixedFunctionModelRendererInternals;
/**
* Class FixedFunctionModelRenderer: Render animated models using only
* OpenGL fixed function.
*
* Use the RenderModifier to enable normal model rendering as well
* as player colour rendering using this model renderer.
*/
class FixedFunctionModelRenderer : public BatchModelRenderer
class FixedFunctionModelRenderer : public ModelVertexRenderer
{
public:
FixedFunctionModelRenderer();
~FixedFunctionModelRenderer();
/**
* Render: Render submitted models using the given RenderModifier
* for fragment stages.
*
* preconditions : PrepareModels must be called before Render.
*
* @param modifier The RenderModifier that specifies the fragment stage.
* @param flags If flags is 0, all submitted models are rendered.
* If flags is non-zero, only models that contain flags in their
* CModel::GetFlags() are rendered.
*/
void Render(RenderModifierPtr modifier, u32 flags);
protected:
// Implementations
void* CreateModelData(CModel* model);
void UpdateModelData(CModel* model, void* data, u32 updateflags);
void DestroyModelData(CModel* model, void* data);
void PrepareModelDef(CModelDefPtr def);
void PrepareTexture(CTexture* texture);
void RenderModel(CModel* model, void* data);
void BeginPass(uint streamflags);
void EndPass(uint streamflags);
void PrepareModelDef(uint streamflags, CModelDefPtr def);
void RenderModel(uint streamflags, CModel* model, void* data);
private:
FixedFunctionModelRendererInternals* m;

View File

@ -74,12 +74,6 @@ struct HWLightingModelRendererInternals
/// Currently used RenderModifier
RenderModifierPtr modifier;
/// Current rendering pass
uint pass;
/// Streamflags required in this pass
uint streamflags;
/// Previously prepared modeldef
HWLModelDef* hwlmodeldef;
};
@ -89,6 +83,7 @@ struct HWLightingModelRendererInternals
HWLightingModelRenderer::HWLightingModelRenderer()
{
m = new HWLightingModelRendererInternals;
m->hwlmodeldef = 0;
}
HWLightingModelRenderer::~HWLightingModelRenderer()
@ -104,50 +99,6 @@ bool HWLightingModelRenderer::IsAvailable()
}
// Render submitted models.
void HWLightingModelRenderer::Render(RenderModifierPtr modifier, u32 flags)
{
if (!HaveSubmissions())
return;
// Save for later
m->modifier = modifier;
glEnableClientState(GL_VERTEX_ARRAY);
m->pass = 0;
do
{
m->streamflags = modifier->BeginPass(m->pass);
if (m->streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (m->streamflags & STREAM_COLOR)
{
const RGBColor* coeffs = g_Renderer.m_SHCoeffsUnits.GetCoefficients();
int idx;
ogl_program_use(g_Renderer.m_VertexShader->m_ModelLight);
idx = g_Renderer.m_VertexShader->m_ModelLight_SHCoefficients;
pglUniform3fvARB(idx, 9, (float*)coeffs);
glEnableClientState(GL_NORMAL_ARRAY);
}
RenderAllModels(flags);
if (m->streamflags & STREAM_UV0) glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (m->streamflags & STREAM_COLOR)
{
pglUseProgramObjectARB(0);
glDisableClientState(GL_NORMAL_ARRAY);
}
} while(!modifier->EndPass(m->pass++));
glDisableClientState(GL_VERTEX_ARRAY);
}
// Build model data (and modeldef data if necessary)
void* HWLightingModelRenderer::CreateModelData(CModel* model)
{
@ -200,7 +151,7 @@ void HWLightingModelRenderer::UpdateModelData(CModel* model, void* data, u32 upd
VertexArrayIterator<CVector3D> Position = hwlmodel->m_Position.GetIterator<CVector3D>();
VertexArrayIterator<CVector3D> Normal = hwlmodel->m_Normal.GetIterator<CVector3D>();
BuildPositionAndNormals(model, Position, Normal);
ModelRenderer::BuildPositionAndNormals(model, Position, Normal);
// upload everything to vertex buffer
hwlmodel->m_Array.Upload();
@ -218,8 +169,43 @@ void HWLightingModelRenderer::DestroyModelData(CModel* UNUSED(model), void* data
}
// Setup one rendering pass
void HWLightingModelRenderer::BeginPass(uint streamflags)
{
glEnableClientState(GL_VERTEX_ARRAY);
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR)
{
const RGBColor* coeffs = g_Renderer.m_SHCoeffsUnits.GetCoefficients();
int idx;
ogl_program_use(g_Renderer.m_VertexShader->m_ModelLight);
idx = g_Renderer.m_VertexShader->m_ModelLight_SHCoefficients;
pglUniform3fvARB(idx, 9, (float*)coeffs);
glEnableClientState(GL_NORMAL_ARRAY);
}
}
// Cleanup one rendering pass
void HWLightingModelRenderer::EndPass(uint streamflags)
{
if (streamflags & STREAM_UV0) glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR)
{
pglUseProgramObjectARB(0);
glDisableClientState(GL_NORMAL_ARRAY);
}
glDisableClientState(GL_VERTEX_ARRAY);
}
// Prepare UV coordinates for this modeldef
void HWLightingModelRenderer::PrepareModelDef(CModelDefPtr def)
void HWLightingModelRenderer::PrepareModelDef(uint UNUSED(streamflags), CModelDefPtr def)
{
m->hwlmodeldef = (HWLModelDef*)def->GetRenderData(m);
@ -227,18 +213,9 @@ void HWLightingModelRenderer::PrepareModelDef(CModelDefPtr def)
}
// Call the modifier to prepare the given texture
void HWLightingModelRenderer::PrepareTexture(CTexture* texture)
{
m->modifier->PrepareTexture(m->pass, texture);
}
// Render one model
void HWLightingModelRenderer::RenderModel(CModel* model, void* data)
void HWLightingModelRenderer::RenderModel(uint streamflags, CModel* model, void* data)
{
m->modifier->PrepareModel(m->pass, model);
CModelDefPtr mdldef = model->GetModelDef();
HWLModel* hwlmodel = (HWLModel*)data;
@ -246,14 +223,14 @@ void HWLightingModelRenderer::RenderModel(CModel* model, void* data)
GLsizei stride = (GLsizei)hwlmodel->m_Array.GetStride();
glVertexPointer(3, GL_FLOAT, stride, base + hwlmodel->m_Position.offset);
if (m->streamflags & STREAM_COLOR)
if (streamflags & STREAM_COLOR)
{
CColor sc = model->GetShadingColor();
glColor3f(sc.r, sc.g, sc.b);
glNormalPointer(GL_FLOAT, stride, base + hwlmodel->m_Normal.offset);
}
if (m->streamflags & STREAM_UV0)
if (streamflags & STREAM_UV0)
{
glTexCoordPointer(2, GL_FLOAT, stride, base + hwlmodel->m_UV.offset);
}

View File

@ -2,7 +2,7 @@
* =========================================================================
* File : HWLightingModelRenderer.h
* Project : Pyrogenesis
* Description : BatchModelRenderer that transforms models on the CPU
* Description : ModelVertexRenderer that transforms models on the CPU
* : but performs lighting in a vertex shader.
*
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
@ -12,7 +12,7 @@
#ifndef HWLIGHTINGMODELRENDERER_H
#define HWLIGHTINGMODELRENDERER_H
#include "renderer/ModelRenderer.h"
#include "renderer/ModelVertexRenderer.h"
struct HWLightingModelRendererInternals;
@ -20,31 +20,25 @@ struct HWLightingModelRendererInternals;
* Class HWLightingModelRenderer: Render animated models using vertex
* shaders for lighting.
*
* Use the RenderModifier to enable normal model rendering as well
* as player colour rendering using this model renderer.
*
* @note You should verify hardware capabilities using IsAvailable
* before creating this model renderer.
*/
class HWLightingModelRenderer : public BatchModelRenderer
class HWLightingModelRenderer : public ModelVertexRenderer
{
public:
HWLightingModelRenderer();
~HWLightingModelRenderer();
/**
* Render: Render submitted models using the given RenderModifier
* for fragment stages.
*
* preconditions : PrepareModels must be called before Render.
*
* @param modifier The RenderModifier that specifies the fragment stage.
* @param flags If flags is 0, all submitted models are rendered.
* If flags is non-zero, only models that contain flags in their
* CModel::GetFlags() are rendered.
*/
void Render(RenderModifierPtr modifier, u32 flags);
// Implementations
void* CreateModelData(CModel* model);
void UpdateModelData(CModel* model, void* data, u32 updateflags);
void DestroyModelData(CModel* model, void* data);
void BeginPass(uint streamflags);
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.
@ -56,16 +50,6 @@ public:
* model renderer.
*/
static bool IsAvailable();
protected:
// Implementations
void* CreateModelData(CModel* model);
void UpdateModelData(CModel* model, void* data, u32 updateflags);
void DestroyModelData(CModel* model, void* data);
void PrepareModelDef(CModelDefPtr def);
void PrepareTexture(CTexture* texture);
void RenderModel(CModel* model, void* data);
private:
HWLightingModelRendererInternals* m;

View File

@ -94,12 +94,6 @@ struct InstancingModelRendererInternals
/// Currently used RenderModifier
RenderModifierPtr modifier;
/// Current rendering pass
uint pass;
/// Streamflags required in this pass
uint streamflags;
/// Previously prepared modeldef
IModelDef* imodeldef;
};
@ -109,6 +103,7 @@ struct InstancingModelRendererInternals
InstancingModelRenderer::InstancingModelRenderer()
{
m = new InstancingModelRendererInternals;
m->imodeldef = 0;
}
InstancingModelRenderer::~InstancingModelRenderer()
@ -124,52 +119,6 @@ bool InstancingModelRenderer::IsAvailable()
}
// Render submitted models.
void InstancingModelRenderer::Render(RenderModifierPtr modifier, u32 flags)
{
if (!HaveSubmissions())
return;
// Save for later
m->modifier = modifier;
glEnableClientState(GL_VERTEX_ARRAY);
m->pass = 0;
do
{
m->streamflags = modifier->BeginPass(m->pass);
if (m->streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (m->streamflags & STREAM_COLOR)
{
const RGBColor* coeffs = g_Renderer.m_SHCoeffsUnits.GetCoefficients();
int idx;
ogl_program_use(g_Renderer.m_VertexShader->m_InstancingLight);
idx = g_Renderer.m_VertexShader->m_InstancingLight_SHCoefficients;
pglUniform3fvARB(idx, 9, (float*)coeffs);
glEnableClientState(GL_NORMAL_ARRAY);
}
else
{
ogl_program_use(g_Renderer.m_VertexShader->m_Instancing);
}
RenderAllModels(flags);
if (m->streamflags & STREAM_UV0) glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (m->streamflags & STREAM_COLOR) glDisableClientState(GL_NORMAL_ARRAY);
pglUseProgramObjectARB(0);
} while(!modifier->EndPass(m->pass++));
glDisableClientState(GL_VERTEX_ARRAY);
}
// Build modeldef data if necessary - we have no per-CModel data
void* InstancingModelRenderer::CreateModelData(CModel* model)
{
@ -183,6 +132,7 @@ void* InstancingModelRenderer::CreateModelData(CModel* model)
imodeldef = new IModelDef(mdef);
mdef->SetRenderData(m, imodeldef);
}
return NULL;
}
@ -199,8 +149,42 @@ void InstancingModelRenderer::DestroyModelData(CModel* UNUSED(model), void* UNUS
}
// Setup one rendering pass.
void InstancingModelRenderer::BeginPass(uint streamflags)
{
glEnableClientState(GL_VERTEX_ARRAY);
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR)
{
const RGBColor* coeffs = g_Renderer.m_SHCoeffsUnits.GetCoefficients();
int idx;
ogl_program_use(g_Renderer.m_VertexShader->m_InstancingLight);
idx = g_Renderer.m_VertexShader->m_InstancingLight_SHCoefficients;
pglUniform3fvARB(idx, 9, (float*)coeffs);
glEnableClientState(GL_NORMAL_ARRAY);
}
else
{
ogl_program_use(g_Renderer.m_VertexShader->m_Instancing);
}
}
// Cleanup rendering pass.
void InstancingModelRenderer::EndPass(uint streamflags)
{
if (streamflags & STREAM_UV0) glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR) glDisableClientState(GL_NORMAL_ARRAY);
pglUseProgramObjectARB(0);
glDisableClientState(GL_VERTEX_ARRAY);
}
// Prepare UV coordinates for this modeldef
void InstancingModelRenderer::PrepareModelDef(CModelDefPtr def)
void InstancingModelRenderer::PrepareModelDef(uint streamflags, CModelDefPtr def)
{
m->imodeldef = (IModelDef*)def->GetRenderData(m);
@ -210,34 +194,25 @@ void InstancingModelRenderer::PrepareModelDef(CModelDefPtr def)
GLsizei stride = (GLsizei)m->imodeldef->m_Array.GetStride();
glVertexPointer(3, GL_FLOAT, stride, base + m->imodeldef->m_Position.offset);
if (m->streamflags & STREAM_COLOR)
if (streamflags & STREAM_COLOR)
{
glNormalPointer(GL_FLOAT, stride, base + m->imodeldef->m_Normal.offset);
}
if (m->streamflags & STREAM_UV0)
if (streamflags & STREAM_UV0)
{
glTexCoordPointer(2, GL_FLOAT, stride, base + m->imodeldef->m_UV.offset);
}
}
// Call the modifier to prepare the given texture
void InstancingModelRenderer::PrepareTexture(CTexture* texture)
{
m->modifier->PrepareTexture(m->pass, texture);
}
// Render one model
void InstancingModelRenderer::RenderModel(CModel* model, void* UNUSED(data))
void InstancingModelRenderer::RenderModel(uint streamflags, CModel* model, void* UNUSED(data))
{
m->modifier->PrepareModel(m->pass, model);
CModelDefPtr mdldef = model->GetModelDef();
const CMatrix3D& mat = model->GetTransform();
RenderPathVertexShader* rpvs = g_Renderer.m_VertexShader;
if (m->streamflags & STREAM_COLOR)
if (streamflags & STREAM_COLOR)
{
CColor sc = model->GetShadingColor();
glColor3f(sc.r, sc.g, sc.b);

View File

@ -2,8 +2,8 @@
* =========================================================================
* File : InstancingModelRenderer.h
* Project : Pyrogenesis
* Description : Special BatchModelRenderer that only works for non-animated
* : models, but performs all transformation in a vertex shader.
* Description : Special ModelVertexRender that only works for non-animated
* : models, but is very fast for instanced models.
*
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
* =========================================================================
@ -12,38 +12,32 @@
#ifndef INSTANCINGMODELRENDERER_H
#define INSTANCINGMODELRENDERER_H
#include "renderer/ModelRenderer.h"
#include "renderer/ModelVertexRenderer.h"
struct InstancingModelRendererInternals;
/**
* Class InstancingModelRenderer: Render non-animated (but potentially
* moving models) using vertex shaders.
*
* Use the RenderModifier to enable normal model rendering as well
* as player colour rendering using this model renderer.
* 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 BatchModelRenderer
class InstancingModelRenderer : public ModelVertexRenderer
{
public:
InstancingModelRenderer();
~InstancingModelRenderer();
/**
* Render: Render submitted models using the given RenderModifier
* for fragment stages.
*
* preconditions : PrepareModels must be called before Render.
*
* @param modifier The RenderModifier that specifies the fragment stage.
* @param flags If flags is 0, all submitted models are rendered.
* If flags is non-zero, only models that contain flags in their
* CModel::GetFlags() are rendered.
*/
void Render(RenderModifierPtr modifier, u32 flags);
// Implementations
void* CreateModelData(CModel* model);
void UpdateModelData(CModel* model, void* data, u32 updateflags);
void DestroyModelData(CModel* model, void* data);
void BeginPass(uint streamflags);
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
@ -56,16 +50,6 @@ public:
* model renderer.
*/
static bool IsAvailable();
protected:
// Implementations
void* CreateModelData(CModel* model);
void UpdateModelData(CModel* model, void* data, u32 updateflags);
void DestroyModelData(CModel* model, void* data);
void PrepareModelDef(CModelDefPtr def);
void PrepareTexture(CTexture* texture);
void RenderModel(CModel* model, void* data);
private:
InstancingModelRendererInternals* m;

View File

@ -22,7 +22,9 @@
#include "graphics/ModelDef.h"
#include "renderer/ModelRenderer.h"
#include "renderer/ModelVertexRenderer.h"
#include "renderer/Renderer.h"
#include "renderer/RenderModifiers.h"
#include "renderer/SHCoeffs.h"
@ -276,6 +278,9 @@ struct BatchModelRendererInternals
/// Back-link to "our" renderer
BatchModelRenderer* m_Renderer;
/// ModelVertexRenderer used for vertex transformations
ModelVertexRendererPtr vertexRenderer;
/// Track the current "phase" of the frame (only for debugging purposes)
BMRPhase phase;
@ -285,8 +290,10 @@ struct BatchModelRendererInternals
/// Helper functions
void ThunkDestroyModelData(CModel* model, void* data)
{
m_Renderer->DestroyModelData(model, data);
vertexRenderer->DestroyModelData(model, data);
}
void RenderAllModels(RenderModifierPtr modifier, u32 filterflags, uint pass, uint streamflags);
};
BMRModelData::~BMRModelData()
@ -296,9 +303,10 @@ BMRModelData::~BMRModelData()
// Construction/Destruction
BatchModelRenderer::BatchModelRenderer()
BatchModelRenderer::BatchModelRenderer(ModelVertexRendererPtr vertexrenderer)
{
m = new BatchModelRendererInternals(this);
m->vertexRenderer = vertexrenderer;
m->phase = BMRSubmit;
m->submissions = 0;
}
@ -332,7 +340,7 @@ void BatchModelRenderer::Submit(CModel* model)
else
{
bmrdata = new BMRModelData(m, model);
bmrdata->m_Data = CreateModelData(model);
bmrdata->m_Data = m->vertexRenderer->CreateModelData(model);
rdata = bmrdata;
model->SetRenderData(bmrdata);
model->SetDirty(~0u);
@ -385,9 +393,13 @@ void BatchModelRenderer::PrepareModels()
{
for(BMRModelData* bmrdata = mdeftracker->m_ModelSlots[idx]; bmrdata; bmrdata = bmrdata->m_Next)
{
debug_assert(bmrdata->GetModel()->GetRenderData() == bmrdata);
CModel* model = bmrdata->GetModel();
UpdateModelData(bmrdata->GetModel(), bmrdata->m_Data, bmrdata->m_UpdateFlags);
debug_assert(model->GetRenderData() == bmrdata);
m->vertexRenderer->UpdateModelData(
model, bmrdata->m_Data,
bmrdata->m_UpdateFlags);
bmrdata->m_UpdateFlags = 0;
}
}
@ -424,31 +436,55 @@ bool BatchModelRenderer::HaveSubmissions()
}
// Walk through the submissions list and call PrepareXYZ and RenderModel as necessary
void BatchModelRenderer::RenderAllModels(u32 flags)
// Render models, outer loop for multi-passing
void BatchModelRenderer::Render(RenderModifierPtr modifier, u32 flags)
{
debug_assert(m->phase == BMRRender);
for(BMRModelDefTracker* mdeftracker = m->submissions; mdeftracker; mdeftracker = mdeftracker->m_Next)
if (!HaveSubmissions())
return;
uint pass = 0;
do
{
PrepareModelDef(mdeftracker->m_ModelDef.lock());
uint streamflags = modifier->BeginPass(pass);
m->vertexRenderer->BeginPass(streamflags);
m->RenderAllModels(modifier, flags, pass, streamflags);
m->vertexRenderer->EndPass(streamflags);
} while(!modifier->EndPass(pass++));
}
// Render one frame worth of models
void BatchModelRendererInternals::RenderAllModels(
RenderModifierPtr modifier, u32 filterflags,
uint pass, uint streamflags)
{
for(BMRModelDefTracker* mdeftracker = submissions; mdeftracker; mdeftracker = mdeftracker->m_Next)
{
vertexRenderer->PrepareModelDef(streamflags, mdeftracker->m_ModelDef.lock());
for(uint idx = 0; idx < mdeftracker->m_Slots; ++idx)
{
BMRModelData* bmrdata = mdeftracker->m_ModelSlots[idx];
PrepareTexture(bmrdata->GetModel()->GetTexture());
modifier->PrepareTexture(pass, bmrdata->GetModel()->GetTexture());
for(; bmrdata; bmrdata = bmrdata->m_Next)
{
CModel* model = bmrdata->GetModel();
debug_assert(bmrdata->GetKey() == m);
debug_assert(bmrdata->GetKey() == this);
if (flags && !(model->GetFlags()&flags))
if (filterflags && !(model->GetFlags()&filterflags))
continue;
RenderModel(model, bmrdata->m_Data);
modifier->PrepareModel(pass, model);
vertexRenderer->RenderModel(streamflags, model, bmrdata->m_Data);
}
}
}

View File

@ -22,6 +22,9 @@
class RenderModifier;
typedef boost::shared_ptr<RenderModifier> RenderModifierPtr;
class ModelVertexRenderer;
typedef boost::shared_ptr<ModelVertexRenderer> ModelVertexRendererPtr;
class CModel;
@ -72,10 +75,17 @@ private:
*
* A ModelRenderer manages a per-frame list of models.
*
* It is supposed to be derived in order to create a new render path
* for models (e.g. for models using special effects).
* However, consider deriving from BatchModelRenderer or another
* specialized base class to use their features.
* It is supposed to be derived in order to create new ways in which
* the per-frame list of models can be managed (for batching, for
* transparent rendering, etc.) or potentially for rarely used special
* effects.
*
* A typical ModelRenderer will delegate vertex transformation/setup
* to a ModelVertexRenderer.
* It will delegate fragment stage setup to a RenderModifier.
*
* For most purposes, you should use a BatchModelRenderer with
* specialized ModelVertexRenderer and RenderModifier implementations.
*
* It is suggested that a derived class implement the provided generic
* Render function, however in some cases it may be necessary to supply
@ -222,27 +232,19 @@ public:
struct BatchModelRendererInternals;
/**
* Class BatchModelRenderer: Base class for model renderers that sorts
* submitted models by CModelDef and texture for batching.
* Class BatchModelRenderer: Model renderer that sorts submitted models
* by CModelDef and texture for batching, and uses a ModelVertexRenderer
* (e.g. FixedFunctionModelRenderer) to manage model vertices.
*
* A derived class must provide its own Render function. Depending on
* the ModelRenderer's purpose, this function may take renderer-dependent
* arguments and prepare OpenGL state or private data. It should then
* call RenderAllModels, which will call back into the various PrepareXYZ
* functions for the actual rendering.
*
* Thus a derived class must also provide implementations for
* RenderModel and PrepareXYZ.
*
* @note Model renderers that derive from this class MUST NOT set their
* own per-CModel render data. Use the CreateModelData facility instead.
* @note Deriving from this class is highly discouraged. Specialize
* using ModelVertexRendererPtr and RenderModifier instead.
*/
class BatchModelRenderer : public ModelRenderer
{
friend struct BatchModelRendererInternals;
public:
BatchModelRenderer();
BatchModelRenderer(ModelVertexRendererPtr vertexrender);
virtual ~BatchModelRenderer();
// Batching implementations
@ -250,102 +252,7 @@ public:
virtual void PrepareModels();
virtual void EndFrame();
virtual bool HaveSubmissions();
protected:
/**
* CreateModelData: Create renderer's internal data for one model.
*
* This function must be implemented by derived classes. It will be
* called once by Submit for every model, and allows derived classes
* to allocate per-model vertex buffers and other data.
*
* @param model The model.
*
* @return A data pointer that is opaque to this class, but will be
* passed to other functions whenever the CModel is passed again.
*/
virtual void* CreateModelData(CModel* model) = 0;
/**
* UpdateModelData: Calculate per-model data for each frame.
*
* This function must be implemented by derived classes. It will be
* called once per frame by PrepareModels, regardless of the value
* of CRenderData::m_UpdateFlags.
*
* This implies that UpdateModelData will be called at least once
* between the call to CreateModelData and the first call to RenderModel
* for this model.
*
* @param model The model.
* @param data Private data as returned by CreateModelData.
* @param updateflags Flags indicating which data has changed during
* the frame. The value is the same as the value of the model's
* CRenderData::m_UpdateFlags.
*/
virtual void UpdateModelData(CModel* model, void* data, u32 updateflags) = 0;
/**
* DestroyModelData: Release all per-model data that has been allocated
* by CreateModelData or UpdateModelData.
*
* @param model The model.
* @param data Private data as returned by CreateModelData.
*/
virtual void DestroyModelData(CModel* model, void* data) = 0;
/**
* RenderAllModels: Loop through submitted models and render them
* by calling the PrepareXYZ functions and RenderModel as appropriate.
*
* @param flags Filter models based on CModel::GetFlags(). If flags
* is 0, all models are rendered. Otherwise, only models are rendered
* for which CModel::GetFlags() & flags returns true.
*
* postconditions : RenderAllModels does not affect OpenGL state
* itself. However, it changes OpenGL state indirectly by calling
* the PrepareXYZ and RenderModel functions.
*/
void RenderAllModels(u32 flags);
/**
* PrepareModelDef: Setup OpenGL state for rendering of models that
* use the given CModelDef object as base.
*
* This function is called by RenderAllModels before rendering any
* models using def as base model definition.
*
* @param def The model definition.
*/
virtual void PrepareModelDef(CModelDefPtr def) = 0;
/**
* PrepareTexture: Setup OpenGL state for rendering of models that
* use the given texture.
*
* This function is called by RenderAllModels before rendering any
* models using the given texture.
*
* @param texture The texture.
*/
virtual void PrepareTexture(CTexture* texture) = 0;
/**
* RenderModel: Render the given model.
*
* This function is called by RenderAllModels.
*
* preconditions : PrepareModelDef and PrepareTexture are called
* before calling RenderModel.
*
* @param model The model that should be rendered.
* @param data Private data for the model as returned by CreateModelData.
*
* postconditions : Subsequent calls to RenderModel for models
* that use the same CModelDef object and the same texture must
* succeed.
*/
virtual void RenderModel(CModel* model, void* data) = 0;
virtual void Render(RenderModifierPtr modifier, u32 flags);
private:
BatchModelRendererInternals* m;

View File

@ -0,0 +1,165 @@
/**
* =========================================================================
* File : ModelVertexRenderer.h
* Project : Pyrogenesis
* Description : Definition of ModelVertexRenderer, the abstract base class
* : for model vertex transformation implementations.
*
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
* =========================================================================
*/
#ifndef MODELVERTEXRENDERER_H
#define MODELVERTEXRENDERER_H
#include "graphics/MeshManager.h"
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.
*/
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.
*
* @param model The model.
*
* @return An opaque pointer that will be passed to other
* ModelVertexRenderer functions whenever the CModel is passed again.
* Note that returning 0 is allowed and does not indicate an error
* condition.
*/
virtual void* CreateModelData(CModel* model) = 0;
/**
* UpdateModelData: Calculate per-model data for each frame.
*
* ModelRenderer implementations must call this once per frame for
* every model that is to be rendered in this frame, even if the
* 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
* the frame. The value is the same as the value of the model's
* CRenderData::m_UpdateFlags.
*/
virtual void UpdateModelData(CModel* model, void* data, u32 updateflags) = 0;
/**
* DestroyModelData: Release all per-model data that has been allocated
* by CreateModelData or UpdateModelData.
*
* ModelRenderer implementations must ensure that this function is
* 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.
*
* @param model The model.
* @param data Private data as returned by CreateModelData.
*/
virtual void DestroyModelData(CModel* model, void* data) = 0;
/**
* BeginPass: Setup global OpenGL state for this ModelVertexRenderer.
*
* ModelVertexRenderer implementations should prepare "heavy" OpenGL
* state such as vertex shader state to prepare for rendering models
* and delivering vertex data to the fragment stage as described by
* streamflags.
*
* ModelRenderer implementations must call this function before any
* calls to other rendering related functions.
*
* 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.
*/
virtual void BeginPass(uint streamflags) = 0;
/**
* EndPass: Cleanup OpenGL state set up by BeginPass.
*
* ModelRenderer implementations must call this function after
* rendering related functions for one pass have been called.
*
* @param streamflags Vertex streams required by the fragment stage.
* This equals the streamflags parameter passed on the last call to
* BeginPass.
*/
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,
* it must call PrepareModelDef for every switch.
*
* @param streamflags Vertex streams required by the fragment stage.
* This equals the streamflags parameter passed on the last call to
* BeginPass.
* @param def The model definition.
*/
virtual void PrepareModelDef(uint streamflags, CModelDefPtr def) = 0;
/**
* RenderModel: Invoke the rendering commands for the given model.
*
* ModelRenderer implementations must call this function to perform
* the actual rendering.
*
* preconditions : The most recent call to PrepareModelDef since
* BeginPass has been for model->GetModelDef().
*
* @param streamflags Vertex streams required by the fragment stage.
* This equals the streamflags parameter passed on the last call to
* BeginPass.
* @param model The model that should be rendered.
* @param data Private data for the model as returned by CreateModelData.
*
* postconditions : Subsequent calls to RenderModel for models
* that use the same CModelDef object and the same texture must
* succeed.
*/
virtual void RenderModel(uint streamflags, CModel* model, void* data) = 0;
};
#endif // MODELVERTEXRENDERER_H

View File

@ -61,7 +61,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_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
// TexEnv #1
pglActiveTextureARB(GL_TEXTURE0+1);
glEnable(GL_TEXTURE_2D);

View File

@ -94,32 +94,39 @@ CRenderer::CRenderer()
}
// model rendering
m_Models.NormalFF = new FixedFunctionModelRenderer;
m_Models.PlayerFF = new FixedFunctionModelRenderer;
m_Models.TransparentFF = new FixedFunctionModelRenderer;
m_Models.VertexFF = ModelVertexRendererPtr(new FixedFunctionModelRenderer);
if (HWLightingModelRenderer::IsAvailable())
m_Models.VertexHWLit = ModelVertexRendererPtr(new HWLightingModelRenderer);
if (InstancingModelRenderer::IsAvailable())
m_Models.VertexInstancing = ModelVertexRendererPtr(new InstancingModelRenderer);
m_Models.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)
{
m_Models.NormalHWLit = new HWLightingModelRenderer;
m_Models.PlayerHWLit = new HWLightingModelRenderer;
m_Models.TransparentHWLit = new HWLightingModelRenderer;
m_Models.NormalHWLit = new BatchModelRenderer(m_Models.VertexHWLit);
m_Models.PlayerHWLit = new BatchModelRenderer(m_Models.VertexHWLit);
m_Models.TranspHWLit = new SortModelRenderer(m_Models.VertexHWLit);
}
else
{
m_Models.NormalHWLit = NULL;
m_Models.PlayerHWLit = NULL;
m_Models.TransparentHWLit = NULL;
m_Models.TranspHWLit = NULL;
}
if (InstancingModelRenderer::IsAvailable())
if (m_Models.VertexInstancing)
{
m_Models.NormalInstancing = new InstancingModelRenderer;
m_Models.PlayerInstancing = new InstancingModelRenderer;
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.Transparency = new TransparencyRenderer;
m_Models.TranspSortAll = new SortModelRenderer(m_Models.VertexPolygonSort);
m_Models.ModWireframe = RenderModifierPtr(new WireframeRenderModifier);
m_Models.ModPlain = RenderModifierPtr(new PlainRenderModifier);
@ -155,13 +162,13 @@ CRenderer::~CRenderer()
// model rendering
delete m_Models.NormalFF;
delete m_Models.PlayerFF;
delete m_Models.TransparentFF;
delete m_Models.TranspFF;
delete m_Models.NormalHWLit;
delete m_Models.PlayerHWLit;
delete m_Models.TransparentHWLit;
delete m_Models.TranspHWLit;
delete m_Models.NormalInstancing;
delete m_Models.PlayerInstancing;
delete m_Models.Transparency;
delete m_Models.TranspSortAll;
// general
delete m_VertexShader;
@ -806,10 +813,10 @@ void CRenderer::RenderShadowMap()
m_Models.NormalInstancing->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
if (m_Models.PlayerInstancing)
m_Models.PlayerInstancing->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
m_Models.TransparentFF->Render(m_Models.ModTransparentShadow, MODELFLAG_CASTSHADOWS);
if (m_Models.TransparentHWLit)
m_Models.TransparentHWLit->Render(m_Models.ModTransparentShadow, MODELFLAG_CASTSHADOWS);
m_Models.Transparency->Render(m_Models.ModTransparentShadow, MODELFLAG_CASTSHADOWS);
m_Models.TranspFF->Render(m_Models.ModTransparentShadow, MODELFLAG_CASTSHADOWS);
if (m_Models.TranspHWLit)
m_Models.TranspHWLit->Render(m_Models.ModTransparentShadow, MODELFLAG_CASTSHADOWS);
m_Models.TranspSortAll->Render(m_Models.ModTransparentShadow, MODELFLAG_CASTSHADOWS);
glEnable(GL_CULL_FACE);
@ -1099,19 +1106,19 @@ void CRenderer::RenderTransparentModels()
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
m_Models.TransparentFF->Render(m_Models.ModTransparent, 0);
if (m_Models.TransparentHWLit)
m_Models.TransparentHWLit->Render(m_Models.ModTransparent, 0);
m_Models.Transparency->Render(m_Models.ModTransparent, 0);
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);
if (m_ModelRenderMode==WIREFRAME) {
// switch wireframe off again
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
} else if (m_ModelRenderMode==EDGED_FACES) {
m_Models.TransparentFF->Render(m_Models.ModWireframe, 0);
if (m_Models.TransparentHWLit)
m_Models.TransparentHWLit->Render(m_Models.ModWireframe, 0);
m_Models.Transparency->Render(m_Models.ModWireframe, 0);
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);
}
}
@ -1130,18 +1137,18 @@ void CRenderer::FlushFrame()
PROFILE_START("prepare models");
m_Models.NormalFF->PrepareModels();
m_Models.PlayerFF->PrepareModels();
m_Models.TransparentFF->PrepareModels();
m_Models.TranspFF->PrepareModels();
if (m_Models.NormalHWLit)
m_Models.NormalHWLit->PrepareModels();
if (m_Models.PlayerHWLit)
m_Models.PlayerHWLit->PrepareModels();
if (m_Models.TransparentHWLit)
m_Models.TransparentHWLit->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.Transparency->PrepareModels();
m_Models.TranspSortAll->PrepareModels();
PROFILE_END("prepare models");
if (!m_ShadowRendered) {
@ -1192,18 +1199,18 @@ void CRenderer::FlushFrame()
// Finish model renderers
m_Models.NormalFF->EndFrame();
m_Models.PlayerFF->EndFrame();
m_Models.TransparentFF->EndFrame();
m_Models.TranspFF->EndFrame();
if (m_Models.NormalHWLit)
m_Models.NormalHWLit->EndFrame();
if (m_Models.PlayerHWLit)
m_Models.PlayerHWLit->EndFrame();
if (m_Models.TransparentHWLit)
m_Models.TransparentHWLit->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.Transparency->EndFrame();
m_Models.TranspSortAll->EndFrame();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -1285,11 +1292,11 @@ void CRenderer::Submit(CModel* model)
else if (model->GetMaterial().UsesAlpha())
{
if (m_SortAllTransparent)
m_Models.Transparency->Submit(model);
m_Models.TranspSortAll->Submit(model);
else if (m_Options.m_RenderPath == RP_VERTEXSHADER)
m_Models.TransparentHWLit->Submit(model);
m_Models.TranspHWLit->Submit(model);
else
m_Models.TransparentFF->Submit(model);
m_Models.TranspFF->Submit(model);
}
else
{

View File

@ -276,6 +276,9 @@ public:
// return the current light environment
const CLightEnv &GetLightEnv() { return *m_LightEnv; }
// return the current camera
const CCamera& GetCamera() const { return m_Camera; }
/**
* SetFastPlayerColor: Tell the renderer which path to take for
* player colored models. Both paths should provide the same visual
@ -292,7 +295,8 @@ protected:
friend class CPatchRData;
friend class FixedFunctionModelRenderer;
friend class ModelRenderer;
friend class TransparencyRenderer;
friend class PolygonSortModelRenderer;
friend class SortModelRenderer;
friend class RenderPathVertexShader;
friend class HWLightingModelRenderer;
friend class InstancingModelRenderer;
@ -413,14 +417,20 @@ protected:
struct Models {
ModelRenderer* NormalFF;
ModelRenderer* PlayerFF;
ModelRenderer* TransparentFF;
ModelRenderer* NormalHWLit;
ModelRenderer* PlayerHWLit;
ModelRenderer* TransparentHWLit;
ModelRenderer* NormalInstancing;
ModelRenderer* PlayerInstancing;
ModelRenderer* Transparency;
ModelRenderer* TranspFF;
ModelRenderer* TranspHWLit;
ModelRenderer* TranspSortAll;
ModelVertexRendererPtr VertexFF;
ModelVertexRendererPtr VertexHWLit;
ModelVertexRendererPtr VertexInstancing;
ModelVertexRendererPtr VertexPolygonSort;
RenderModifierPtr ModWireframe;
RenderModifierPtr ModPlain;
RenderModifierPtr ModPlayer;

View File

@ -2,8 +2,9 @@
* =========================================================================
* File : TransparencyRenderer.h
* Project : Pyrogenesis
* Description : ModelRenderer implementation that sorts polygons based
* : on distance from viewer, for transparency rendering.
* Description : ModelRenderer implementation that sorts models and/or
* : polygons based on distance from viewer, for transparency
* : rendering.
*
* @author Rich Cross <rich@wildfiregames.com>
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
@ -31,14 +32,15 @@
///////////////////////////////////////////////////////////////////////////////////////////////////
// TransparencyRenderer implementation
// PolygonSortModelRenderer implementation
/**
* Struct TModelDef: Per-CModelDef data for the transparency renderer
* Struct PSModelDef: Per-CModelDef data for the polygon sort vertex renderer
*/
struct TModelDef : public CModelDefRPrivate
struct PSModelDef : public CModelDefRPrivate
{
TModelDef(CModelDefPtr mdef);
PSModelDef(CModelDefPtr mdef);
/// Static vertex array
VertexArray m_Array;
@ -47,7 +49,7 @@ struct TModelDef : public CModelDefRPrivate
VertexArray::Attribute m_UV;
};
TModelDef::TModelDef(CModelDefPtr mdef)
PSModelDef::PSModelDef(CModelDefPtr mdef)
: m_Array(false)
{
m_UV.type = GL_FLOAT;
@ -67,11 +69,12 @@ TModelDef::TModelDef(CModelDefPtr mdef)
/**
* Struct TModel: Per-CModel data for the transparency renderer
* Struct PSModel: Per-CModel data for the polygon sorting renderer
*/
struct TModel : public CModelRData
struct PSModel
{
TModel(TransparencyRendererInternals* tri, CModel* model);
PSModel(CModel* model);
~PSModel();
/**
* BackToFrontIndexSort: Sort polygons by distance to camera for
@ -83,6 +86,9 @@ struct TModel : public CModelRData
*/
float BackToFrontIndexSort(const CMatrix3D& objToCam);
/// Back-link to the model
CModel* m_Model;
/// Dynamic per-CModel vertex array
VertexArray m_Array;
@ -94,10 +100,10 @@ struct TModel : public CModelRData
u16* m_Indices;
};
TModel::TModel(TransparencyRendererInternals* tri, CModel* model)
: CModelRData(tri, model), m_Array(true)
PSModel::PSModel(CModel* model)
: m_Model(model), m_Array(true)
{
CModelDefPtr mdef = model->GetModelDef();
CModelDefPtr mdef = m_Model->GetModelDef();
m_Position.type = GL_FLOAT;
m_Position.elems = 3;
@ -113,6 +119,11 @@ TModel::TModel(TransparencyRendererInternals* tri, CModel* model)
m_Indices = new u16[mdef->GetNumFaces()*3];
}
PSModel::~PSModel()
{
delete[] m_Indices;
}
typedef std::pair<int,float> IntFloatPair;
@ -122,11 +133,11 @@ struct SortFacesByDist {
}
};
float TModel::BackToFrontIndexSort(const CMatrix3D& worldToCam)
float PSModel::BackToFrontIndexSort(const CMatrix3D& worldToCam)
{
static std::vector<IntFloatPair> IndexSorter;
CModelDefPtr mdef = GetModel()->GetModelDef();
CModelDefPtr mdef = m_Model->GetModelDef();
size_t numFaces = mdef->GetNumFaces();
const SModelFace* faces = mdef->GetFaces();
@ -166,191 +177,325 @@ float TModel::BackToFrontIndexSort(const CMatrix3D& worldToCam)
/**
* Struct SObject: Pair of model and camera distance.
* Struct PolygonSortModelRendererInternals: Internal data structure of
* PolygonSortModelRenderer
*/
struct SObject
struct PolygonSortModelRendererInternals
{
/// the transparent model
TModel* m_Model;
/// sqrd distance from camera to centre of nearest triangle
float m_Dist;
SObject(TModel* tmdl) : m_Model(tmdl), m_Dist(0) { }
};
/**
* Struct TransparencyRendererInternals: Internal data structure of TransparencyRenderer
*/
struct TransparencyRendererInternals
{
/// List of submitted models.
std::vector<SObject> objects;
/// Scratch space for normal vector calculation
std::vector<CVector3D> normals;
};
// Construction / Destruction
TransparencyRenderer::TransparencyRenderer()
PolygonSortModelRenderer::PolygonSortModelRenderer()
{
m = new TransparencyRendererInternals;
m = new PolygonSortModelRendererInternals;
}
TransparencyRenderer::~TransparencyRenderer()
PolygonSortModelRenderer::~PolygonSortModelRenderer()
{
delete m;
}
// Create per-CModel data for the model (and per-CModelDef data if necessary)
void* PolygonSortModelRenderer::CreateModelData(CModel* model)
{
CModelDefPtr mdef = model->GetModelDef();
PSModelDef* psmdef = (PSModelDef*)mdef->GetRenderData(m);
if (!psmdef)
{
psmdef = new PSModelDef(mdef);
mdef->SetRenderData(m, psmdef);
}
return new PSModel(model);
}
// Updated transforms
void PolygonSortModelRenderer::UpdateModelData(CModel* model, void* data, u32 updateflags)
{
PSModel* psmdl = (PSModel*)data;
if (updateflags & RENDERDATA_UPDATE_VERTICES)
{
CModelDefPtr mdef = model->GetModelDef();
size_t numVertices = mdef->GetNumVertices();
// build vertices
if (m->normals.size() < numVertices)
m->normals.resize(numVertices);
VertexArrayIterator<CVector3D> Position = psmdl->m_Position.GetIterator<CVector3D>();
VertexArrayIterator<CVector3D> Normal = VertexArrayIterator<CVector3D>((char*)&m->normals[0], sizeof(CVector3D));
ModelRenderer::BuildPositionAndNormals(model, Position, Normal);
VertexArrayIterator<SColor4ub> Color = psmdl->m_Color.GetIterator<SColor4ub>();
ModelRenderer::BuildColor4ub(model, Normal, Color);
// upload everything to vertex buffer
psmdl->m_Array.Upload();
}
// resort model indices from back to front, according to camera position - and store
// the returned sqrd distance to the centre of the nearest triangle
PROFILE_START( "sorting transparent" );
CMatrix3D worldToCam;
g_Renderer.GetCamera().m_Orientation.GetInverse(worldToCam);
psmdl->BackToFrontIndexSort(worldToCam);
PROFILE_END( "sorting transparent" );
}
// Cleanup per-CModel data
void PolygonSortModelRenderer::DestroyModelData(CModel* UNUSED(model), void* data)
{
PSModel* psmdl = (PSModel*)data;
delete psmdl;
}
// Prepare for one rendering pass
void PolygonSortModelRenderer::BeginPass(uint streamflags)
{
glEnableClientState(GL_VERTEX_ARRAY);
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR) glEnableClientState(GL_COLOR_ARRAY);
}
// Cleanup rendering
void PolygonSortModelRenderer::EndPass(uint streamflags)
{
if (streamflags & STREAM_UV0) glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
// Prepare for rendering models using this CModelDef
void PolygonSortModelRenderer::PrepareModelDef(uint streamflags, CModelDefPtr def)
{
if (streamflags & STREAM_UV0)
{
PSModelDef* psmdef = (PSModelDef*)def->GetRenderData(m);
debug_assert(psmdef);
u8* base = psmdef->m_Array.Bind();
GLsizei stride = (GLsizei)psmdef->m_Array.GetStride();
glTexCoordPointer(2, GL_FLOAT, stride, base + psmdef->m_UV.offset);
}
}
// Render one model
void PolygonSortModelRenderer::RenderModel(uint streamflags, CModel* model, void* data)
{
CModelDefPtr mdef = model->GetModelDef();
PSModel* psmdl = (PSModel*)data;
// Setup per-CModel arrays
u8* base = psmdl->m_Array.Bind();
GLsizei stride = (GLsizei)psmdl->m_Array.GetStride();
glVertexPointer(3, GL_FLOAT, stride, base + psmdl->m_Position.offset);
if (streamflags & STREAM_COLOR)
glColorPointer(3, psmdl->m_Color.type, stride, base + psmdl->m_Color.offset);
// render the lot
size_t numFaces = mdef->GetNumFaces();
pglDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)mdef->GetNumVertices(),
(GLsizei)numFaces*3, GL_UNSIGNED_SHORT, psmdl->m_Indices);
// bump stats
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_ModelTris += numFaces;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// SortModelRenderer implementation
/**
* Struct SModel: Per-CModel data for the model-sorting renderer
*/
struct SModel : public CModelRData
{
SModel(SortModelRendererInternals* tri, CModel* model);
~SModel();
// Back-link to the Model renderer
SortModelRendererInternals* m_SMRI;
// Private data of the ModelVertexRenderer
void* m_Data;
// Distance to camera (for sorting)
float m_Distance;
};
/**
* Struct SortModelRendererInternals: Internal data structure of SortModelRenderer
*/
struct SortModelRendererInternals
{
/// Vertex renderer used for transform and lighting
ModelVertexRendererPtr vertexRenderer;
/// List of submitted models.
std::vector<SModel*> models;
};
SModel::SModel(SortModelRendererInternals* smri, CModel* model)
: CModelRData(smri, model), m_SMRI(smri)
{
m_Data = m_SMRI->vertexRenderer->CreateModelData(model);
m_Distance = 0;
}
SModel::~SModel()
{
m_SMRI->vertexRenderer->DestroyModelData(GetModel(), m_Data);
}
// Construction / Destruction
SortModelRenderer::SortModelRenderer(ModelVertexRendererPtr vertexRenderer)
{
m = new SortModelRendererInternals;
m->vertexRenderer = vertexRenderer;
}
SortModelRenderer::~SortModelRenderer()
{
delete m;
}
// Submit a model: Create, but don't fill in, our own Model and ModelDef structures
void TransparencyRenderer::Submit(CModel* model)
void SortModelRenderer::Submit(CModel* model)
{
CModelRData* rdata = (CModelRData*)model->GetRenderData();
TModel* tmdl;
SModel* smdl;
if (rdata && rdata->GetKey() == m)
{
tmdl = (TModel*)rdata;
smdl = (SModel*)rdata;
}
else
{
CModelDefPtr mdef = model->GetModelDef();
TModelDef* tmdef = (TModelDef*)mdef->GetRenderData(m);
if (!tmdef)
{
tmdef = new TModelDef(mdef);
mdef->SetRenderData(m, tmdef);
}
tmdl = new TModel(m, model);
rdata = tmdl;
smdl = new SModel(m, model);
rdata = smdl;
model->SetRenderData(rdata);
model->SetDirty(~0u);
g_Renderer.LoadTexture(model->GetTexture(), GL_CLAMP_TO_EDGE);
}
m->objects.push_back(tmdl);
m->models.push_back(smdl);
}
// Transform and sort all models
struct SortObjectsByDist {
bool operator()(const SObject& lhs, const SObject& rhs) {
return lhs.m_Dist>rhs.m_Dist? true : false;
struct SortModelsByDist {
bool operator()(SModel* lhs, SModel* rhs) {
return lhs->m_Distance > rhs->m_Distance ? true : false;
}
};
void TransparencyRenderer::PrepareModels()
void SortModelRenderer::PrepareModels()
{
CMatrix3D worldToCam;
if (m->objects.size() == 0)
if (m->models.size() == 0)
return;
g_Renderer.m_Camera.m_Orientation.GetInverse(worldToCam);
for(std::vector<SObject>::iterator it = m->objects.begin(); it != m->objects.end(); ++it)
for(std::vector<SModel*>::iterator it = m->models.begin(); it != m->models.end(); ++it)
{
TModel* tmdl = it->m_Model;
CModel* model = tmdl->GetModel();
SModel* smdl = *it;
CModel* model = smdl->GetModel();
debug_assert(model->GetRenderData() == tmdl);
debug_assert(model->GetRenderData() == smdl);
if (tmdl->m_UpdateFlags & RENDERDATA_UPDATE_VERTICES)
{
CModelDefPtr mdef = model->GetModelDef();
size_t numVertices = mdef->GetNumVertices();
// build vertices
if (m->normals.size() < numVertices)
m->normals.resize(numVertices);
m->vertexRenderer->UpdateModelData(model, smdl->m_Data, smdl->m_UpdateFlags);
smdl->m_UpdateFlags = 0;
VertexArrayIterator<CVector3D> Position = tmdl->m_Position.GetIterator<CVector3D>();
VertexArrayIterator<CVector3D> Normal = VertexArrayIterator<CVector3D>((char*)&m->normals[0], sizeof(CVector3D));
CVector3D modelpos = model->GetTransform().GetTranslation();
BuildPositionAndNormals(model, Position, Normal);
modelpos = worldToCam.Transform(modelpos);
VertexArrayIterator<SColor4ub> Color = tmdl->m_Color.GetIterator<SColor4ub>();
BuildColor4ub(model, Normal, Color);
// upload everything to vertex buffer
tmdl->m_Array.Upload();
}
tmdl->m_UpdateFlags = 0;
// resort model indices from back to front, according to camera position - and store
// the returned sqrd distance to the centre of the nearest triangle
PROFILE_START( "sorting transparent" );
it->m_Dist = tmdl->BackToFrontIndexSort(worldToCam);
PROFILE_END( "sorting transparent" );
smdl->m_Distance = modelpos.Z;
}
PROFILE_START( "sorting transparent" );
std::sort(m->objects.begin(), m->objects.end(), SortObjectsByDist());
std::sort(m->models.begin(), m->models.end(), SortModelsByDist());
PROFILE_END( "sorting transparent" );
}
// Render all models in order
void TransparencyRenderer::EndFrame()
// Cleanup per-frame model list
void SortModelRenderer::EndFrame()
{
m->objects.clear();
m->models.clear();
}
// Return whether models have been submitted this frame
bool TransparencyRenderer::HaveSubmissions()
bool SortModelRenderer::HaveSubmissions()
{
return m->objects.size() != 0;
return m->models.size() != 0;
}
// Render submitted models (filtered by flags) using the given modifier
void TransparencyRenderer::Render(RenderModifierPtr modifier, u32 flags)
void SortModelRenderer::Render(RenderModifierPtr modifier, u32 flags)
{
uint pass = 0;
if (m->objects.size() == 0)
if (m->models.size() == 0)
return;
glEnableClientState(GL_VERTEX_ARRAY);
do
{
u32 streamflags = modifier->BeginPass(pass);
CModelDefPtr lastmdef;
CTexture* lasttex = 0;
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR) glEnableClientState(GL_COLOR_ARRAY);
m->vertexRenderer->BeginPass(streamflags);
for(std::vector<SObject>::iterator it = m->objects.begin(); it != m->objects.end(); ++it)
for(std::vector<SModel*>::iterator it = m->models.begin(); it != m->models.end(); ++it)
{
if (flags & !(it->m_Model->GetModel()->GetFlags()&flags))
SModel* smdl = *it;
CModel* mdl = smdl->GetModel();
if (flags & !(mdl->GetFlags() & flags))
continue;
TModel* tmdl = it->m_Model;
CModel* mdl = tmdl->GetModel();
debug_assert(smdl->GetKey() == m);
CModelDefPtr mdef = mdl->GetModelDef();
CTexture* tex = mdl->GetTexture();
// Prepare per-CModelDef data if changed
if (mdef != lastmdef)
{
TModelDef* tmdef = (TModelDef*)mdef->GetRenderData(m);
if (streamflags & STREAM_UV0)
{
u8* base = tmdef->m_Array.Bind();
GLsizei stride = (GLsizei)tmdef->m_Array.GetStride();
glTexCoordPointer(2, GL_FLOAT, stride, base + tmdef->m_UV.offset);
}
m->vertexRenderer->PrepareModelDef(streamflags, mdef);
lastmdef = mdef;
}
@ -363,29 +508,12 @@ void TransparencyRenderer::Render(RenderModifierPtr modifier, u32 flags)
modifier->PrepareModel(pass, mdl);
// Setup per-CModel arrays
u8* base = tmdl->m_Array.Bind();
GLsizei stride = (GLsizei)tmdl->m_Array.GetStride();
glVertexPointer(3, GL_FLOAT, stride, base + tmdl->m_Position.offset);
if (streamflags & STREAM_COLOR)
glColorPointer(3, tmdl->m_Color.type, stride, base + tmdl->m_Color.offset);
// render the lot
size_t numFaces = mdef->GetNumFaces();
pglDrawRangeElementsEXT(GL_TRIANGLES, 0, (GLuint)mdef->GetNumVertices(),
(GLsizei)numFaces*3, GL_UNSIGNED_SHORT, tmdl->m_Indices);
// bump stats
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_ModelTris += numFaces;
// Render the model
m->vertexRenderer->RenderModel(streamflags, mdl, smdl->m_Data);
}
if (streamflags & STREAM_UV0) glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY);
m->vertexRenderer->EndPass(streamflags);
} while(!modifier->EndPass(pass++));
glDisableClientState(GL_VERTEX_ARRAY);
}

View File

@ -2,8 +2,9 @@
* =========================================================================
* File : TransparencyRenderer.h
* Project : Pyrogenesis
* Description : ModelRenderer implementation that sorts polygons based
* : on distance from viewer, for transparency rendering.
* Description : ModelRenderer implementation that sorts models and/or
* : polygons based on distance from viewer, for transparency
* : rendering.
*
* @author Rich Cross <rich@wildfiregames.com>
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
@ -14,52 +15,70 @@
#define __TRANSPARENCYRENDERER_H
#include "renderer/ModelRenderer.h"
#include "renderer/ModelVertexRenderer.h"
#include "renderer/RenderModifiers.h"
struct TransparencyRendererInternals;
struct PolygonSortModelRendererInternals;
/**
* Class TransparencyRenderer: Render transparent models that require
* Z-based sorting.
* Class PolygonSortModelRenderer: Render animated models using only
* OpenGL fixed function, sorting polygons from back to front.
*
* This is a lot less efficient than batched model
* renderers, so it should be used only when really necessary for
* translucent models. Models that use the alpha channel for masking
* should probably use a batched model renderer and an appropriate
* RenderModifier.
*
* Use this renderer together with TransparentRenderModifier and
* TransparentShadowRenderModifier.
* This ModelVertexRenderer should only be used with SortModelRenderer.
* However, SortModelRenderer can be used with other ModelVertexRenderers
* than this one.
*/
class TransparencyRenderer : public ModelRenderer
class PolygonSortModelRenderer : public ModelVertexRenderer
{
public:
TransparencyRenderer();
~TransparencyRenderer();
PolygonSortModelRenderer();
~PolygonSortModelRenderer();
// Implementations
void* CreateModelData(CModel* model);
void UpdateModelData(CModel* model, void* data, u32 updateflags);
void DestroyModelData(CModel* model, void* data);
void BeginPass(uint streamflags);
void EndPass(uint streamflags);
void PrepareModelDef(uint streamflags, CModelDefPtr def);
void RenderModel(uint streamflags, CModel* model, void* data);
private:
PolygonSortModelRendererInternals* m;
};
struct SortModelRendererInternals;
/**
* Class SortModelRenderer: Render models back-to-front from the
* camera's point of view.
*
* This is less efficient than batched model renderers, but
* necessary for transparent models.
*
* TransparencyRenderer can be used with any ModelVertexRenderer.
*
* Use this renderer together with TransparentRenderModifier and
* TransparentShadowRenderModifier to achieve transparency.
*/
class SortModelRenderer : public ModelRenderer
{
public:
SortModelRenderer(ModelVertexRendererPtr vertexrenderer);
~SortModelRenderer();
// Transparency renderer implementation
void Submit(CModel* model);
void PrepareModels();
void EndFrame();
bool HaveSubmissions();
/**
* Render: Render submitted models, using the given RenderModifier to setup
* the fragment stage.
*
* preconditions : PrepareModels must be called after all models have been
* submitted and before calling Render.
*
* @param modifier The RenderModifier that specifies the fragment stage.
* @param flags If flags is 0, all submitted models are rendered.
* If flags is non-zero, only models that contain flags in their
* CModel::GetFlags() are rendered.
*/
void Render(RenderModifierPtr modifier, u32 flags);
private:
TransparencyRendererInternals* m;
SortModelRendererInternals* m;
};