Reworked model and terrain rendering to use new VertexBuffer classes; many other smaller changes.

This was SVN commit r411.
This commit is contained in:
notpete 2004-06-07 19:53:58 +00:00
parent 4f8ce4b1d4
commit a7d0c194ad
8 changed files with 981 additions and 750 deletions

View file

@ -8,7 +8,12 @@
#include "ModelRData.h"
#include "Model.h"
///////////////////////////////////////////////////////////////////
// shared list of all submitted models this frame
std::vector<CModel*> CModelRData::m_Models;
///////////////////////////////////////////////////////////////////
// CModelRData constructor
CModelRData::CModelRData(CModel* model)
: m_Model(model), m_Vertices(0), m_Normals(0), m_Indices(0), m_VB(0), m_Flags(0)
{
@ -17,13 +22,17 @@ CModelRData::CModelRData(CModel* model)
Build();
}
///////////////////////////////////////////////////////////////////
// CModelRData destructor
CModelRData::~CModelRData()
{
{
// clean up system copies of data
delete[] m_Indices;
delete[] m_Vertices;
delete[] m_Normals;
if (m_VB) {
glGenBuffersARB(1,(GLuint*) &m_VB);
if (m_VB) {
// release vertex buffer chunks
g_VBMan.Release(m_VB);
}
}
@ -41,22 +50,27 @@ void CModelRData::Build()
}
void CModelRData::BuildIndices()
{
CModelDef* mdef=m_Model->GetModelDef();
{
CModelDef* mdef=m_Model->GetModelDef();
assert(mdef);
// must have a valid vertex buffer by this point so we know where indices are supposed to start
assert(m_VB);
// allocate indices if we haven't got any already
if (!m_Indices) {
m_Indices=new u16[mdef->GetNumFaces()*3];
}
// build indices
u32 base=m_VB->m_Index;
u32 indices=0;
SModelFace* faces=mdef->GetFaces();
for (int j=0; j<mdef->GetNumFaces(); j++) {
SModelFace& face=faces[j];
m_Indices[indices++]=face.m_Verts[0];
m_Indices[indices++]=face.m_Verts[1];
m_Indices[indices++]=face.m_Verts[2];
m_Indices[indices++]=face.m_Verts[0]+base;
m_Indices[indices++]=face.m_Verts[1]+base;
m_Indices[indices++]=face.m_Verts[2]+base;
}
}
@ -77,30 +91,46 @@ static SColor4ub ConvertColor(const RGBColor& src)
return result;
}
static CVector3D SkinPoint(const SModelVertex& vertex,const CMatrix3D* matrices)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SkinPoint: skin the vertex position using it's blend data and given bone matrices
static void SkinPoint(const SModelVertex& vertex,const CMatrix3D* matrices,CVector3D& result)
{
CVector3D result(0,0,0),tmp;
for (u32 i=0;vertex.m_Blend.m_Bone[i]!=0xff && i<SVertexBlend::SIZE;i++) {
const CMatrix3D& m=matrices[vertex.m_Blend.m_Bone[i]];
m.Transform(vertex.m_Coords,tmp);
result+=tmp*vertex.m_Blend.m_Weight[i];
}
return result;
CVector3D tmp;
const SVertexBlend& blend=vertex.m_Blend;
// must have at least one valid bone if we're using SkinPoint
assert(blend.m_Bone[0]!=0xff);
const CMatrix3D& m=matrices[blend.m_Bone[0]];
m.Transform(vertex.m_Coords,result);
result*=blend.m_Weight[0];
for (u32 i=1;blend.m_Bone[i]!=0xff && i<SVertexBlend::SIZE;i++) {
const CMatrix3D& m=matrices[blend.m_Bone[i]];
m.Transform(vertex.m_Coords,tmp);
result+=tmp*blend.m_Weight[i];
}
}
static CVector3D SkinNormal(const SModelVertex& vertex,const CMatrix3D* invmatrices)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SkinPoint: skin the vertex normal using it's blend data and given bone matrices
static void SkinNormal(const SModelVertex& vertex,const CMatrix3D* invmatrices,CVector3D& result)
{
CVector3D result(0,0,0),tmp;
CVector3D tmp;
const SVertexBlend& blend=vertex.m_Blend;
// must have at least one valid bone if we're using SkinNormal
assert(blend.m_Bone[0]!=0xff);
const CMatrix3D& m=invmatrices[blend.m_Bone[0]];
m.RotateTransposed(vertex.m_Norm,result);
result*=blend.m_Weight[0];
for (u32 i=0;vertex.m_Blend.m_Bone[i]!=0xff && i<SVertexBlend::SIZE;i++) {
const CMatrix3D& m=invmatrices[vertex.m_Blend.m_Bone[i]];
for (u32 i=1;vertex.m_Blend.m_Bone[i]!=0xff && i<SVertexBlend::SIZE;i++) {
const CMatrix3D& m=invmatrices[blend.m_Bone[i]];
m.RotateTransposed(vertex.m_Norm,tmp);
result+=tmp*vertex.m_Blend.m_Weight[i];
result+=tmp*blend.m_Weight[i];
}
return result;
}
void CModelRData::BuildVertices()
@ -116,18 +146,21 @@ void CModelRData::BuildVertices()
// build vertices
u32 numVertices=mdef->GetNumVertices();
SModelVertex* vertices=mdef->GetVertices();
if (m_Model->GetBoneMatrices()) {
// boned model - calculate skinned vertex positions/normals
const CMatrix3D* bonematrices=m_Model->GetBoneMatrices();
if (bonematrices) {
// boned model - calculate skinned vertex positions/normals
const CMatrix3D* invbonematrices=m_Model->GetInvBoneMatrices();
for (uint j=0; j<numVertices; j++) {
m_Vertices[j].m_Position=SkinPoint(vertices[j],m_Model->GetBoneMatrices());
m_Normals[j]=SkinNormal(vertices[j],m_Model->GetInvBoneMatrices());
SkinPoint(vertices[j],bonematrices,m_Vertices[j].m_Position);
SkinNormal(vertices[j],invbonematrices,m_Normals[j]);
}
} else {
// just copy regular positions, transform normals to world space
const CMatrix3D& trans=m_Model->GetInvTransform();
const CMatrix3D& transform=m_Model->GetTransform();
const CMatrix3D& invtransform=m_Model->GetInvTransform();
for (uint j=0; j<numVertices; j++) {
m_Vertices[j].m_Position=vertices[j].m_Coords;
m_Normals[j]=trans.RotateTransposed(vertices[j].m_Norm);
transform.Transform(vertices[j].m_Coords,m_Vertices[j].m_Position);
invtransform.RotateTransposed(vertices[j].m_Norm,m_Normals[j]);
}
}
@ -137,37 +170,22 @@ void CModelRData::BuildVertices()
m_Vertices[j].m_UVs[1]=1-vertices[j].m_V;
g_Renderer.m_SHCoeffsUnits.Evaluate(m_Normals[j],m_Vertices[j].m_Color);
}
if (g_Renderer.m_Caps.m_VBO) {
if (!m_VB) {
glGenBuffersARB(1,(GLuint*) &m_VB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VB);
glBufferDataARB(GL_ARRAY_BUFFER_ARB,mdef->GetNumVertices()*sizeof(SVertex),0,mdef->GetNumBones() ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB);
}
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VB);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB,0,mdef->GetNumVertices()*sizeof(SVertex),m_Vertices);
}
// upload everything to vertex buffer - create one if necessary
if (!m_VB) {
m_VB=g_VBMan.Allocate(sizeof(SVertex),mdef->GetNumVertices(),mdef->GetNumBones() ? true : false);
}
m_VB->m_Owner->UpdateChunkVertices(m_VB,m_Vertices);
}
void CModelRData::RenderStreams(u32 streamflags,bool transparentPass)
void CModelRData::RenderStreams(u32 streamflags)
{
// ignore transparent passes if this is a transparent object
if (!transparentPass && (m_Flags & MODELRDATA_FLAG_TRANSPARENT)) {
return;
}
CModelDef* mdldef=(CModelDef*) m_Model->GetModelDef();
if (streamflags & STREAM_UV0) g_Renderer.SetTexture(0,m_Model->GetTexture());
u8* base;
if (g_Renderer.m_Caps.m_VBO) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VB);
base=0;
} else {
base=(u8*) &m_Vertices[0];
}
u8* base=m_VB->m_Owner->Bind();
// set vertex pointers
u32 stride=sizeof(SVertex);
@ -182,11 +200,7 @@ void CModelRData::RenderStreams(u32 streamflags,bool transparentPass)
// bump stats
g_Renderer.m_Stats.m_DrawCalls++;
if (transparentPass) {
g_Renderer.m_Stats.m_TransparentTris+=numFaces;
} else {
g_Renderer.m_Stats.m_ModelTris+=numFaces;
}
g_Renderer.m_Stats.m_ModelTris+=numFaces;
}
@ -251,9 +265,9 @@ float CModelRData::BackToFrontIndexSort(CMatrix3D& objToCam)
u32 indices=0;
for (i=0;i<numFaces;i++) {
SModelFace& face=faces[IndexSorter[i].first];
m_Indices[indices++]=face.m_Verts[0];
m_Indices[indices++]=face.m_Verts[1];
m_Indices[indices++]=face.m_Verts[2];
m_Indices[indices++]=face.m_Verts[0]+m_VB->m_Index;
m_Indices[indices++]=face.m_Verts[1]+m_VB->m_Index;
m_Indices[indices++]=face.m_Verts[2]+m_VB->m_Index;
}
// clear list for next call
@ -261,3 +275,88 @@ float CModelRData::BackToFrontIndexSort(CMatrix3D& objToCam)
return mindist;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// SubmitBatches: submit batches for this model to the vertex buffer
void CModelRData::SubmitBatches()
{
assert(m_VB);
m_VB->m_Owner->AppendBatch(m_VB,m_Model->GetTexture()->GetHandle(),m_Model->GetModelDef()->GetNumFaces()*3,m_Indices);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// RenderModels: render all submitted models; assumes necessary client states already enabled,
// and texture environment already setup as required
void CModelRData::RenderModels(u32 streamflags)
{
uint i;
#if 1
// submit batches for each model to the vertex buffer
for (i=0;i<m_Models.size();++i) {
CModelRData* modeldata=(CModelRData*) m_Models[i]->GetRenderData();
modeldata->SubmitBatches();
}
// step through all accumulated batches
const std::list<CVertexBuffer*>& buffers=g_VBMan.GetBufferList();
std::list<CVertexBuffer*>::const_iterator iter;
for (iter=buffers.begin();iter!=buffers.end();++iter) {
CVertexBuffer* buffer=*iter;
// any batches in this VB?
const std::vector<CVertexBuffer::Batch*>& batches=buffer->GetBatches();
if (batches.size()>0) {
u8* base=buffer->Bind();
// setup data pointers
u32 stride=sizeof(SVertex);
glVertexPointer(3,GL_FLOAT,stride,base+offsetof(SVertex,m_Position));
if (streamflags & STREAM_COLOR) glColorPointer(3,GL_FLOAT,stride,base+offsetof(SVertex,m_Color));
if (streamflags & STREAM_UV0) glTexCoordPointer(2,GL_FLOAT,stride,base+offsetof(SVertex,m_UVs[0]));
// render each batch
for (i=0;i<batches.size();++i) {
const CVertexBuffer::Batch* batch=batches[i];
if (batch->m_IndexData.size()>0) {
if (streamflags & STREAM_UV0) g_Renderer.BindTexture(0,tex_id(batch->m_Texture));
for (uint j=0;j<batch->m_IndexData.size();j++) {
glDrawElements(GL_TRIANGLES,batch->m_IndexData[j].first,GL_UNSIGNED_SHORT,batch->m_IndexData[j].second);
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_ModelTris+=batch->m_IndexData[j].first/2;
}
}
}
}
}
// everything rendered; empty out batch lists
g_VBMan.ClearBatchIndices();
#else
for (i=0;i<m_Models.size();++i) {
CModelRData* modeldata=(CModelRData*) m_Models[i]->GetRenderData();
modeldata->RenderStreams(streamflags);
}
#endif
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Submit: submit a model to render this frame
void CModelRData::Submit(CModel* model)
{
CModelRData* data=(CModelRData*) model->GetRenderData();
if (data==0) {
// no renderdata for model, create it now
data=new CModelRData(model);
model->SetRenderData(data);
} else {
data->Update();
}
if (data->GetFlags() & MODELRDATA_FLAG_TRANSPARENT) {
// add this mode to the transparency renderer for later processing - calculate
// transform matrix
g_TransparencyRenderer.Add(model);
} else {
// add to regular model list
m_Models.push_back(model);
}
}

View file

@ -18,7 +18,7 @@ public:
~CModelRData();
void Update();
void RenderStreams(u32 streamflags,bool transparentPass=false);
void RenderStreams(u32 streamflags);
// return render flags for this model
u32 GetFlags() const { return m_Flags; }
@ -26,6 +26,14 @@ public:
// sort indices of this object from back to front according to given
// object to camera space transform; return sqrd distance to centre of nearest triangle
float BackToFrontIndexSort(CMatrix3D& objToCam);
// submit a model to render this frame
static void Submit(CModel* model);
// clear per frame patch list
static void ClearSubmissions() { m_Models.clear(); }
// render all submitted models
static void RenderModels(u32 streamflags);
private:
// build this renderdata object
@ -34,6 +42,8 @@ private:
void BuildVertices();
void BuildIndices();
// submit batches for this model to the vertex buffer
void SubmitBatches();
struct SVertex {
// vertex position
@ -46,8 +56,8 @@ private:
// owner model
CModel* m_Model;
// handle to models vertex buffer
u32 m_VB;
// vertex buffer object for this model
CVertexBuffer::VBChunk* m_VB;
// model render vertices
SVertex* m_Vertices;
// transformed vertex normals - required for recalculating lighting on skinned models
@ -56,6 +66,8 @@ private:
u16* m_Indices;
// model render flags
u32 m_Flags;
// list of all submitted models
static std::vector<CModel*> m_Models;
};

View file

@ -7,6 +7,11 @@
#include "Renderer.h"
#include "PatchRData.h"
#include "AlphaMapCalculator.h"
///////////////////////////////////////////////////////////////////
// shared list of all submitted patches this frame
std::vector<CPatch*> CPatchRData::m_Patches;
const int BlendOffsets[8][2] = {
{ 0, -1 },
@ -19,18 +24,40 @@ const int BlendOffsets[8][2] = {
{ 1, -1 }
};
inline int clamp(int x,int min,int max)
{
if (x<min) return min;
else if (x>max) return max;
else return x;
}
static SColor4ub ConvertColor(const RGBColor& src)
{
SColor4ub result;
result.R=clamp(int(src.X*255),0,255);
result.G=clamp(int(src.Y*255),0,255);
result.B=clamp(int(src.Z*255),0,255);
result.A=0xff;
return result;
}
///////////////////////////////////////////////////////////////////
// CPatchRData constructor
CPatchRData::CPatchRData(CPatch* patch) : m_Patch(patch), m_Vertices(0), m_VBBase(0), m_VBBlends(0)
{
assert(patch);
Build();
}
///////////////////////////////////////////////////////////////////
// CPatchRData destructor
CPatchRData::~CPatchRData()
{
delete[] m_Vertices;
if (m_VBBase) glDeleteBuffersARB(1,(GLuint*) &m_VBBase);
if (m_VBBlends) glDeleteBuffersARB(1,(GLuint*) &m_VBBlends);
// delete copy of vertex data
delete[] m_Vertices;
// release vertex buffer chunks
if (m_VBBase) g_VBMan.Release(m_VBBase);
if (m_VBBlends) g_VBMan.Release(m_VBBlends);
}
@ -226,48 +253,48 @@ void CPatchRData::BuildBlends()
}
}
}
// now build outgoing splats
m_BlendSplats.resize(splatTextures.size());
int splatCount=0;
std::set<Handle>::iterator iter=splatTextures.begin();
for (;iter!=splatTextures.end();++iter) {
Handle tex=*iter;
SSplat& splat=m_BlendSplats[splatCount];
splat.m_IndexStart=m_BlendIndices.size();
splat.m_Texture=tex;
for (uint k=0;k<splats.size();k++) {
if (splats[k].m_Texture==tex) {
m_BlendIndices.push_back(splats[k].m_Indices[0]);
m_BlendIndices.push_back(splats[k].m_Indices[1]);
m_BlendIndices.push_back(splats[k].m_Indices[2]);
m_BlendIndices.push_back(splats[k].m_Indices[3]);
splat.m_IndexCount+=4;
}
}
splatCount++;
}
if (g_Renderer.m_Caps.m_VBO) {
if (m_VBBlends) {
// destroy old buffer
glDeleteBuffersARB(1,(GLuint*) &m_VBBlends);
} else {
// generate buffer index
glGenBuffersARB(1,(GLuint*) &m_VBBlends);
}
// create new buffer
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VBBlends);
glBufferDataARB(GL_ARRAY_BUFFER_ARB,m_BlendVertices.size()*sizeof(SBlendVertex),&m_BlendVertices[0],GL_STATIC_DRAW_ARB);
}
// build vertex data
if (m_VBBlends) {
// release existing vertex buffer chunk
g_VBMan.Release(m_VBBlends);
}
m_VBBlends=g_VBMan.Allocate(sizeof(SBlendVertex),m_BlendVertices.size(),false);
m_VBBlends->m_Owner->UpdateChunkVertices(m_VBBlends,&m_BlendVertices[0]);
// now build outgoing splats
m_BlendSplats.resize(splatTextures.size());
int splatCount=0;
u32 base=m_VBBlends->m_Index;
std::set<Handle>::iterator iter=splatTextures.begin();
for (;iter!=splatTextures.end();++iter) {
Handle tex=*iter;
SSplat& splat=m_BlendSplats[splatCount];
splat.m_IndexStart=m_BlendIndices.size();
splat.m_Texture=tex;
for (uint k=0;k<splats.size();k++) {
if (splats[k].m_Texture==tex) {
m_BlendIndices.push_back(splats[k].m_Indices[0]+base);
m_BlendIndices.push_back(splats[k].m_Indices[1]+base);
m_BlendIndices.push_back(splats[k].m_Indices[2]+base);
m_BlendIndices.push_back(splats[k].m_Indices[3]+base);
splat.m_IndexCount+=4;
}
}
splatCount++;
}
}
void CPatchRData::BuildIndices()
{
{
// must have allocated some vertices before trying to build corresponding indices
assert(m_VBBase);
// number of vertices in each direction in each patch
int vsize=PATCH_SIZE+1;
@ -290,7 +317,8 @@ void CPatchRData::BuildIndices()
// now build base splats from interior textures
m_Splats.resize(textures.size());
// build indices for base splats
u32 base=m_VBBase->m_Index;
for (uint i=0;i<m_Splats.size();i++) {
Handle h=textures[i];
@ -301,66 +329,33 @@ void CPatchRData::BuildIndices()
for (int j=0;j<PATCH_SIZE;j++) {
for (int i=0;i<PATCH_SIZE;i++) {
if (texgrid[j][i]==h){
m_Indices.push_back(((j+0)*vsize+(i+0)));
m_Indices.push_back(((j+0)*vsize+(i+1)));
m_Indices.push_back(((j+1)*vsize+(i+1)));
m_Indices.push_back(((j+1)*vsize+(i+0)));
m_Indices.push_back(((j+0)*vsize+(i+0))+base);
m_Indices.push_back(((j+0)*vsize+(i+1))+base);
m_Indices.push_back(((j+1)*vsize+(i+1))+base);
m_Indices.push_back(((j+1)*vsize+(i+0))+base);
}
}
}
splat.m_IndexCount=m_Indices.size()-splat.m_IndexStart;
}
}
// build indices for the shadow map pass
for (int j=0;j<PATCH_SIZE;j++) {
for (int i=0;i<PATCH_SIZE;i++) {
m_ShadowMapIndices.push_back(((j+0)*vsize+(i+0))+base);
m_ShadowMapIndices.push_back(((j+0)*vsize+(i+1))+base);
m_ShadowMapIndices.push_back(((j+1)*vsize+(i+1))+base);
m_ShadowMapIndices.push_back(((j+1)*vsize+(i+0))+base);
}
}
}
inline int clamp(int x,int min,int max)
{
if (x<min) return min;
else if (x>max) return max;
else return x;
}
static SColor4ub ConvertColor(const RGBColor& src)
{
SColor4ub result;
result.R=clamp(int(src.X*255),0,255);
result.G=clamp(int(src.Y*255),0,255);
result.B=clamp(int(src.Z*255),0,255);
result.A=0xff;
return result;
}
static void BuildHeightmapNormals(int size,u16 *heightmap,CVector3D* normals)
{
int x, y;
int sm=size-1;
for(y = 0;y < size; y++)
for(x = 0; x < size; x++) {
// Access current normalmap grid point
CVector3D* N = &normals[y*size+x];
// Compute normal by using the height differential
u16 h1=(x==sm) ? heightmap[y*size+x] : heightmap[y*size+x+1];
u16 h2=(y==sm) ? heightmap[y*size+x] : heightmap[(y+1)*size+x];
u16 h3=(x==0) ? heightmap[y*size+x] : heightmap[y*size+x-1];
u16 h4=(y==0) ? heightmap[y*size+x] : heightmap[(y-1)*size+x+1];
N->X = (h3-h1)*HEIGHT_SCALE;
N->Y = CELL_SIZE;
N->Z = (h4-h2)*HEIGHT_SCALE;
// Normalize it
float len=N->GetLength();
if (len>0) {
(*N)*=1.0f/len;
} else {
*N=CVector3D(0,0,0);
}
}
}
void CPatchRData::BuildVertices()
{
CVector3D normal;
RGBColor c;
// number of vertices in each direction in each patch
int vsize=PATCH_SIZE+1;
@ -377,38 +372,26 @@ void CPatchRData::BuildVertices()
CTerrain* terrain=m_Patch->m_Parent;
u32 mapSize=terrain->GetVerticesPerSide();
// build vertices
for (int j=0; j<vsize; j++)
{
for (int i=0; i<vsize; i++)
{
int ix=px*16+i;
int iz=pz*16+j;
// build vertices
for (int j=0;j<vsize;j++) {
for (int i=0;i<vsize;i++) {
int ix=px*PATCH_SIZE+i;
int iz=pz*PATCH_SIZE+j;
int v=(j*vsize)+i;
CVector3D pos,normal;
terrain->CalcPosition(ix,iz,pos);
terrain->CalcNormal(ix,iz,normal);
RGBColor c;
g_Renderer.m_SHCoeffsTerrain.Evaluate(normal,c);
int v=(j*vsize)+i;
terrain->CalcPosition(ix,iz,vertices[v].m_Position);
terrain->CalcNormal(ix,iz,normal);
g_Renderer.m_SHCoeffsTerrain.Evaluate(normal,c);
vertices[v].m_Color=ConvertColor(c);
vertices[v].m_UVs[0]=i*0.125f;
vertices[v].m_UVs[1]=j*0.125f;
vertices[v].m_Color=ConvertColor(c);
vertices[v].m_Position=pos;
}
}
if (g_Renderer.m_Caps.m_VBO) {
if (!m_VBBase) {
glGenBuffersARB(1,(GLuint*) &m_VBBase);
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VBBase);
glBufferDataARB(GL_ARRAY_BUFFER_ARB,vsize*vsize*sizeof(SBaseVertex),0,GL_STATIC_DRAW_ARB);
}
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VBBase);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB,0,vsize*vsize*sizeof(SBaseVertex),m_Vertices);
}
if (!m_VBBase) {
m_VBBase=g_VBMan.Allocate(sizeof(SBaseVertex),vsize*vsize,false);
}
m_VBBase->m_Owner->UpdateChunkVertices(m_VBBase,m_Vertices);
}
void CPatchRData::Build()
@ -436,13 +419,7 @@ void CPatchRData::RenderBase()
{
assert(m_UpdateFlags==0);
u8* base;
if (g_Renderer.m_Caps.m_VBO) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VBBase);
base=0;
} else {
base=(u8*) &m_Vertices[0];
}
u8* base=m_VBBase->m_Owner->Bind();
// setup data pointers
u32 stride=sizeof(SBaseVertex);
@ -465,13 +442,7 @@ void CPatchRData::RenderStreams(u32 streamflags)
{
assert(m_UpdateFlags==0);
u8* base;
if (g_Renderer.m_Caps.m_VBO) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VBBase);
base=0;
} else {
base=(u8*) &m_Vertices[0];
}
u8* base=m_VBBase->m_Owner->Bind();
// setup data pointers
glVertexPointer(3,GL_FLOAT,sizeof(SBaseVertex),base+offsetof(SBaseVertex,m_Position));
@ -493,14 +464,7 @@ void CPatchRData::RenderBlends()
if (m_BlendVertices.size()==0) return;
u8* base;
if (g_Renderer.m_Caps.m_VBO) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VBBlends);
base=0;
} else {
base=(u8*) &m_BlendVertices[0];
}
u8* base=m_VBBlends->m_Owner->Bind();
// setup data pointers
u32 stride=sizeof(SBlendVertex);
@ -527,6 +491,7 @@ void CPatchRData::RenderBlends()
void CPatchRData::RenderOutline()
{
// TODO, RC - fixme, only works for PATCH_SIZE = 16
const u16 EdgeIndices[PATCH_SIZE*4] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
33, 50, 67, 84, 101, 118, 135, 152, 169, 186, 203, 220, 237, 254, 271, 288,
@ -534,13 +499,7 @@ void CPatchRData::RenderOutline()
255, 238, 221, 204, 187, 170, 153, 136, 119, 102, 85, 68, 51, 34, 17, 0
};
u8* base;
if (g_Renderer.m_Caps.m_VBO) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VBBase);
base=0;
} else {
base=(u8*) &m_Vertices[0];
}
u8* base=m_VBBase->m_Owner->Bind();
// setup data pointers
glVertexPointer(3,GL_FLOAT,sizeof(SBaseVertex),base+offsetof(SBaseVertex,m_Position));
@ -551,3 +510,298 @@ void CPatchRData::RenderOutline()
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_TerrainTris+=numIndices/2;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// SubmitBaseBatches: submit base batches for this patch to the vertex buffer
void CPatchRData::SubmitBaseBatches()
{
assert(m_VBBase);
for (uint i=0;i<m_Splats.size();i++) {
const SSplat& splat=m_Splats[i];
m_VBBase->m_Owner->AppendBatch(m_VBBase,splat.m_Texture,splat.m_IndexCount,&m_Indices[splat.m_IndexStart]);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// SubmitBlendBatches: submit next set of blend batches for this patch to the vertex buffer;
// return true if all blends on this patch have been submitted, else false
bool CPatchRData::SubmitBlendBatches()
{
if (m_NextBlendSplat<m_BlendSplats.size()) {
for (uint i=m_NextBlendSplat;i<m_BlendSplats.size();i++) {
const SSplat& splat=m_BlendSplats[i];
m_VBBlends->m_Owner->AppendBatch(m_VBBlends,splat.m_Texture,splat.m_IndexCount,&m_BlendIndices[splat.m_IndexStart]);
}
return true;
}
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// RenderBaseSplats: render all base passes of all patches; assumes vertex, texture and color
// client states are enabled
void CPatchRData::RenderBaseSplats()
{
uint i;
// set up texture environment for base pass
glActiveTexture(GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_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);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_ZERO);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA);
#if 1
// submit base batches for each patch to the vertex buffer
for (i=0;i<m_Patches.size();++i) {
CPatchRData* patchdata=(CPatchRData*) m_Patches[i]->GetRenderData();
patchdata->SubmitBaseBatches();
}
// render base passes for each patch
const std::list<CVertexBuffer*>& buffers=g_VBMan.GetBufferList();
std::list<CVertexBuffer*>::const_iterator iter;
for (iter=buffers.begin();iter!=buffers.end();++iter) {
CVertexBuffer* buffer=*iter;
// any batches in this VB?
const std::vector<CVertexBuffer::Batch*>& batches=buffer->GetBatches();
if (batches.size()>0) {
u8* base=buffer->Bind();
// setup data pointers
u32 stride=sizeof(SBaseVertex);
glVertexPointer(3,GL_FLOAT,stride,base+offsetof(SBaseVertex,m_Position));
glColorPointer(4,GL_UNSIGNED_BYTE,stride,base+offsetof(SBaseVertex,m_Color));
glTexCoordPointer(2,GL_FLOAT,stride,base+offsetof(SBaseVertex,m_UVs[0]));
// render each batch
for (i=0;i<batches.size();++i) {
const CVertexBuffer::Batch* batch=batches[i];
if (batch->m_IndexData.size()>0) {
g_Renderer.BindTexture(0,tex_id(batch->m_Texture));
for (uint j=0;j<batch->m_IndexData.size();j++) {
glDrawElements(GL_QUADS,batch->m_IndexData[j].first,GL_UNSIGNED_SHORT,batch->m_IndexData[j].second);
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_TerrainTris+=batch->m_IndexData[j].first/2;
}
}
}
}
}
// everything rendered; empty out batch lists
g_VBMan.ClearBatchIndices();
#else
for (i=0;i<m_Patches.size();++i) {
CPatchRData* patchdata=(CPatchRData*) m_Patches[i]->GetRenderData();
patchdata->RenderBase();
}
#endif
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// RenderBlendSplats: render all blend passes of all patches; assumes vertex, texture and color
// client states are enabled
void CPatchRData::RenderBlendSplats()
{
uint i;
// switch on second uv set
glClientActiveTexture(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTexture(GL_TEXTURE0);
// switch on the composite alpha map texture
g_Renderer.BindTexture(1,g_Renderer.m_CompositeAlphaMap);
// setup additional texenv required by blend pass
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_ONE_MINUS_SRC_ALPHA);
// switch on blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
// no need to write to the depth buffer a second time
glDepthMask(0);
#if 1
// submit blend batches for each patch to the vertex buffer
for (i=0;i<m_Patches.size();++i) {
CPatchRData* patchdata=(CPatchRData*) m_Patches[i]->GetRenderData();
patchdata->SetupBlendBatches();
}
bool finished=true;
do
{
for (i=0;i<m_Patches.size();++i) {
CPatchRData* patchdata=(CPatchRData*) m_Patches[i]->GetRenderData();
if (!patchdata->SubmitBlendBatches()) finished=false;
}
} while (!finished);
// render blend passes for each patch
const std::list<CVertexBuffer*>& buffers=g_VBMan.GetBufferList();
std::list<CVertexBuffer*>::const_iterator iter;
for (iter=buffers.begin();iter!=buffers.end();++iter) {
CVertexBuffer* buffer=*iter;
// any batches in this VB?
const std::vector<CVertexBuffer::Batch*>& batches=buffer->GetBatches();
if (batches.size()>0) {
u8* base=buffer->Bind();
// setup data pointers
u32 stride=sizeof(SBlendVertex);
glVertexPointer(3,GL_FLOAT,stride,base+offsetof(SBlendVertex,m_Position));
glColorPointer(4,GL_UNSIGNED_BYTE,stride,base+offsetof(SBlendVertex,m_Color));
glClientActiveTexture(GL_TEXTURE0);
glTexCoordPointer(2,GL_FLOAT,stride,base+offsetof(SBlendVertex,m_UVs[0]));
glClientActiveTexture(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2,GL_FLOAT,stride,base+offsetof(SBlendVertex,m_AlphaUVs[0]));
// render each batch
for (i=0;i<batches.size();++i) {
const CVertexBuffer::Batch* batch=batches[i];
if (batch->m_IndexData.size()>0) {
g_Renderer.BindTexture(0,tex_id(batch->m_Texture));
for (uint j=0;j<batch->m_IndexData.size();j++) {
glDrawElements(GL_QUADS,batch->m_IndexData[j].first,GL_UNSIGNED_SHORT,batch->m_IndexData[j].second);
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_TerrainTris+=batch->m_IndexData[j].first/2;
}
}
}
}
}
// everything rendered; empty out batch lists
g_VBMan.ClearBatchIndices();
#else
// render blend passes for each patch
for (i=0;i<m_TerrainPatches.size();++i) {
CPatchRData* patchdata=(CPatchRData*) m_Patches[i]->GetRenderData();
patchdata->RenderBlends();
}
#endif
// restore depth writes
glDepthMask(1);
// restore default state: switch off blending
glDisable(GL_BLEND);
// switch off texture unit 1, make unit 0 active texture
g_Renderer.BindTexture(1,0);
glActiveTexture(GL_TEXTURE0);
// tidy up client states
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTexture(GL_TEXTURE0_ARB);
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Submit: submit a patch to render this frame
void CPatchRData::Submit(CPatch* patch)
{
CPatchRData* data=(CPatchRData*) patch->GetRenderData();
if (data==0) {
// no renderdata for patch, create it now
data=new CPatchRData(patch);
patch->SetRenderData(data);
} else {
data->Update();
}
m_Patches.push_back(patch);
}
/////////////////////////////////////////////////////////////////////////////////////////////
// ApplyShadowMap: apply given shadow map to all terrain patches; assume the texture matrix
// has been correctly setup on unit 1 to handle the projection
void CPatchRData::ApplyShadowMap(GLuint shadowmaphandle)
{
uint i;
// glEnable(GL_ALPHA_TEST);
// glAlphaFunc(GL_GREATER,0.0f);
g_Renderer.BindTexture(0,shadowmaphandle);
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_TEXTURE);
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);
glColor3f(1,1,1);
glEnable(GL_BLEND);
glBlendFunc(GL_DST_COLOR,GL_ZERO);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
#if 1
// submit base batches for each patch to the vertex buffer
for (i=0;i<m_Patches.size();++i) {
CPatchRData* patchdata=(CPatchRData*) m_Patches[i]->GetRenderData();
patchdata->m_VBBase->m_Owner->AppendBatch(patchdata->m_VBBase,0,patchdata->m_ShadowMapIndices.size(),
&patchdata->m_ShadowMapIndices[0]);
}
// render base passes for each patch
const std::list<CVertexBuffer*>& buffers=g_VBMan.GetBufferList();
std::list<CVertexBuffer*>::const_iterator iter;
for (iter=buffers.begin();iter!=buffers.end();++iter) {
CVertexBuffer* buffer=*iter;
// any batches in this VB?
const std::vector<CVertexBuffer::Batch*>& batches=buffer->GetBatches();
if (batches.size()>0) {
u8* base=buffer->Bind();
// setup data pointers
u32 stride=sizeof(SBaseVertex);
glVertexPointer(3,GL_FLOAT,stride,base+offsetof(SBaseVertex,m_Position));
glColorPointer(4,GL_UNSIGNED_BYTE,stride,base+offsetof(SBaseVertex,m_Color));
glTexCoordPointer(3,GL_FLOAT,sizeof(SBaseVertex),base+offsetof(SBaseVertex,m_Position));
// render batch (can only be one per buffer, since all batches are flagged as using a null texture)
const CVertexBuffer::Batch* batch=batches[0];
for (uint j=0;j<batch->m_IndexData.size();j++) {
glDrawElements(GL_QUADS,batch->m_IndexData[j].first,GL_UNSIGNED_SHORT,batch->m_IndexData[j].second);
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_TerrainTris+=batch->m_IndexData[j].first/2;
}
}
}
// everything rendered; empty out batch lists
g_VBMan.ClearBatchIndices();
#else
for (uint i=0;i<m_Patches.size();++i) {
CPatchRData* patchdata=(CPatchRData*) m_Patches[i]->GetRenderData();;
patchdata->RenderStreams(STREAM_POS|STREAM_POSTOUV0);
}
#endif
glDisable(GL_ALPHA_TEST);
glDisable(GL_BLEND);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}

View file

@ -6,9 +6,13 @@
#include "Color.h"
#include "Vector3D.h"
#include "RenderableObject.h"
#include "VertexBufferManager.h"
class CPatch;
//////////////////////////////////////////////////////////////////////////////////////////////////
// CPatchRData: class encapsulating logic for rendering terrain patches; holds per
// patch data, plus some supporting static functions for batching, etc
class CPatchRData : public CRenderData
{
public:
@ -20,8 +24,68 @@ public:
void RenderBlends();
void RenderOutline();
void RenderStreams(u32 streamflags);
// submit a patch to render this frame
static void Submit(CPatch* patch);
// clear per frame patch list
static void ClearSubmissions() { m_Patches.clear(); }
// render the base pass of all patches
static void RenderBaseSplats();
// render the blend pass of all patches
static void RenderBlendSplats();
// apply given shadow map to all terrain patches
static void ApplyShadowMap(GLuint handle);
// submit base batches for this patch to the vertex buffer
void SubmitBaseBatches();
// submit next set of blend batches for this patch to the vertex buffer;
// return true if all blends on this patch have been submitted, else false
bool SubmitBlendBatches();
// perform necessary initialisation prior to rendering blend splats
void SetupBlendBatches() { m_NextBlendSplat=0; }
private:
struct SSplat {
SSplat() : m_Texture(0), m_IndexCount(0) {}
// handle of texture to apply during splat
Handle m_Texture;
// offset into the index array for this patch where splat starts
u32 m_IndexStart;
// number of indices used by splat
u32 m_IndexCount;
};
struct SBaseVertex {
// vertex position
CVector3D m_Position;
// vertex color
SColor4ub m_Color;
// vertex uvs for base texture
float m_UVs[2];
};
struct SBlendVertex {
// vertex position
CVector3D m_Position;
// vertex color
SColor4ub m_Color;
// vertex uvs for base texture
float m_UVs[2];
// vertex uvs for alpha texture
float m_AlphaUVs[2];
};
struct STex {
bool operator==(const STex& rhs) const { return m_Handle==rhs.m_Handle; }
bool operator<(const STex& rhs) const { return m_Priority<rhs.m_Priority; }
Handle m_Handle;
int m_Priority;
};
// build this renderdata object
void Build();
@ -29,54 +93,18 @@ private:
void BuildIndices();
void BuildVertices();
struct SSplat {
SSplat() : m_Texture(0), m_IndexCount(0) {}
// handle of texture to apply during splat
Handle m_Texture;
// offset into the index array for this patch where splat starts
u32 m_IndexStart;
// number of indices used by splat
u32 m_IndexCount;
};
struct SBaseVertex {
// vertex position
CVector3D m_Position;
// vertex color
SColor4ub m_Color;
// vertex uvs for base texture
float m_UVs[2];
};
struct SBlendVertex {
// vertex position
CVector3D m_Position;
// vertex color
SColor4ub m_Color;
// vertex uvs for base texture
float m_UVs[2];
// vertex uvs for alpha texture
float m_AlphaUVs[2];
};
struct STex {
bool operator==(const STex& rhs) const { return m_Handle==rhs.m_Handle; }
bool operator<(const STex& rhs) const { return m_Priority<rhs.m_Priority; }
Handle m_Handle;
int m_Priority;
};
// owner patch
CPatch* m_Patch;
// vertex buffer handle for base vertices
u32 m_VBBase;
CVertexBuffer::VBChunk* m_VBBase;
// vertex buffer handle for blend vertices
u32 m_VBBlends;
CVertexBuffer::VBChunk* m_VBBlends;
// patch render vertices
SBaseVertex* m_Vertices;
// patch index list
// indices into base vertices for the base splats
std::vector<unsigned short> m_Indices;
// indices into base vertices for the shadow map pass
std::vector<unsigned short> m_ShadowMapIndices;
// list of base splats to apply to this patch
std::vector<SSplat> m_Splats;
// vertices to use for blending transition texture passes
@ -84,7 +112,11 @@ private:
// indices into blend vertices for the blend splats
std::vector<unsigned short> m_BlendIndices;
// splats used in blend pass
std::vector<SSplat> m_BlendSplats;
std::vector<SSplat> m_BlendSplats;
// index of the next blend splat to render
u32 m_NextBlendSplat;
// list of all submitted patches
static std::vector<CPatch*> m_Patches;
};

File diff suppressed because it is too large Load diff

View file

@ -95,7 +95,6 @@ public:
m_DrawCalls+=rhs.m_DrawCalls;
m_TerrainTris+=rhs.m_TerrainTris;
m_ModelTris+=rhs.m_ModelTris;
m_TransparentTris+=rhs.m_TransparentTris;
m_BlendSplats+=rhs.m_BlendSplats;
return *this;
}
@ -107,8 +106,6 @@ public:
u32 m_TerrainTris;
// number of (non-transparent) model triangles drawn
u32 m_ModelTris;
// number of transparent model triangles drawn
u32 m_TransparentTris;
// number of splat passes for alphamapping
u32 m_BlendSplats;
};
@ -129,9 +126,9 @@ public:
// set/get boolean renderer option
void SetOptionBool(enum Option opt,bool value);
bool GetOptionBool(enum Option opt) const;
// set/get color renderer option
void SetOptionColor(enum Option opt,const RGBColor& value);
const RGBColor& GetOptionColor(enum Option opt) const;
// set/get RGBA color renderer option
void SetOptionColor(enum Option opt,const RGBAColor& value);
const RGBAColor& GetOptionColor(enum Option opt) const;
// return view width
int GetWidth() const { return m_Width; }
@ -197,9 +194,10 @@ public:
// try and load the given texture
bool LoadTexture(CTexture* texture,u32 wrapflags);
// set the given unit to reference the given texture; pass a null texture to disable texturing on any unit
// set the given unit to reference the given texture; pass a null texture to disable texturing on any unit;
// active texture unit always set to given unit on exit
void SetTexture(int unit,CTexture* texture);
// BindTexture: bind a GL texture object to given unit
// bind a GL texture object to active unit
void BindTexture(int unit,GLuint tex);
// query transparency of given texture
bool IsTextureTransparent(CTexture* texture);
@ -211,12 +209,11 @@ public:
const Stats& GetStats() { return m_Stats; }
protected:
friend class CVertexBuffer;
friend class CPatchRData;
friend class CModelRData;
friend class CTransparencyRenderer;
// recurse down given model building renderdata for it and all it's children
void UpdateModelDataRecursive(CModel* model);
// update renderdata of everything submitted
void UpdateSubmittedObjectData();
@ -225,17 +222,14 @@ protected:
void RenderPatches();
// model rendering stuff
void BuildTransparentPasses(CModel* model);
void RenderModelSubmissions();
void RenderModelsRecursive(CModel* model,u32 streamflags);
void RenderModelsStreams(u32 streamflags);
void RenderModels();
// shadow rendering stuff
void CreateShadowMap();
void RenderShadowMap();
void ApplyShadowMap();
void CRenderer::BuildTransformation(const CVector3D& pos,const CVector3D& right,const CVector3D& up,
void BuildTransformation(const CVector3D& pos,const CVector3D& right,const CVector3D& up,
const CVector3D& dir,CMatrix3D& result);
void ConstructLightTransform(const CVector3D& pos,const CVector3D& lightdir,CMatrix3D& result);
void CalcShadowMatrices();
@ -259,8 +253,6 @@ protected:
// color used to clear screen in BeginFrame
float m_ClearColor[4];
// submitted object lists for batching
std::vector<CPatch*> m_TerrainPatches;
std::vector<CModel*> m_Models;
std::vector<CSprite*> m_Sprites;
std::vector<CParticleSys*> m_ParticleSyses;
std::vector<COverlay*> m_Overlays;
@ -274,8 +266,10 @@ protected:
u32 m_CompositeAlphaMap;
// handle of shadow map
u32 m_ShadowMap;
// size of each side of shadow map
u32 m_ShadowMapSize;
// width, height of shadow map
u32 m_ShadowMapWidth,m_ShadowMapHeight;
// object space bound of shadow casting objects
CBound m_ShadowBound;
// per-frame flag: has the shadow map been rendered this frame?
bool m_ShadowRendered;
// projection matrix of shadow casting light
@ -290,20 +284,18 @@ protected:
struct Caps {
bool m_VBO;
bool m_TextureBorderClamp;
bool m_PBuffer;
bool m_GenerateMipmaps;
} m_Caps;
// renderer options
struct Options {
bool m_NoVBO;
bool m_NoPBuffer;
bool m_Shadows;
RGBColor m_ShadowColor;
RGBAColor m_ShadowColor;
} m_Options;
// build card cap bits
void EnumCaps();
// per-frame renderer stats
Stats m_Stats;
Stats m_Stats;
// active textures on each unit
GLuint m_ActiveTextures[MaxTextureUnits];
};

