2005-10-25 03:43:07 +02:00
|
|
|
/**
|
|
|
|
* =========================================================================
|
|
|
|
* File : TransparencyRenderer.h
|
|
|
|
* Project : Pyrogenesis
|
2006-01-07 02:04:26 +01:00
|
|
|
* Description : ModelRenderer implementation that sorts models and/or
|
|
|
|
* : polygons based on distance from viewer, for transparency
|
2005-11-06 00:15:23 +01:00
|
|
|
* : rendering.
|
2005-10-25 03:43:07 +02:00
|
|
|
*
|
|
|
|
* @author Rich Cross <rich@wildfiregames.com>
|
|
|
|
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
|
|
|
|
* =========================================================================
|
|
|
|
*/
|
2004-06-11 00:24:03 +02:00
|
|
|
|
2004-06-03 20:38:14 +02:00
|
|
|
#include "precompiled.h"
|
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
#include <algorithm>
|
2005-10-25 03:43:07 +02:00
|
|
|
#include <vector>
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
#include "ogl.h"
|
|
|
|
#include "MathUtil.h"
|
|
|
|
#include "Vector3D.h"
|
|
|
|
#include "Vector4D.h"
|
|
|
|
|
|
|
|
#include "graphics/Model.h"
|
|
|
|
#include "graphics/ModelDef.h"
|
|
|
|
|
|
|
|
#include "ps/Profile.h"
|
|
|
|
|
|
|
|
#include "renderer/Renderer.h"
|
|
|
|
#include "renderer/TransparencyRenderer.h"
|
|
|
|
#include "renderer/VertexArray.h"
|
2004-05-30 02:46:58 +02:00
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
2005-11-06 00:15:23 +01:00
|
|
|
// PolygonSortModelRenderer implementation
|
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
|
|
|
|
/**
|
2005-11-06 00:15:23 +01:00
|
|
|
* Struct PSModelDef: Per-CModelDef data for the polygon sort vertex renderer
|
2005-10-25 03:43:07 +02:00
|
|
|
*/
|
2005-11-06 00:15:23 +01:00
|
|
|
struct PSModelDef : public CModelDefRPrivate
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
2005-11-06 00:15:23 +01:00
|
|
|
PSModelDef(CModelDefPtr mdef);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
/// Static vertex array
|
|
|
|
VertexArray m_Array;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
/// UV is static
|
|
|
|
VertexArray::Attribute m_UV;
|
|
|
|
};
|
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
PSModelDef::PSModelDef(CModelDefPtr mdef)
|
2005-10-25 03:43:07 +02:00
|
|
|
: m_Array(false)
|
|
|
|
{
|
|
|
|
m_UV.type = GL_FLOAT;
|
|
|
|
m_UV.elems = 2;
|
|
|
|
m_Array.AddAttribute(&m_UV);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
m_Array.SetNumVertices(mdef->GetNumVertices());
|
|
|
|
m_Array.Layout();
|
|
|
|
|
|
|
|
VertexArrayIterator<float[2]> UVit = m_UV.GetIterator<float[2]>();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
ModelRenderer::BuildUV(mdef, UVit);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
m_Array.Upload();
|
|
|
|
m_Array.FreeBackingStore();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2005-11-06 00:15:23 +01:00
|
|
|
* Struct PSModel: Per-CModel data for the polygon sorting renderer
|
2005-10-25 03:43:07 +02:00
|
|
|
*/
|
2005-11-06 00:15:23 +01:00
|
|
|
struct PSModel
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
2005-11-06 00:15:23 +01:00
|
|
|
PSModel(CModel* model);
|
|
|
|
~PSModel();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
/**
|
|
|
|
* BackToFrontIndexSort: Sort polygons by distance to camera for
|
|
|
|
* transparency rendering and fill the indices array appropriately.
|
|
|
|
*
|
|
|
|
* @param worldToCam World to camera coordinate space transform
|
|
|
|
*
|
|
|
|
* @return Square of the estimated distance to the nearest triangle.
|
|
|
|
*/
|
|
|
|
float BackToFrontIndexSort(const CMatrix3D& objToCam);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
/// Back-link to the model
|
|
|
|
CModel* m_Model;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
/// Dynamic per-CModel vertex array
|
|
|
|
VertexArray m_Array;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
/// Position and lighting are recalculated on CPU every frame
|
|
|
|
VertexArray::Attribute m_Position;
|
|
|
|
VertexArray::Attribute m_Color;
|
|
|
|
|
|
|
|
/// Indices array (sorted on CPU based on distance to camera)
|
|
|
|
u16* m_Indices;
|
|
|
|
};
|
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
PSModel::PSModel(CModel* model)
|
|
|
|
: m_Model(model), m_Array(true)
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
2005-11-06 00:15:23 +01:00
|
|
|
CModelDefPtr mdef = m_Model->GetModelDef();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
m_Position.type = GL_FLOAT;
|
|
|
|
m_Position.elems = 3;
|
|
|
|
m_Array.AddAttribute(&m_Position);
|
|
|
|
|
|
|
|
m_Color.type = GL_UNSIGNED_BYTE;
|
|
|
|
m_Color.elems = 4;
|
|
|
|
m_Array.AddAttribute(&m_Color);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
m_Array.SetNumVertices(mdef->GetNumVertices());
|
|
|
|
m_Array.Layout();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
m_Indices = new u16[mdef->GetNumFaces()*3];
|
|
|
|
}
|
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
PSModel::~PSModel()
|
|
|
|
{
|
|
|
|
delete[] m_Indices;
|
|
|
|
}
|
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
|
|
|
|
typedef std::pair<int,float> IntFloatPair;
|
|
|
|
|
|
|
|
struct SortFacesByDist {
|
|
|
|
bool operator()(const IntFloatPair& lhs,const IntFloatPair& rhs) {
|
|
|
|
return lhs.second>rhs.second ? true : false;
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
float PSModel::BackToFrontIndexSort(const CMatrix3D& worldToCam)
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
2005-10-25 03:43:07 +02:00
|
|
|
static std::vector<IntFloatPair> IndexSorter;
|
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
CModelDefPtr mdef = m_Model->GetModelDef();
|
2005-10-25 03:43:07 +02:00
|
|
|
size_t numFaces = mdef->GetNumFaces();
|
|
|
|
const SModelFace* faces = mdef->GetFaces();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
if (IndexSorter.size() < numFaces)
|
|
|
|
IndexSorter.resize(numFaces);
|
|
|
|
|
|
|
|
VertexArrayIterator<CVector3D> Position = m_Position.GetIterator<CVector3D>();
|
|
|
|
CVector3D tmpvtx;
|
|
|
|
|
|
|
|
for(size_t i = 0; i < numFaces; ++i)
|
|
|
|
{
|
|
|
|
tmpvtx = Position[faces[i].m_Verts[0]];
|
|
|
|
tmpvtx += Position[faces[i].m_Verts[1]];
|
|
|
|
tmpvtx += Position[faces[i].m_Verts[2]];
|
|
|
|
tmpvtx *= 1.0f/3.0f;
|
|
|
|
|
|
|
|
tmpvtx = worldToCam.Transform(tmpvtx);
|
|
|
|
float distsqrd = SQR(tmpvtx.X)+SQR(tmpvtx.Y)+SQR(tmpvtx.Z);
|
|
|
|
|
2005-10-31 17:26:51 +01:00
|
|
|
IndexSorter[i].first = (int)i;
|
2005-10-25 03:43:07 +02:00
|
|
|
IndexSorter[i].second = distsqrd;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::sort(IndexSorter.begin(),IndexSorter.begin()+numFaces,SortFacesByDist());
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
// now build index list
|
|
|
|
u32 idxidx = 0;
|
|
|
|
for (size_t i = 0; i < numFaces; ++i) {
|
|
|
|
const SModelFace& face = faces[IndexSorter[i].first];
|
|
|
|
m_Indices[idxidx++] = (u16)(face.m_Verts[0]);
|
|
|
|
m_Indices[idxidx++] = (u16)(face.m_Verts[1]);
|
|
|
|
m_Indices[idxidx++] = (u16)(face.m_Verts[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return IndexSorter[0].second;
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
|
|
|
|
/**
|
2005-11-06 00:15:23 +01:00
|
|
|
* Struct PolygonSortModelRendererInternals: Internal data structure of
|
|
|
|
* PolygonSortModelRenderer
|
2005-10-25 03:43:07 +02:00
|
|
|
*/
|
2005-11-06 00:15:23 +01:00
|
|
|
struct PolygonSortModelRendererInternals
|
|
|
|
{
|
|
|
|
/// Scratch space for normal vector calculation
|
|
|
|
std::vector<CVector3D> normals;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Construction / Destruction
|
|
|
|
PolygonSortModelRenderer::PolygonSortModelRenderer()
|
|
|
|
{
|
|
|
|
m = new PolygonSortModelRendererInternals;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
if (!psmdef)
|
|
|
|
{
|
|
|
|
psmdef = new PSModelDef(mdef);
|
|
|
|
mdef->SetRenderData(m, psmdef);
|
|
|
|
}
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
return new PSModel(model);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Updated transforms
|
|
|
|
void PolygonSortModelRenderer::UpdateModelData(CModel* model, void* data, u32 updateflags)
|
|
|
|
{
|
|
|
|
PSModel* psmdl = (PSModel*)data;
|
|
|
|
|
2006-02-15 01:45:16 +01:00
|
|
|
if (updateflags & (RENDERDATA_UPDATE_VERTICES|RENDERDATA_UPDATE_COLOR))
|
2005-11-06 00:15:23 +01:00
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2006-01-22 20:12:30 +01:00
|
|
|
// resort model indices from back to front, according to the view camera position - and store
|
2005-11-06 00:15:23 +01:00
|
|
|
// the returned sqrd distance to the centre of the nearest triangle
|
2006-01-22 20:12:30 +01:00
|
|
|
// Use the view camera instead of the cull camera because:
|
|
|
|
// a) polygon sorting implicitly uses the view camera (and changing that would be costly)
|
|
|
|
// b) using the cull camera is likely not interesting from a debugging POV
|
2005-11-06 00:15:23 +01:00
|
|
|
PROFILE_START( "sorting transparent" );
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
CMatrix3D worldToCam;
|
2006-01-22 20:12:30 +01:00
|
|
|
g_Renderer.GetViewCamera().m_Orientation.GetInverse(worldToCam);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
psmdl->BackToFrontIndexSort(worldToCam);
|
|
|
|
PROFILE_END( "sorting transparent" );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Cleanup per-CModel data
|
|
|
|
void PolygonSortModelRenderer::DestroyModelData(CModel* UNUSED(model), void* data)
|
|
|
|
{
|
|
|
|
PSModel* psmdl = (PSModel*)data;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
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);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
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);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
debug_assert(psmdef);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
u8* base = psmdef->m_Array.Bind();
|
|
|
|
GLsizei stride = (GLsizei)psmdef->m_Array.GetStride();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
glTexCoordPointer(2, GL_FLOAT, stride, base + psmdef->m_UV.offset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Render one model
|
|
|
|
void PolygonSortModelRenderer::RenderModel(uint streamflags, CModel* model, void* data)
|
2004-06-11 00:24:03 +02:00
|
|
|
{
|
2005-11-06 00:15:23 +01:00
|
|
|
CModelDefPtr mdef = model->GetModelDef();
|
|
|
|
PSModel* psmdl = (PSModel*)data;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
// Setup per-CModel arrays
|
|
|
|
u8* base = psmdl->m_Array.Bind();
|
|
|
|
GLsizei stride = (GLsizei)psmdl->m_Array.GetStride();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
glVertexPointer(3, GL_FLOAT, stride, base + psmdl->m_Position.offset);
|
|
|
|
if (streamflags & STREAM_COLOR)
|
2006-01-07 02:04:26 +01:00
|
|
|
glColorPointer(3, psmdl->m_Color.type, stride, base + psmdl->m_Color.offset);
|
2005-11-06 00:15:23 +01:00
|
|
|
|
|
|
|
// 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
|
2005-05-20 19:09:47 +02:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
/**
|
|
|
|
* Struct SModel: Per-CModel data for the model-sorting renderer
|
|
|
|
*/
|
|
|
|
struct SModel : public CModelRData
|
|
|
|
{
|
|
|
|
SModel(SortModelRendererInternals* tri, CModel* model);
|
|
|
|
~SModel();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
// Back-link to the Model renderer
|
|
|
|
SortModelRendererInternals* m_SMRI;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
// Private data of the ModelVertexRenderer
|
|
|
|
void* m_Data;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
// Distance to camera (for sorting)
|
|
|
|
float m_Distance;
|
2005-10-25 03:43:07 +02:00
|
|
|
};
|
2004-06-07 21:53:58 +02:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
/**
|
2005-11-06 00:15:23 +01:00
|
|
|
* Struct SortModelRendererInternals: Internal data structure of SortModelRenderer
|
2005-10-25 03:43:07 +02:00
|
|
|
*/
|
2005-11-06 00:15:23 +01:00
|
|
|
struct SortModelRendererInternals
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
2005-11-06 00:15:23 +01:00
|
|
|
/// Vertex renderer used for transform and lighting
|
|
|
|
ModelVertexRendererPtr vertexRenderer;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
/// List of submitted models.
|
|
|
|
std::vector<SModel*> models;
|
2005-10-25 03:43:07 +02:00
|
|
|
};
|
2004-05-30 02:46:58 +02:00
|
|
|
|
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
// Construction / Destruction
|
2005-11-06 00:15:23 +01:00
|
|
|
SortModelRenderer::SortModelRenderer(ModelVertexRendererPtr vertexRenderer)
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
2005-11-06 00:15:23 +01:00
|
|
|
m = new SortModelRendererInternals;
|
|
|
|
m->vertexRenderer = vertexRenderer;
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
2004-06-11 00:24:03 +02:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
SortModelRenderer::~SortModelRenderer()
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
|
|
|
delete m;
|
|
|
|
}
|
2004-06-11 00:24:03 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
// Submit a model: Create, but don't fill in, our own Model and ModelDef structures
|
2005-11-06 00:15:23 +01:00
|
|
|
void SortModelRenderer::Submit(CModel* model)
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
|
|
|
CModelRData* rdata = (CModelRData*)model->GetRenderData();
|
2005-11-06 00:15:23 +01:00
|
|
|
SModel* smdl;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
if (rdata && rdata->GetKey() == m)
|
|
|
|
{
|
2005-11-06 00:15:23 +01:00
|
|
|
smdl = (SModel*)rdata;
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-11-06 00:15:23 +01:00
|
|
|
smdl = new SModel(m, model);
|
|
|
|
rdata = smdl;
|
2005-10-25 03:43:07 +02:00
|
|
|
model->SetRenderData(rdata);
|
2005-10-31 17:26:51 +01:00
|
|
|
model->SetDirty(~0u);
|
2005-10-25 03:43:07 +02:00
|
|
|
g_Renderer.LoadTexture(model->GetTexture(), GL_CLAMP_TO_EDGE);
|
|
|
|
}
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
m->models.push_back(smdl);
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2004-06-11 00:24:03 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
// Transform and sort all models
|
2005-11-06 00:15:23 +01:00
|
|
|
struct SortModelsByDist {
|
|
|
|
bool operator()(SModel* lhs, SModel* rhs) {
|
|
|
|
return lhs->m_Distance > rhs->m_Distance ? true : false;
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
|
|
|
};
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
void SortModelRenderer::PrepareModels()
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
|
|
|
CMatrix3D worldToCam;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
if (m->models.size() == 0)
|
2005-10-25 04:22:22 +02:00
|
|
|
return;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2006-01-22 20:12:30 +01:00
|
|
|
g_Renderer.GetViewCamera().m_Orientation.GetInverse(worldToCam);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
for(std::vector<SModel*>::iterator it = m->models.begin(); it != m->models.end(); ++it)
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
2005-11-06 00:15:23 +01:00
|
|
|
SModel* smdl = *it;
|
|
|
|
CModel* model = smdl->GetModel();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
debug_assert(model->GetRenderData() == smdl);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
m->vertexRenderer->UpdateModelData(model, smdl->m_Data, smdl->m_UpdateFlags);
|
|
|
|
smdl->m_UpdateFlags = 0;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
CVector3D modelpos = model->GetTransform().GetTranslation();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
modelpos = worldToCam.Transform(modelpos);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
smdl->m_Distance = modelpos.Z;
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
2004-10-17 23:01:00 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
PROFILE_START( "sorting transparent" );
|
2005-11-06 00:15:23 +01:00
|
|
|
std::sort(m->models.begin(), m->models.end(), SortModelsByDist());
|
2005-10-25 03:43:07 +02:00
|
|
|
PROFILE_END( "sorting transparent" );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
// Cleanup per-frame model list
|
|
|
|
void SortModelRenderer::EndFrame()
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
2005-11-06 00:15:23 +01:00
|
|
|
m->models.clear();
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Return whether models have been submitted this frame
|
2005-11-06 00:15:23 +01:00
|
|
|
bool SortModelRenderer::HaveSubmissions()
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
2005-11-06 00:15:23 +01:00
|
|
|
return m->models.size() != 0;
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
2004-05-30 02:46:58 +02:00
|
|
|
|
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
// Render submitted models (filtered by flags) using the given modifier
|
2005-11-06 00:15:23 +01:00
|
|
|
void SortModelRenderer::Render(RenderModifierPtr modifier, u32 flags)
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
|
|
|
uint pass = 0;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
if (m->models.size() == 0)
|
2005-10-25 03:43:07 +02:00
|
|
|
return;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
do
|
|
|
|
{
|
|
|
|
u32 streamflags = modifier->BeginPass(pass);
|
|
|
|
CModelDefPtr lastmdef;
|
|
|
|
CTexture* lasttex = 0;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
m->vertexRenderer->BeginPass(streamflags);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
for(std::vector<SModel*>::iterator it = m->models.begin(); it != m->models.end(); ++it)
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
2005-11-06 00:15:23 +01:00
|
|
|
SModel* smdl = *it;
|
|
|
|
CModel* mdl = smdl->GetModel();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
if (flags & !(mdl->GetFlags() & flags))
|
2005-10-25 03:43:07 +02:00
|
|
|
continue;
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
debug_assert(smdl->GetKey() == m);
|
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
CModelDefPtr mdef = mdl->GetModelDef();
|
|
|
|
CTexture* tex = mdl->GetTexture();
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
// Prepare per-CModelDef data if changed
|
|
|
|
if (mdef != lastmdef)
|
|
|
|
{
|
2005-11-06 00:15:23 +01:00
|
|
|
m->vertexRenderer->PrepareModelDef(streamflags, mdef);
|
2005-10-25 03:43:07 +02:00
|
|
|
lastmdef = mdef;
|
|
|
|
}
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
// Prepare necessary RenderModifier stuff
|
|
|
|
if (tex != lasttex)
|
|
|
|
{
|
|
|
|
modifier->PrepareTexture(pass, tex);
|
|
|
|
lasttex = tex;
|
|
|
|
}
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
modifier->PrepareModel(pass, mdl);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
// Render the model
|
|
|
|
m->vertexRenderer->RenderModel(streamflags, mdl, smdl->m_Data);
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-11-06 00:15:23 +01:00
|
|
|
m->vertexRenderer->EndPass(streamflags);
|
2005-10-25 03:43:07 +02:00
|
|
|
} while(!modifier->EndPass(pass++));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// TransparentRenderModifier implementation
|
|
|
|
|
|
|
|
TransparentRenderModifier::TransparentRenderModifier()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
TransparentRenderModifier::~TransparentRenderModifier()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 TransparentRenderModifier::BeginPass(uint pass)
|
|
|
|
{
|
|
|
|
if (pass == 0)
|
|
|
|
{
|
|
|
|
// First pass: Put down Z for opaque parts of the model,
|
|
|
|
// don't touch the color buffer.
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_CONSTANT);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
|
|
|
|
|
|
|
// just pass through texture's alpha
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
|
|
|
|
|
|
|
// Set the proper LOD bias
|
|
|
|
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
glEnable(GL_ALPHA_TEST);
|
|
|
|
glAlphaFunc(GL_GREATER,0.975f);
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
// render everything with color writes off to setup depth buffer correctly
|
|
|
|
glColorMask(0,0,0,0);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
return STREAM_POS|STREAM_UV0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Second pass: Put down color, disable Z write
|
|
|
|
glColorMask(1,1,1,1);
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
glDepthMask(0);
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
// setup texture environment to modulate diffuse color with texture color
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
glAlphaFunc(GL_GREATER,0);
|
2004-05-30 02:46:58 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
// Set the proper LOD bias
|
|
|
|
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
bool TransparentRenderModifier::EndPass(uint pass)
|
|
|
|
{
|
|
|
|
if (pass == 0)
|
|
|
|
return false; // multi-pass
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
glDepthMask(1);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-10-31 17:26:51 +01:00
|
|
|
void TransparentRenderModifier::PrepareTexture(uint UNUSED(pass), CTexture* texture)
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
2005-10-25 03:43:07 +02:00
|
|
|
g_Renderer.SetTexture(0, texture);
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
2005-10-31 17:26:51 +01:00
|
|
|
void TransparentRenderModifier::PrepareModel(uint UNUSED(pass), CModel* UNUSED(model))
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
2005-11-06 06:05:07 +01:00
|
|
|
// No per-model setup necessary
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
2004-05-30 02:46:58 +02:00
|
|
|
|
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// TransparentShadowRenderModifier implementation
|
|
|
|
|
|
|
|
TransparentShadowRenderModifier::TransparentShadowRenderModifier()
|
|
|
|
{
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
2004-10-21 17:04:19 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
TransparentShadowRenderModifier::~TransparentShadowRenderModifier()
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
2004-06-11 00:24:03 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
u32 TransparentShadowRenderModifier::BeginPass(uint pass)
|
|
|
|
{
|
|
|
|
debug_assert(pass == 0);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2004-05-30 02:46:58 +02:00
|
|
|
glDepthMask(0);
|
|
|
|
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
|
2004-06-07 21:53:58 +02:00
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
|
2004-05-30 02:46:58 +02:00
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
|
|
|
|
2004-10-21 17:04:19 +02:00
|
|
|
// Set the proper LOD bias
|
|
|
|
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
|
2004-10-17 23:01:00 +02:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
return STREAM_POS|STREAM_UV0;
|
|
|
|
}
|
2004-06-11 00:24:03 +02:00
|
|
|
|
2005-10-31 17:26:51 +01:00
|
|
|
bool TransparentShadowRenderModifier::EndPass(uint UNUSED(pass))
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
2004-05-30 02:46:58 +02:00
|
|
|
glDepthMask(1);
|
|
|
|
glDisable(GL_BLEND);
|
2006-01-07 02:04:26 +01:00
|
|
|
|
2005-10-25 03:43:07 +02:00
|
|
|
return true;
|
2004-05-30 02:46:58 +02:00
|
|
|
}
|
|
|
|
|
2005-10-31 17:26:51 +01:00
|
|
|
void TransparentShadowRenderModifier::PrepareTexture(uint UNUSED(pass), CTexture* texture)
|
2004-05-30 02:46:58 +02:00
|
|
|
{
|
2005-10-25 03:43:07 +02:00
|
|
|
g_Renderer.SetTexture(0, texture);
|
2004-06-11 04:14:18 +02:00
|
|
|
}
|
2005-10-25 03:43:07 +02:00
|
|
|
|
2005-10-31 17:26:51 +01:00
|
|
|
void TransparentShadowRenderModifier::PrepareModel(uint UNUSED(pass), CModel* UNUSED(model))
|
2005-10-25 03:43:07 +02:00
|
|
|
{
|
2005-11-06 06:05:07 +01:00
|
|
|
// No per-model setup necessary
|
2005-10-25 03:43:07 +02:00
|
|
|
}
|
2006-02-11 19:04:32 +01:00
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// TransparentDepthShadowModifier implementation
|
|
|
|
|
|
|
|
TransparentDepthShadowModifier::TransparentDepthShadowModifier()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
TransparentDepthShadowModifier::~TransparentDepthShadowModifier()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 TransparentDepthShadowModifier::BeginPass(uint pass)
|
|
|
|
{
|
|
|
|
debug_assert(pass == 0);
|
|
|
|
|
|
|
|
glEnable(GL_ALPHA_TEST);
|
|
|
|
glAlphaFunc(GL_GREATER, 0.4);
|
|
|
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
|
|
|
|
|
|
|
|
// Set the proper LOD bias
|
|
|
|
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
|
|
|
|
|
|
|
|
return STREAM_POS|STREAM_UV0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TransparentDepthShadowModifier::EndPass(uint UNUSED(pass))
|
|
|
|
{
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TransparentDepthShadowModifier::PrepareTexture(uint UNUSED(pass), CTexture* texture)
|
|
|
|
{
|
|
|
|
g_Renderer.SetTexture(0, texture);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TransparentDepthShadowModifier::PrepareModel(uint UNUSED(pass), CModel* UNUSED(model))
|
|
|
|
{
|
|
|
|
// No per-model setup necessary
|
|
|
|
}
|