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:
parent
139c48e733
commit
0346ba1b18
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
165
source/renderer/ModelVertexRenderer.h
Normal file
165
source/renderer/ModelVertexRenderer.h
Normal 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
|
@ -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);
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user