View file

@ -1,3 +1,11 @@
///////////////////////////////////////////////////////////////////////////////
//
// Name: TransparencyRenderer.cpp
// Author: Rich Cross
// Contact: rich@wildfiregames.com
//
///////////////////////////////////////////////////////////////////////////////
#include "precompiled.h"
#include <algorithm>
@ -30,7 +38,9 @@ void CTransparencyRenderer::Sort()
// Render: render all deferred passes; call Sort before using to ensure passes
// are drawn in correct order
void CTransparencyRenderer::Render()
{
{
if (m_Objects.size()==0) return;
// switch on wireframe if we need it
if (g_Renderer.m_ModelRenderMode==WIREFRAME) {
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
@ -41,13 +51,10 @@ void CTransparencyRenderer::Render()
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// setup texture environment to modulate diffuse color with texture color
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_ONE);
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);
// just pass through texture's alpha
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
@ -56,14 +63,24 @@ void CTransparencyRenderer::Render()
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER,0.975f);
RenderObjectsStreams(STREAM_POS|STREAM_COLOR|STREAM_UV0);
// render everything with color writes off to setup depth buffer correctly
glColorMask(0,0,0,0);
RenderObjectsStreams(STREAM_POS|STREAM_UV0);
glColorMask(1,1,1,1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(0);
glAlphaFunc(GL_LEQUAL,0.975f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glAlphaFunc(GL_GREATER,0);
// 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);
RenderObjectsStreams(STREAM_POS|STREAM_COLOR|STREAM_UV0);
@ -138,11 +155,9 @@ void CTransparencyRenderer::Add(CModel* model)
void CTransparencyRenderer::RenderShadows()
{
// coarsely sort submitted objects in back to front manner
std::sort(m_Objects.begin(),m_Objects.end(),SortObjectsByDist());
if (m_Objects.size()==0) return;
// switch on client states
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glDepthMask(0);
@ -152,20 +167,18 @@ void CTransparencyRenderer::RenderShadows()
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_ARB);
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);
RenderObjectsStreams(STREAM_POS|STREAM_UV0);
glDisable(GL_ALPHA_TEST);
glDepthMask(1);
glDisable(GL_BLEND);
// switch off client states
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
@ -174,14 +187,7 @@ void CTransparencyRenderer::RenderShadows()
void CTransparencyRenderer::RenderObjectsStreams(u32 streamflags)
{
for (uint i=0;i<m_Objects.size();++i) {
CModel* model=m_Objects[i].m_Model;
glPushMatrix();
glMultMatrixf(&model->GetTransform()._11);
CModelRData* modeldata=(CModelRData*) model->GetRenderData();
modeldata->RenderStreams(streamflags,true);
glPopMatrix();
CModelRData* modeldata=(CModelRData*) m_Objects[i].m_Model->GetRenderData();
modeldata->RenderStreams(streamflags);
}
}

View file

@ -1,3 +1,11 @@
///////////////////////////////////////////////////////////////////////////////
//
// Name: TransparencyRenderer.h
// Author: Rich Cross
// Contact: rich@wildfiregames.com
//
///////////////////////////////////////////////////////////////////////////////
#ifndef __TRANSPARENCYRENDERER_H
#define __TRANSPARENCYRENDERER_H