From d4ca9695d7dfda0b73d3580f1f341c224a177bc6 Mon Sep 17 00:00:00 2001 From: olsner Date: Tue, 13 Apr 2004 16:54:34 +0000 Subject: [PATCH] Changed terrain stuff from ScEd 0.0.5.2 This was SVN commit r203. --- source/terrain/Bound.cpp | 25 + source/terrain/Bound.h | 3 + source/terrain/Camera.cpp | 12 +- source/terrain/Camera.h | 2 +- source/terrain/MathUtil.h | 3 +- source/terrain/Matrix3D.cpp | 43 +- source/terrain/Matrix3D.h | 2 +- source/terrain/MiniPatch.cpp | 19 +- source/terrain/MiniPatch.h | 40 +- source/terrain/Model.cpp | 18 + source/terrain/Model.h | 10 +- source/terrain/ModelDef.cpp | 17 +- source/terrain/ModelDef.h | 2 +- source/terrain/Patch.cpp | 47 +- source/terrain/Patch.h | 33 +- source/terrain/PatchRData.cpp | 4 +- source/terrain/Renderer.cpp | 833 ++++++++++++++++++------------ source/terrain/Renderer.h | 118 ++++- source/terrain/SHCoeffs.cpp | 7 +- source/terrain/SHCoeffs.h | 4 +- source/terrain/TerrGlobals.h | 15 +- source/terrain/Terrain.cpp | 349 ++++++++----- source/terrain/Terrain.h | 62 ++- source/terrain/TextureManager.cpp | 6 +- source/terrain/Types.h | 2 +- source/terrain/terrainMain.cpp | 217 ++++---- 26 files changed, 1159 insertions(+), 734 deletions(-) diff --git a/source/terrain/Bound.cpp b/source/terrain/Bound.cpp index aba1b64336..4bc2f96166 100755 --- a/source/terrain/Bound.cpp +++ b/source/terrain/Bound.cpp @@ -10,6 +10,7 @@ //----------------------------------------------------------- // necessary includes +#include #include #include "Bound.h" @@ -138,3 +139,27 @@ void CBound::SetEmpty() } +void CBound::Transform(const CMatrix3D& m,CBound& result) const +{ + assert(this!=&result); + + for (int i=0;i<3;++i) { + // handle translation + result[0][i]=result[1][i]=m(3,i); + + // Now find the extreme points by considering the product of the + // min and max with each component of matrix + for(int j=0;j<3;j++) { + float a=m(i,j)*m_Data[0][j]; + float b=m(i,j)*m_Data[1][j]; + + if (a 0) ? (a) : (-a)) diff --git a/source/terrain/Matrix3D.cpp b/source/terrain/Matrix3D.cpp index 784430c0b8..95bcbe82b7 100755 --- a/source/terrain/Matrix3D.cpp +++ b/source/terrain/Matrix3D.cpp @@ -277,36 +277,27 @@ void CMatrix3D::Scale (float x_scale, float y_scale, float z_scale) //Returns the transpose of the matrix. For orthonormal //matrices, this is the same is the inverse matrix -CMatrix3D CMatrix3D::GetTranspose() const +void CMatrix3D::GetTranspose(CMatrix3D& result) const { - CMatrix3D Temp; + result._11 = _11; + result._21 = _12; + result._31 = _13; + result._41 = _14; - Temp._11 = _11; - Temp._21 = _12; - Temp._31 = _13; - Temp._41 = 0.0f; + result._12 = _21; + result._22 = _22; + result._32 = _23; + result._42 = _24; - Temp._12 = _21; - Temp._22 = _22; - Temp._32 = _23; - Temp._42 = 0.0f; + result._13 = _31; + result._23 = _32; + result._33 = _33; + result._43 = _34; - Temp._13 = _31; - Temp._23 = _32; - Temp._33 = _33; - Temp._43 = 0.0f; - - Temp._14 = 0.0f; - Temp._24 = 0.0f; - Temp._34 = 0.0f; - Temp._44 = 1.0f; - - CMatrix3D Trans; - Trans.SetTranslation (-_14, -_24, -_34); - - Temp = Temp * Trans; - - return Temp; + result._14 = _41; + result._24 = _42; + result._34 = _43; + result._44 = _44; } //Get a vector which points to the left of the matrix diff --git a/source/terrain/Matrix3D.h b/source/terrain/Matrix3D.h index 6ceb380e93..9921496589 100755 --- a/source/terrain/Matrix3D.h +++ b/source/terrain/Matrix3D.h @@ -84,7 +84,7 @@ class CMatrix3D //Returns the transpose of the matrix. For orthonormal //matrices, this is the same is the inverse matrix - CMatrix3D GetTranspose() const; + void GetTranspose(CMatrix3D& result) const; //Get a vector which points to the left of the matrix CVector3D GetLeft () const; diff --git a/source/terrain/MiniPatch.cpp b/source/terrain/MiniPatch.cpp index 1d39f7ad9d..23d92788b3 100755 --- a/source/terrain/MiniPatch.cpp +++ b/source/terrain/MiniPatch.cpp @@ -1,22 +1,21 @@ #include "MiniPatch.h" +#include "Patch.h" CMiniPatch::CMiniPatch() { - Tex1 = Tex2 = 0; - m_AlphaMap = 0; - m_pRightNeighbor = NULL; - m_pParrent = NULL; - m_Rotation = 0; - m_RenderStage = 0; - m_LastRenderedFrame = 0; + Tex1 = 0; + Tex1Priority = 0; + m_Parent = NULL; } CMiniPatch::~CMiniPatch() { } -void CMiniPatch::Initialize (STerrainVertex *first_vertex) +void CMiniPatch::GetTileIndex(u32& x,u32& z) { - m_pVertices = first_vertex; + u32 tindex=this-&m_Parent->m_MiniPatches[0][0]; + x=(m_Parent->m_X*16)+tindex%16; + z=(m_Parent->m_Z*16)+tindex/16; +} -} \ No newline at end of file diff --git a/source/terrain/MiniPatch.h b/source/terrain/MiniPatch.h index 940aa206cf..a762ba7759 100755 --- a/source/terrain/MiniPatch.h +++ b/source/terrain/MiniPatch.h @@ -2,36 +2,28 @@ #define MINIPATCH_H #include "res/res.h" -#include "Color.h" -#include "Vector3D.h" - -struct STerrainVertex -{ - CVector3D m_Position; - CVector3D m_Normal; - RGBColor m_Color; -}; +class CPatch; class CMiniPatch { - public: - CMiniPatch(); - ~CMiniPatch(); +public: + CMiniPatch(); + ~CMiniPatch(); - void Initialize (STerrainVertex *first_vertex); + // get the index of this tile in the root terrain object; x,y in [0,MapSize) + void GetTileIndex(u32& x,u32& z); + + Handle Tex1; + int Tex1Priority; + +// Handle Tex2; +// Handle m_AlphaMap; +// unsigned int m_AlphaMapFlags; -Handle Tex1, Tex2; -Handle m_AlphaMap; - CMiniPatch *m_pRightNeighbor; - CPatch *m_pParrent; - unsigned char m_RenderStage; - unsigned int m_LastRenderedFrame; - - unsigned char m_Rotation; - - STerrainVertex *m_pVertices; + CPatch *m_Parent; +// STerrainVertex *m_pVertices; }; -#endif \ No newline at end of file +#endif diff --git a/source/terrain/Model.cpp b/source/terrain/Model.cpp index 22441861ce..db233d4a8f 100755 --- a/source/terrain/Model.cpp +++ b/source/terrain/Model.cpp @@ -11,11 +11,13 @@ #include "Model.h" #include "Quaternion.h" +#include "Bound.h" CModel::CModel() { m_pModelDef = NULL; m_pBonePoses = NULL; + m_RenderData = 0; } CModel::~CModel() @@ -126,3 +128,19 @@ void RotateX (CMatrix3D *mat, float angle1, float angle2, float factor) *mat = RotX * (*mat); } + +void CModel::CalcBounds(CBound& bound) +{ + bound.SetEmpty(); + + for (int i=0; iGetNumVertices(); i++) + { + SModelVertex *pVertex = &m_pModelDef->GetVertices()[i]; + CVector3D coord; + if (pVertex->m_Bone!=-1) { + bound+=GetBonePoses()[pVertex->m_Bone].Transform(pVertex->m_Coords); + } else { + bound+=pVertex->m_Coords; + } + } +} diff --git a/source/terrain/Model.h b/source/terrain/Model.h index 217ae65ca8..851688e826 100755 --- a/source/terrain/Model.h +++ b/source/terrain/Model.h @@ -14,8 +14,12 @@ #include "Texture.h" #include "ModelDef.h" +#include "RenderableObject.h" -class CModel + +class CBound; + +class CModel { public: CModel(); @@ -27,6 +31,10 @@ class CModel void SetPose (const char *anim_name, float time); void ClearPose (); + void CalcBounds(CBound& bound); + + CRenderData* m_RenderData; + //access functions public: CModelDef *GetModelDef() { return m_pModelDef; } diff --git a/source/terrain/ModelDef.cpp b/source/terrain/ModelDef.cpp index 1724bbed16..c3616c7396 100755 --- a/source/terrain/ModelDef.cpp +++ b/source/terrain/ModelDef.cpp @@ -94,16 +94,19 @@ void CModelDef::SetupBones() for (i=0; im_Bone]; + if (pVertex->m_Bone>=0) { + SModelBone *pBone = &m_pBones[pVertex->m_Bone]; - CVector3D BonePos = pBone->m_Absolute.GetTranslation(); + CVector3D BonePos = pBone->m_Absolute.GetTranslation(); - pVertex->m_Coords.X -= BonePos.X; - pVertex->m_Coords.Y -= BonePos.Y; - pVertex->m_Coords.Z -= BonePos.Z; + pVertex->m_Coords.X -= BonePos.X; + pVertex->m_Coords.Y -= BonePos.Y; + pVertex->m_Coords.Z -= BonePos.Z; - CMatrix3D BoneInvMat = pBone->m_Absolute.GetTranspose(); + CMatrix3D BoneInvMat; + pBone->m_Absolute.Invert(BoneInvMat); - pVertex->m_Coords = BoneInvMat.Rotate (pVertex->m_Coords); + pVertex->m_Coords = BoneInvMat.Rotate (pVertex->m_Coords); + } } } diff --git a/source/terrain/ModelDef.h b/source/terrain/ModelDef.h index 5f547bd44c..5bc4b6b03c 100755 --- a/source/terrain/ModelDef.h +++ b/source/terrain/ModelDef.h @@ -99,7 +99,7 @@ class CModelDef int GetNumAnimationFrames() { return m_NumAnimationFrames; } int GetNumAnimations() { return m_NumAnimations; } - protected: + public: SModelVertex *m_pVertices; SModelFace *m_pFaces; SModelBone *m_pBones; diff --git a/source/terrain/Patch.cpp b/source/terrain/Patch.cpp index 54f2f4319f..95a450387c 100755 --- a/source/terrain/Patch.cpp +++ b/source/terrain/Patch.cpp @@ -11,40 +11,51 @@ //*********************************************************** #include "Patch.h" +#include "Terrain.h" -CPatch::CPatch () +CPatch::CPatch() { - m_pVertices = NULL; + m_Parent = NULL; } -CPatch::~CPatch () +CPatch::~CPatch() { } -//Initialize the patch -void CPatch::Initialize (STerrainVertex *first_vertex) +void CPatch::Initialize(CTerrain* parent,u32 x,u32 z) { - int j; + delete m_RenderData; + m_RenderData; - m_pVertices = first_vertex; + m_Parent=parent; + m_X=x; + m_Z=z; + + u32 mapSize=m_Parent->GetVerticesPerSide(); + + for (int j=0; j<16; j++) { + for (int i=0; i<16; i++) { + m_MiniPatches[j][i].m_Parent=this; + } + } + + CalcBounds(); +} + +void CPatch::CalcBounds() +{ + u32 mapSize=m_Parent->GetVerticesPerSide(); m_Bounds.SetEmpty(); - for (j=0; jCalcPosition(m_X*PATCH_SIZE+i,m_Z*PATCH_SIZE+j,pos); + m_Bounds+=pos; } } } diff --git a/source/terrain/Patch.h b/source/terrain/Patch.h index c7418b4d74..c9c7925331 100755 --- a/source/terrain/Patch.h +++ b/source/terrain/Patch.h @@ -12,27 +12,32 @@ #ifndef PATCH_H #define PATCH_H -#include "Bound.h" +#include "Matrix3D.h" +#include "Camera.h" #include "TerrGlobals.h" #include "MiniPatch.h" +#include "RenderableObject.h" -class CPatch + +class CPatch : public CRenderableObject { - public: - CPatch (); - ~CPatch (); +public: + CPatch(); + ~CPatch(); - //initialize the patch - void Initialize (STerrainVertex *first_vertex); + //initialize the patch + void Initialize(CTerrain* parent,u32 x,u32 z); -// protected: - CMiniPatch m_MiniPatches[16][16]; + // calculate and store bounds of this patch + void CalcBounds(); - CBound m_Bounds; - unsigned int m_LastVisFrame; - - STerrainVertex *m_pVertices; + // minipatches (tiles) making up the patch + CMiniPatch m_MiniPatches[16][16]; + // position of patch in parent terrain grid + u32 m_X,m_Z; + // parent terrain + CTerrain* m_Parent; }; -#endif \ No newline at end of file +#endif diff --git a/source/terrain/PatchRData.cpp b/source/terrain/PatchRData.cpp index 8689e96573..d35edb4e7f 100755 --- a/source/terrain/PatchRData.cpp +++ b/source/terrain/PatchRData.cpp @@ -106,7 +106,7 @@ void CPatchRData::BuildBlends() } } if (neighbourTextures.size()>0) { - u32 count=neighbourTextures.size(); + size_t count=neighbourTextures.size(); // sort textures from lowest to highest priority std::sort(neighbourTextures.begin(),neighbourTextures.end()); @@ -175,7 +175,7 @@ void CPatchRData::BuildBlends() int vsize=PATCH_SIZE+1; SBlendVertex dst; - int vindex=m_BlendVertices.size(); + size_t vindex=m_BlendVertices.size(); const SBaseVertex& vtx0=m_Vertices[(j*vsize)+i]; dst.m_UVs[0]=i*0.125f; diff --git a/source/terrain/Renderer.cpp b/source/terrain/Renderer.cpp index 8f0816b421..4cd05f81a7 100755 --- a/source/terrain/Renderer.cpp +++ b/source/terrain/Renderer.cpp @@ -10,21 +10,90 @@ // types - terrain, models, sprites, particles etc //---------------------------------------------------------------- + +#include +#include +#include #include "Renderer.h" +#include "TransparencyRenderer.h" #include "Terrain.h" #include "Matrix3D.h" #include "Camera.h" +#include "PatchRData.h" #include "Texture.h" +#include "LightEnv.h" +#include "Visual.h" #include "Model.h" #include "ModelDef.h" #include "types.h" #include "ogl.h" -#include "res/res.h" +#include "res/mem.h" +#include "res/tex.h" + + +struct TGAHeader { + // header stuff + unsigned char iif_size; + unsigned char cmap_type; + unsigned char image_type; + unsigned char pad[5]; + + // origin : unused + unsigned short d_x_origin; + unsigned short d_y_origin; + + // dimensions + unsigned short width; + unsigned short height; + + // bits per pixel : 16, 24 or 32 + unsigned char bpp; + + // image descriptor : Bits 3-0: size of alpha channel + // Bit 4: must be 0 (reserved) + // Bit 5: should be 0 (origin) + // Bits 6-7: should be 0 (interleaving) + unsigned char image_descriptor; +}; + +static bool saveTGA(const char* filename,int width,int height,unsigned char* data) +{ + FILE* fp=fopen(filename,"wb"); + if (!fp) return false; + + // fill file header + TGAHeader header; + header.iif_size=0; + header.cmap_type=0; + header.image_type=2; + memset(header.pad,0,sizeof(header.pad)); + header.d_x_origin=0; + header.d_y_origin=0; + header.width=width; + header.height=height; + header.bpp=24; + header.image_descriptor=0; + + if (fwrite(&header,sizeof(TGAHeader),1,fp)!=1) { + fclose(fp); + return false; + } + + // write data + if (fwrite(data,width*height*3,1,fp)!=1) { + fclose(fp); + return false; + } + + // return success .. + fclose(fp); + return true; +} + +extern CTerrain g_Terrain; -#define RENDER_STAGE_BASE (1) -#define RENDER_STAGE_TRANS (2) CRenderer::CRenderer () { @@ -32,7 +101,8 @@ CRenderer::CRenderer () m_Height=0; m_Depth=0; m_FrameCounter=0; - m_TerrainMode=FILL; + m_TerrainRenderMode=SOLID; + m_ModelRenderMode=SOLID; } CRenderer::~CRenderer () @@ -40,18 +110,38 @@ CRenderer::~CRenderer () } +// EnumCaps: build card cap bits +void CRenderer::EnumCaps() +{ + // assume support for nothing + m_Caps.m_VBO=false; +#if 1 + // now start querying extensions + if (oglExtAvail("GL_ARB_vertex_buffer_object")) { + m_Caps.m_VBO=true; + } +#endif +} + bool CRenderer::Open(int width, int height, int depth) { m_Width = width; m_Height = height; m_Depth = depth; + // set packing parameters + glPixelStorei(GL_PACK_ALIGNMENT,1); + glPixelStorei(GL_UNPACK_ALIGNMENT,1); + // setup default state glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glClearColor(0.0f,0.0f,0.0f,0.0f); + // query card capabilities + EnumCaps(); + return true; } @@ -72,35 +162,199 @@ void CRenderer::BeginFrame() // bump frame counter m_FrameCounter++; + // zero out all the per-frame stats + m_Stats.Reset(); + + // calculate coefficients for terrain and unit lighting + m_SHCoeffsUnits.Clear(); + m_SHCoeffsTerrain.Clear(); + + if (m_LightEnv) { + CVector3D dirlight; + m_LightEnv->GetSunDirection(dirlight); + m_SHCoeffsUnits.AddDirectionalLight(dirlight,m_LightEnv->m_SunColor); + m_SHCoeffsTerrain.AddDirectionalLight(dirlight,m_LightEnv->m_SunColor); + + m_SHCoeffsUnits.AddAmbientLight(m_LightEnv->m_UnitsAmbientColor); + m_SHCoeffsTerrain.AddAmbientLight(m_LightEnv->m_TerrainAmbientColor); + } + // clear buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } +void CRenderer::RenderPatches() +{ + // switch on wireframe if we need it + if (m_TerrainRenderMode==WIREFRAME) { + glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); + } + + // render all the patches, including blend pass + RenderPatchSubmissions(); + + if (m_TerrainRenderMode==WIREFRAME) { + // switch wireframe off again + glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); + } else if (m_TerrainRenderMode==EDGED_FACES) { + // edged faces: need to make a second pass over the data: + // first switch on wireframe + glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); + + // setup some renderstate .. + glDepthMask(0); + SetTexture(0,0); + glColor4f(1,1,1,0.35f); + glLineWidth(2.0f); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + // .. and some client states + glEnableClientState(GL_VERTEX_ARRAY); + + uint i; + + // render each patch in wireframe + for (i=0;im_RenderData; + patchdata->RenderWireframe(); + } + + // set color for outline + glColor3f(0,0,1); + glLineWidth(4.0f); + + // render outline of each patch + for (i=0;im_RenderData; + patchdata->RenderOutline(); + } + + // .. and switch off the client states + glDisableClientState(GL_VERTEX_ARRAY); + + // .. and restore the renderstates + glDisable(GL_BLEND); + glDepthMask(1); + + // restore fill mode, and we're done + glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); + } +} + +void CRenderer::RenderModelSubmissions() +{ + uint i; + + // first ensure all patches have up to date renderdata built for them; build up transparent passes + // along the way + for (i=0;im_Model->m_RenderData; + if (data==0) { + // no renderdata for model, create it now + data=new CModelRData(visual->m_Model); + } else { + data->Update(); + } + + BuildTransparentPasses(visual); + } + + // 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_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); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); + + // setup client states + glClientActiveTexture(GL_TEXTURE0); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + // render models + for (i=0;im_Model->m_RenderData; + modeldata->Render(visual->GetTransform()); + } + + // switch off client states + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + +void CRenderer::RenderModels() +{ + // switch on wireframe if we need it + if (m_ModelRenderMode==WIREFRAME) { + glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); + } + + // render all the models + RenderModelSubmissions(); + + if (m_ModelRenderMode==WIREFRAME) { + // switch wireframe off again + glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); + } else if (m_ModelRenderMode==EDGED_FACES) { + // edged faces: need to make a second pass over the data: + // first switch on wireframe + glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); + + // setup some renderstate .. + glDepthMask(0); + SetTexture(0,0); + glColor4f(1,1,1,0.75f); + glLineWidth(1.0f); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + // .. and some client states + glEnableClientState(GL_VERTEX_ARRAY); + + // render each model + for (uint i=0;im_Model->m_RenderData; + modeldata->RenderWireframe(visual->GetTransform()); + } + + // .. and switch off the client states + glDisableClientState(GL_VERTEX_ARRAY); + + // .. and restore the renderstates + glDisable(GL_BLEND); + glDepthMask(1); + + // restore fill mode, and we're done + glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); + } +} + // force rendering of any batched objects void CRenderer::FlushFrame() { - unsigned i; + // render submitted patches and models + RenderPatches(); - // render base terrain - if (m_TerrainMode==WIREFRAME) { - glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); - } + RenderModels(); - for (i=0;i sub; - patch->m_LastVisFrame=m_FrameCounter; sub.m_Object=patch; m_TerrainPatches.push_back(sub); } -void CRenderer::Submit(CModel* model,CMatrix3D* transform) +void CRenderer::Submit(CVisual* visual) { - SSubmission sub; - sub.m_Object=model; - sub.m_Transform=transform; + SSubmission sub; + sub.m_Object=visual; m_Models.push_back(sub); } @@ -167,74 +422,109 @@ void CRenderer::Submit(COverlay* overlay) { } - - -/* -void CRenderer::RenderTileOutline (CMiniPatch *mpatch) +void CRenderer::RenderPatchSubmissions() { - glActiveTexture (GL_TEXTURE0); - glDisable (GL_DEPTH_TEST); - glDisable (GL_TEXTURE_2D); - glLineWidth (4); - - STerrainVertex V[4]; - V[0] = mpatch->m_pVertices[0]; - V[1] = mpatch->m_pVertices[1]; - V[2] = mpatch->m_pVertices[MAP_SIZE*1 + 1]; - V[3] = mpatch->m_pVertices[MAP_SIZE*1]; - - glColor3f (0,1.0f,0); - - glBegin (GL_LINE_LOOP); - - for(int i = 0; i < 4; i++) - glVertex3fv(&V[i].m_Position.X); - - glEnd (); - - glEnable (GL_DEPTH_TEST); - glEnable (GL_TEXTURE_2D); -} -*/ - -void CRenderer::RenderModel(SSubmission& modelsub) -{ - glPushMatrix(); - glMultMatrixf(modelsub.m_Transform->_data); - - SetTexture(0,modelsub.m_Object->GetTexture()); - glColor3f(1.0f,1.0f,1.0f); - - CModel* mdl=(CModel*) modelsub.m_Object; - CModelDef* mdldef=(CModelDef*) mdl->GetModelDef(); - - glBegin(GL_TRIANGLES); - for (int fi=0; fiGetNumFaces(); fi++) - { - SModelFace *pFace = &mdldef->GetFaces()[fi]; - - for (int vi=0; vi<3; vi++) - { - SModelVertex *pVertex = &mdldef->GetVertices()[pFace->m_Verts[vi]]; - CVector3D Coord = mdl->GetBonePoses()[pVertex->m_Bone].Transform(pVertex->m_Coords); - - glTexCoord2f (pVertex->m_U, pVertex->m_V); - - glVertex3f (Coord.X, Coord.Y, Coord.Z); + uint i; + // first ensure all patches have up to date renderdata built for them + for (i=0;im_RenderData; + if (data==0) { + // no renderdata for patch, create it now + data=new CPatchRData(patch); + } else { + data->Update(); } } - glEnd(); - glPopMatrix(); + // set up client states for base pass + glClientActiveTexture(GL_TEXTURE0); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + // set up texture environment for base pass + glActiveTexture(GL_TEXTURE0); + glEnable(GL_TEXTURE_2D); + 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); + + // render base passes for each patch + for (i=0;im_RenderData; + patchdata->RenderBase(); + } + + // switch on the composite alpha map texture + glActiveTexture(GL_TEXTURE1); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D,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); + + glClientActiveTexture(GL_TEXTURE1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + // render blend passes for each patch + for (i=0;im_RenderData; + patchdata->RenderBlends(); + } + + glClientActiveTexture(GL_TEXTURE1); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + // restore depth writes + glDepthMask(1); + + // restore default state: switch off blending + glDisable(GL_BLEND); + + // switch off texture unit 1, make unit 0 active texture + glActiveTexture(GL_TEXTURE1); + glDisable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + + // switch off all client states + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); } + + // try and load the given texture bool CRenderer::LoadTexture(CTexture* texture) { Handle h=texture->GetHandle(); if (h) { - // already tried to load this texture, nothing to do here - just return accord to whether this - // is a valid handle + // already tried to load this texture, nothing to do here - just return success according + // to whether this is a valid handle or not return h==0xfffffff ? true : false; } else { h=tex_load(texture->GetName()); @@ -250,7 +540,7 @@ bool CRenderer::LoadTexture(CTexture* texture) } // set the given unit to reference the given texture; pass a null texture to disable texturing on any unit -void CRenderer::SetTexture(int unit,CTexture* texture) +void CRenderer::SetTexture(int unit,CTexture* texture,u32 wrapflags) { glActiveTexture(GL_TEXTURE0+unit); if (texture) { @@ -258,6 +548,11 @@ void CRenderer::SetTexture(int unit,CTexture* texture) if (!h) { LoadTexture(texture); h=texture->GetHandle(); + + if (wrapflags) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapflags); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapflags); + } } // disable texturing if invalid handle @@ -273,247 +568,147 @@ void CRenderer::SetTexture(int unit,CTexture* texture) } } -void CRenderer::RenderPatchBase (CPatch *patch) +bool CRenderer::IsTextureTransparent(CTexture* texture) { - CMiniPatch *MPatch, *MPCurrent; - - float StartU, StartV; - - - for (int j=0; j<16; j++) - { - for (int i=0; i<16; i++) - { - MPatch = &(patch->m_MiniPatches[j][i]); - - if (MPatch->m_LastRenderedFrame == m_FrameCounter) - continue; - - glActiveTexture (GL_TEXTURE0); - glEnable(GL_TEXTURE_2D); - -tex_bind(MPatch->Tex1); - - glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - -///////////////////////////////////// - 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); - glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); - glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); -///////////////////////////////////// - - StartU = 0.125f * (float)(i%8); - StartV = 0.125f * (float)(j%8); - - float tu[2], tv[2]; - tu[0] = tu[1] = StartU; - tv[0] = StartV+0.125f; - tv[1] = StartV; - - MPCurrent = MPatch; - glBegin (GL_TRIANGLE_STRIP); - - int start = 0; - - while (MPCurrent) - { - for (int x=start; x<2; x++) - { - int v1 = MAP_SIZE + x; - int v2 = x; - - glTexCoord2f (tu[0], tv[0]); - - if (g_HillShading) - glColor3fv(&MPCurrent->m_pVertices[v1].m_Color.X); - else - glColor3f (1,1,1); - - glVertex3f (MPCurrent->m_pVertices[v1].m_Position.X, - MPCurrent->m_pVertices[v1].m_Position.Y, - MPCurrent->m_pVertices[v1].m_Position.Z); - - glTexCoord2f (tu[1], tv[1]); - - if (g_HillShading) - glColor3fv(&MPCurrent->m_pVertices[v2].m_Color.X); - else - glColor3f (1,1,1); - - glVertex3f (MPCurrent->m_pVertices[v2].m_Position.X, - MPCurrent->m_pVertices[v2].m_Position.Y, - MPCurrent->m_pVertices[v2].m_Position.Z); - - tu[0]+=0.125f; - tu[1]+=0.125f; - } - - MPCurrent->m_LastRenderedFrame = m_FrameCounter; - MPCurrent->m_RenderStage = RENDER_STAGE_BASE; - - if (!MPCurrent->m_pRightNeighbor) - break; - else - { - if (MPCurrent->m_pRightNeighbor->Tex1 != MPCurrent->Tex1 || - MPCurrent->m_pRightNeighbor->m_pParrent->m_LastVisFrame != m_FrameCounter) - break; - } - - MPCurrent = MPCurrent->m_pRightNeighbor; - start = 1; + if (texture) { + Handle h=texture->GetHandle(); + if (!h) { + LoadTexture(texture); + h=texture->GetHandle(); + if (h!=0xffffffff) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); } - - glEnd (); + } + if (h!=0xffffffff && h) { + int fmt; + int bpp; + + tex_info(h, NULL, NULL, &fmt, &bpp, NULL); + if (bpp==24 || fmt == GL_COMPRESSED_RGB_S3TC_DXT1_EXT) + { + return false; + } + return true; + } else { + return false; } + } else { + return false; } } -void CRenderer::RenderPatchTrans (CPatch *patch) +static int RoundUpToPowerOf2(int x) { - CMiniPatch *MPatch, *MPCurrent; + if ((x & (x-1))==0) return x; + int d=x; + while (d & (d-1)) { + d&=(d-1); + } + return d<<1; +} - float StartU, StartV; + +inline void CopyTriple(unsigned char* dst,const unsigned char* src) +{ + dst[0]=src[0]; + dst[1]=src[1]; + dst[2]=src[2]; +} + +// LoadAlphaMaps: load the 14 default alpha maps, pack them into one composite texture and +// calculate the coordinate of each alphamap within this packed texture .. need to add +// validation that all maps are the same size +bool CRenderer::LoadAlphaMaps(const char* fnames[]) +{ + glActiveTexture(GL_TEXTURE0_ARB); - glEnable (GL_BLEND); - glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + Handle textures[NumAlphaMaps]; + + int i; - for (int j=0; j<16; j++) - { - for (int i=0; i<16; i++) - { - MPatch = &(patch->m_MiniPatches[j][i]); - - if (MPatch->m_LastRenderedFrame == m_FrameCounter && - MPatch->m_RenderStage == RENDER_STAGE_TRANS) - continue; - - //now for transition - if (MPatch->Tex2 && MPatch->m_AlphaMap) - { - - glActiveTexture (GL_TEXTURE0); - glEnable(GL_TEXTURE_2D); - -tex_bind(MPatch->Tex2); - - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - -///////////////////////////////////// - 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_TEXTURE); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); -///////////////////////////////////// - - - glActiveTexture (GL_TEXTURE1); - glEnable(GL_TEXTURE_2D); -tex_bind(MPatch->m_AlphaMap); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); -///////////////////////////////////// - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); - glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); - glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE); - 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_TEXTURE); - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); -///////////////////////////////////// - - StartU = 0.125f * (float)(i%8); - StartV = 0.125f * (float)(j%8); - - float tu[2], tv[2]; - tu[0] = tu[1] = StartU; - tv[0] = StartV+0.125f; - tv[1] = StartV; - - glBegin (GL_TRIANGLE_STRIP); - MPCurrent = MPatch; - - int start = 0; - - while (MPCurrent) - { - for (int x=start; x<2; x++) - { - int v1 = MAP_SIZE + x; - int v2 = x; - - glMultiTexCoord2f (GL_TEXTURE0_ARB, tu[0], tv[0]); - glMultiTexCoord2f (GL_TEXTURE1_ARB, tu[0]*2, tv[0]*2); - - if (g_HillShading) - glColor3fv(&MPCurrent->m_pVertices[v1].m_Color.X); - else - glColor3f (1,1,1); - - glVertex3f (MPCurrent->m_pVertices[v1].m_Position.X, - MPCurrent->m_pVertices[v1].m_Position.Y, - MPCurrent->m_pVertices[v1].m_Position.Z); - - glMultiTexCoord2f (GL_TEXTURE0_ARB, tu[1], tv[1]); - glMultiTexCoord2f (GL_TEXTURE1_ARB, tu[1]*2, tv[1]*2); - - if (g_HillShading) - glColor3fv(&MPCurrent->m_pVertices[v1].m_Color.X); - else - glColor3f (1,1,1); - - glVertex3f (MPCurrent->m_pVertices[v2].m_Position.X, - MPCurrent->m_pVertices[v2].m_Position.Y, - MPCurrent->m_pVertices[v2].m_Position.Z); - - tu[0]+=0.125f; - tu[1]+=0.125f; - } - - MPCurrent->m_LastRenderedFrame = m_FrameCounter; - MPCurrent->m_RenderStage = RENDER_STAGE_TRANS; - - if (!MPCurrent->m_pRightNeighbor) - break; - else - { - if (MPCurrent->m_pRightNeighbor->Tex2 != MPCurrent->Tex2 || - MPCurrent->m_pRightNeighbor->m_AlphaMap != MPCurrent->m_AlphaMap || - MPCurrent->m_pRightNeighbor->m_pParrent->m_LastVisFrame != m_FrameCounter) - break; - } - - MPCurrent = MPCurrent->m_pRightNeighbor; - start=1; - } - - glEnd (); - } + for (i=0;im_Model->GetTexture())) { + // ok, no transparency on this model .. ignore it here + return; + } + + // add this visual to the transparency renderer for later processing + g_TransparencyRenderer.Add(visual); +} + + diff --git a/source/terrain/Renderer.h b/source/terrain/Renderer.h index 239386d0bd..1fa5d18b84 100755 --- a/source/terrain/Renderer.h +++ b/source/terrain/Renderer.h @@ -15,20 +15,31 @@ #define RENDERER_H #include +#include "res/res.h" #include "ogl.h" +#include "Camera.h" #include "Frustum.h" +#include "PatchRData.h" +#include "ModelRData.h" +#include "SHCoeffs.h" +#include "Terrain.h" // necessary declarations class CCamera; class CPatch; -class CModel; +class CVisual; class CSprite; class CParticleSys; class COverlay; class CMaterial; class CLightEnv; -class SPatchRData; class CTexture; +class CTerrain; + + +// rendering modes +enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES }; + ////////////////////////////////////////////////////////////////////////////////////////// // SSubmission: generalised class representating a submission of objects to renderer @@ -63,8 +74,36 @@ struct SVertex2D class CRenderer { public: - // various enumerations - enum ETerrainMode { WIREFRAME, FILL }; + // various enumerations and renderer related constants + enum { NumAlphaMaps=14 }; + + // stats class - per frame counts of number of draw calls, poly counts etc + struct Stats { + // set all stats to zero + void Reset() { memset(this,0,sizeof(*this)); } + // add given stats to this stats + Stats& operator+=(const Stats& rhs) { + m_Counter++; + 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; + } + // count of the number of stats added together + u32 m_Counter; + // number of draw calls per frame - total DrawElements + Begin/End immediate mode loops + u32 m_DrawCalls; + // number of terrain triangles drawn + 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; + }; public: // constructor, destructor @@ -95,12 +134,11 @@ public: // submission of objects for rendering; the passed matrix indicating the transform must be scoped such that it is valid beyond // the call to frame end, as must the object itself void Submit(CPatch* patch); - void Submit(CModel* model,CMatrix3D* transform); + void Submit(CVisual* visual); void Submit(CSprite* sprite,CMatrix3D* transform); void Submit(CParticleSys* psys,CMatrix3D* transform); void Submit(COverlay* overlay); -#if 0 // basic primitive rendering operations in 2 and 3D; handy for debugging stuff, but also useful in // editor tools (eg for highlighting specific terrain patches) // note: @@ -115,30 +153,53 @@ public: void RenderLineLoop(int len,const SVertex3D* vertices); void RenderTri(const SVertex3D* vertices); void RenderQuad(const SVertex3D* vertices); -#endif // set the current lighting environment; (note: the passed pointer is just copied to a variable within the renderer, // so the lightenv passed must be scoped such that it is not destructed until after the renderer is no longer rendering) - void SetLightEnv(CLightEnv* lightenv); + void SetLightEnv(CLightEnv* lightenv) { + m_LightEnv=lightenv; + } // set the mode to render subsequent terrain patches - void SetTerrainMode(ETerrainMode mode) { m_TerrainMode=mode; } + void SetTerrainRenderMode(ERenderMode mode) { m_TerrainRenderMode=mode; } // get the mode to render subsequent terrain patches - ETerrainMode GetTerrainMode() const { return m_TerrainMode; } + ERenderMode GetTerrainRenderMode() const { return m_TerrainRenderMode; } + + // set the mode to render subsequent models + void SetModelRenderMode(ERenderMode mode) { m_ModelRenderMode=mode; } + // get the mode to render subsequent models + ERenderMode GetModelRenderMode() const { return m_ModelRenderMode; } // try and load the given texture bool LoadTexture(CTexture* texture); // set the given unit to reference the given texture; pass a null texture to disable texturing on any unit // note - active texture always set to given unit on exit - void SetTexture(int unit,CTexture* texture); + void SetTexture(int unit,CTexture* texture,u32 wrapflags=0); + // query transparency of given texture + bool IsTextureTransparent(CTexture* texture); + + // load the default set of alphamaps; return false if any alphamap fails to load, true otherwise + bool LoadAlphaMaps(const char* fnames[]); + + // return stats accumulated for current frame + const Stats& GetStats() { return m_Stats; } + + inline int GetWidth() const { return m_Width; } + inline int GetHeight() const { return m_Height; } protected: + friend class CPatchRData; + friend class CModelRData; + friend class CTransparencyRenderer; + // patch rendering stuff - void RenderPatchBase(CPatch* patch); - void RenderPatchTrans(CPatch* patch); + void RenderPatchSubmissions(); + void RenderPatches(); // model rendering stuff - void RenderModel(SSubmission& modelsub); + void BuildTransparentPasses(CVisual* visual); + void RenderModelSubmissions(); + void RenderModels(); // RENDERER DATA: // view width @@ -150,15 +211,40 @@ protected: // frame counter int m_FrameCounter; // current terrain rendering mode - ETerrainMode m_TerrainMode; + ERenderMode m_TerrainRenderMode; + // current model rendering mode + ERenderMode m_ModelRenderMode; + // current view camera + CCamera m_Camera; // submitted object lists for batching std::vector > m_TerrainPatches; - std::vector > m_Models; + std::vector > m_Models; std::vector > m_Sprites; std::vector > m_ParticleSyses; std::vector > m_Overlays; // current lighting setup CLightEnv* m_LightEnv; + // current spherical harmonic coefficients (for unit lighting), derived from lightenv + CSHCoeffs m_SHCoeffsUnits; + // current spherical harmonic coefficients (for terrain lighting), derived from lightenv + CSHCoeffs m_SHCoeffsTerrain; + // default alpha maps + //Handle m_AlphaMaps[NumAlphaMaps]; + // all the alpha maps packed into one texture + unsigned int m_CompositeAlphaMap; + // coordinates of each (untransformed) alpha map within the packed texture + struct { + float u0,u1,v0,v1; + } m_AlphaMapCoords[NumAlphaMaps]; + + // card capabilities + struct Caps { + bool m_VBO; + } m_Caps; + // build card cap bits + void EnumCaps(); + // per-frame renderer stats + Stats m_Stats; }; diff --git a/source/terrain/SHCoeffs.cpp b/source/terrain/SHCoeffs.cpp index f11be80cb2..d8ad9d96bf 100755 --- a/source/terrain/SHCoeffs.cpp +++ b/source/terrain/SHCoeffs.cpp @@ -12,6 +12,11 @@ #include "SHCoeffs.h" CSHCoeffs::CSHCoeffs() +{ + Clear(); +} + +void CSHCoeffs::Clear() { for (int i=0;i<9;i++) { _data[i].Clear(); @@ -45,7 +50,7 @@ void CSHCoeffs::AddDirectionalLight(const CVector3D& lightDir,const RGBColor& li _data[8]+=lightColor*c5*(SQR(dirToLight.X)-SQR(dirToLight.Y)); } -void CSHCoeffs::Evaluate(const CVector3D& normal,RGBColor& color) +void CSHCoeffs::Evaluate(const CVector3D& normal,RGBColor& color) const { #if 1 color=_data[0]; diff --git a/source/terrain/SHCoeffs.h b/source/terrain/SHCoeffs.h index bcecce76dd..a71621bd74 100755 --- a/source/terrain/SHCoeffs.h +++ b/source/terrain/SHCoeffs.h @@ -19,10 +19,12 @@ class CSHCoeffs public: CSHCoeffs(); + void Clear(); + void AddAmbientLight(const RGBColor& color); void AddDirectionalLight(const CVector3D& lightDir,const RGBColor& lightColor); - void Evaluate(const CVector3D& normal,RGBColor& color); + void Evaluate(const CVector3D& normal,RGBColor& color) const; const RGBColor* GetCoefficients() const { return _data; } diff --git a/source/terrain/TerrGlobals.h b/source/terrain/TerrGlobals.h index 18c27aa6b3..aa831010fc 100755 --- a/source/terrain/TerrGlobals.h +++ b/source/terrain/TerrGlobals.h @@ -12,18 +12,9 @@ #ifndef TERRGLOBALS_H #define TERRGLOBALS_H -const int PATCH_SIZE = 16; -const int CELL_SIZE = 4; //horizontal scale of the patches -const float HEIGHT_SCALE = 0.35f; - -//only 3x3 patches loaded at a time -const int NUM_PATCHES_PER_SIDE = 20; - -//must be odd number of patches -//#define TERRAIN_CHUNK_SIZE (PATCH_SIZE*NUM_PATCHES_PER_SIDE) -const int MAP_SIZE = ( (NUM_PATCHES_PER_SIDE*PATCH_SIZE)+1 ); - - +const int PATCH_SIZE = 16; +const int CELL_SIZE = 4; //horizontal scale of the patches +const float HEIGHT_SCALE = 0.35f/256.0f; #endif diff --git a/source/terrain/Terrain.cpp b/source/terrain/Terrain.cpp index 993aeec7bc..715bd02d6e 100755 --- a/source/terrain/Terrain.cpp +++ b/source/terrain/Terrain.cpp @@ -14,182 +14,267 @@ // //*********************************************************** -#include "res/res.h" +#include "res/tex.h" +#include "res/mem.h" + +#include #include "Terrain.h" -#include "LightEnv.h" -#include "SHCoeffs.h" -bool g_HillShading = true; -CVector3D SeasonLight[2]; -float SeasonColor[2][3]; - -CTerrain::CTerrain () +CTerrain::CTerrain() { - m_pVertices = NULL; + m_Heightmap = NULL; + m_Patches = NULL; + m_MapSize = 0; + m_MapSizePatches = 0; } -CTerrain::~CTerrain () +CTerrain::~CTerrain() { - delete [] m_pVertices; + Reset(); } -bool CTerrain::Load(char *filename) -{ - Handle ht = tex_load(filename); - if(!ht) - return false; - void* p; - tex_info(ht, 0, 0, &p); - return InitFromHeightmap((const u8*)p); +void CTerrain::Reset() +{ + delete[] m_Heightmap; + delete[] m_Patches; } -bool CTerrain::InitFromHeightmap(const u8* data) + +bool CTerrain::Initialize(u32 size,const u16* data) { - int j; + // clean up any previous terrain + Reset(); - delete[] m_pVertices; + // store terrain size + m_MapSize=(size*PATCH_SIZE)+1; + m_MapSizePatches=size; - m_pVertices = new STerrainVertex[MAP_SIZE*MAP_SIZE]; - if (m_pVertices == NULL) - return false; + // allocate data for new terrain + m_Heightmap=new u16[m_MapSize*m_MapSize]; + m_Patches=new CPatch[m_MapSizePatches*m_MapSizePatches]; - for (j=0; j0) - left = m_pVertices[j*MAP_SIZE + i - 1].m_Position - - m_pVertices[j*MAP_SIZE + i].m_Position; + left.Clear(); + right.Clear(); + up.Clear(); + down.Clear(); + + // get position of vertex where normal is being evaluated + CVector3D basepos; + CalcPosition(i,j,basepos); - if (i0) { + CalcPosition(i-1,j,tmp); + left=tmp-basepos; + } - if (j>0) - up = m_pVertices[(j-1)*MAP_SIZE + i].m_Position - - m_pVertices[j*MAP_SIZE + i].m_Position; + if (i0) { + CalcPosition(i,j-1,tmp); + up=tmp-basepos; + } - n[0] = up.Cross(left); - n[1] = left.Cross(down); - n[2] = down.Cross(right); - n[3] = right.Cross(up); + if (j0.0001f) n[0]*=1.0f/n0len; + CVector3D n0 = up.Cross(left); + CVector3D n1 = left.Cross(down); + CVector3D n2 = down.Cross(right); + CVector3D n3 = right.Cross(up); - float n1len=n[1].GetLength(); - if (n1len>0.0001f) n[1]*=1.0f/n1len; + normal = n0 + n1 + n2 + n3; + float nlen=normal.GetLength(); + if (nlen>0.00001f) normal*=1.0f/nlen; +} - float n2len=n[2].GetLength(); - if (n2len>0.0001f) n[2]*=1.0f/n2len; - float n3len=n[3].GetLength(); - if (n3len>0.0001f) n[3]*=1.0f/n3len; +CPatch* CTerrain::GetPatch(int32 x,int32 z) +{ + if (x<0 || x>=int32(m_MapSizePatches)) return 0; + if (z<0 || z>=int32(m_MapSizePatches)) return 0; + return &m_Patches[(z*m_MapSizePatches)+x]; +} - CVector3D Normal = n[0] + n[1] + n[2] + n[3]; - float nlen=Normal.GetLength(); - if (nlen>0.00001f) Normal*=1.0f/nlen; - - m_pVertices[j*MAP_SIZE + i].m_Normal=Normal; +CMiniPatch* CTerrain::GetTile(int32 x,int32 z) +{ + if (x<0 || x>=int32(m_MapSize)-1) return 0; + if (z<0 || z>=int32(m_MapSize)-1) return 0; + + CPatch* patch=GetPatch(x/16,z/16); + return &patch->m_MiniPatches[z%16][x%16]; +} + + +void CTerrain::Resize(u32 size) +{ + if (size==m_MapSizePatches) { + // inexplicable request to resize terrain to the same size .. ignore it + return; + } + + if (!m_Heightmap) { + // not yet created a terrain; build a default terrain of the given size now + Initialize(size,0); + return; + } + + // allocate data for new terrain + u32 newMapSize=(size*PATCH_SIZE)+1; + u16* newHeightmap=new u16[newMapSize*newMapSize]; + CPatch* newPatches=new CPatch[size*size]; + + if (size>m_MapSizePatches) { + // new map is bigger than old one - zero the heightmap so we don't get uninitialised + // height data along the expanded edges + memset(newHeightmap,0,newMapSize*newMapSize); + } + + // now copy over rows of data + u32 j; + u16* src=m_Heightmap; + u16* dst=newHeightmap; + u32 copysize=newMapSize>m_MapSize ? m_MapSize : newMapSize; + for (j=0;jm_MapSize) { + // entend the last height to the end of the row + for (u32 i=0;im_MapSize) { + // copy over heights of the last row to any remaining rows + src=newHeightmap+((m_MapSize-1)*newMapSize); + dst=src+newMapSize; + for (u32 i=0;im_MiniPatches[tj][ti]; - - MPatch->m_pParrent = ThisPatch; - - if (ti < 15) - MPatch->m_pRightNeighbor = &ThisPatch->m_MiniPatches[tj][ti+1]; - else - { - if (RightPatch) - MPatch->m_pRightNeighbor = &RightPatch->m_MiniPatches[tj][0]; - else - MPatch->m_pRightNeighbor = NULL; + if (jm_MapSizePatches) { + // copy over the last tile from each column + for (u32 n=0;nm_MapSizePatches) { + // copy over the last tile from each column + CPatch* srcpatch=&newPatches[(m_MapSizePatches-1)*size]; + CPatch* dstpatch=srcpatch+size; + for (u32 p=0;pm_MiniPatches[15][k]; + CMiniPatch& dst=dstpatch->m_MiniPatches[m][k]; + dst.Tex1=src.Tex1; + dst.Tex1Priority=src.Tex1Priority; + } + } + srcpatch++; + dstpatch++; + } + } + } + + // release all the original data + Reset(); + + // store new data + m_Heightmap=newHeightmap; + m_Patches=newPatches; + m_MapSize=newMapSize; + m_MapSizePatches=size; + + // initialise all the new patches + InitialisePatches(); +} + +void CTerrain::InitialisePatches() +{ + for (u32 j=0;jInitialize(this,i,j); + } + } +} + +// SetHeightMap: set up a new heightmap from 16-bit source data; +// assumes heightmap matches current terrain size +void CTerrain::SetHeightMap(u16* heightmap) +{ + // keep a copy of the given heightmap + memcpy(m_Heightmap,heightmap,m_MapSize*m_MapSize*sizeof(u16)); + + // recalculate patch bounds, invalidate vertices + for (u32 j=0;jCalcBounds(); + if (patch->m_RenderData) patch->m_RenderData->m_UpdateFlags|=RENDERDATA_UPDATE_VERTICES; + } + } } diff --git a/source/terrain/Terrain.h b/source/terrain/Terrain.h index 47fa2322d9..dcd2c6fba7 100755 --- a/source/terrain/Terrain.h +++ b/source/terrain/Terrain.h @@ -17,34 +17,62 @@ #ifndef TERRAIN_H #define TERRAIN_H -#include - #include "Patch.h" #include "Vector3D.h" +#include "TerrGlobals.h" class CLightEnv; +class CSHCoeffs; -extern bool g_HillShading; class CTerrain { - public: - CTerrain (); - ~CTerrain (); +public: + CTerrain(); + ~CTerrain(); - bool Load(char *filename); - bool InitFromHeightmap(const u8* data); + bool Initialize(u32 size,const u16* ptr); -// protected: - //the patches currently loaded - CPatch m_Patches[NUM_PATCHES_PER_SIDE][NUM_PATCHES_PER_SIDE]; - STerrainVertex *m_pVertices; + // return number of vertices along edge of the terrain + u32 GetVerticesPerSide() { return m_MapSize; } + // return number of patches along edge of the terrain + u32 GetPatchesPerSide() { return m_MapSizePatches; } + // resize this terrain such that each side has given number of patches + void Resize(u32 size); + + // set up a new heightmap from 16 bit data; assumes heightmap matches current terrain size + void SetHeightMap(u16* heightmap); + // return a pointer to the heightmap + u16* GetHeightMap() const { return m_Heightmap; } + + // get patch at given coordinates, expressed in patch-space; return 0 if + // coordinates represent patch off the edge of the map + CPatch* GetPatch(int32 x,int32 z); + // get tile at given coordinates, expressed in tile-space; return 0 if + // coordinates represent tile off the edge of the map + CMiniPatch* GetTile(int32 x,int32 z); + + // calculate the position of a given vertex + void CalcPosition(u32 i,u32 j,CVector3D& pos); + // calculate the normal at a given vertex + void CalcNormal(u32 i,u32 j,CVector3D& normal); + +private: + // clean up terrain data + void Reset(); + // setup patch pointers etc + void InitialisePatches(); + + // size of this map in each direction, in vertices; ie. total tiles = sqr(m_MapSize-1) + u32 m_MapSize; + // size of this map in each direction, in patches; total patches = sqr(m_MapSizePatches) + u32 m_MapSizePatches; + // the patches comprising this terrain + CPatch* m_Patches; + // 16-bit heightmap data + u16* m_Heightmap; -// protected: - void CalcNormals(); - void CalcLighting(const CLightEnv& env); - void SetNeighbors(); }; -#endif \ No newline at end of file +#endif diff --git a/source/terrain/TextureManager.cpp b/source/terrain/TextureManager.cpp index fff7711d4e..0cbdd22da5 100755 --- a/source/terrain/TextureManager.cpp +++ b/source/terrain/TextureManager.cpp @@ -80,7 +80,7 @@ CTextureEntry* CTextureManager::AddTexture(const char* filename,int type) { assert(type // TODO: fix scrolling hack - framerate independent, use SDL //#include "win.h" // REMOVEME @@ -37,15 +39,8 @@ double g_LastTime; const int NUM_ALPHA_MAPS = 13; -//CTexture g_BaseTexture[5]; -Handle BaseTexs[5]; - -Handle AlphaMaps[NUM_ALPHA_MAPS]; -//CTexture g_TransitionTexture[NUM_ALPHA_MAPS]; - int mouse_x=50, mouse_y=50; - void terr_init() { int xres,yres; @@ -69,10 +64,10 @@ void terr_update() g_Renderer.BeginFrame(); g_Renderer.SetCamera(g_Camera); - ///////////////////////////////////////////// - /*POINT MousePos; + // switch on wireframe for terrain if we want it + g_Renderer.SetTerrainRenderMode(SOLID); - GetCursorPos (&MousePos);*/ + ///////////////////////////////////////////// CVector3D right(1,0,1); CVector3D up(1,0,-1); right.Normalize (); @@ -106,22 +101,21 @@ void terr_update() CFrustum frustum=g_Camera.GetFustum(); // iterate through patches; cull everything not visible - for (int j=0; jGetBounds())) { + g_Renderer.Submit(g_Terrain.GetPatch(j, i)); } } } // flush the frame to force terrain to be renderered before overlays g_Renderer.FlushFrame(); - + // g_Renderer.RenderTileOutline (&(g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX])); - // mark end of frame g_Renderer.EndFrame(); } @@ -142,11 +136,11 @@ bool terr_handler(const SDL_Event& ev) case SDL_KEYDOWN: switch(ev.key.keysym.sym) { - case 'W': - if (g_Renderer.GetTerrainMode()==CRenderer::WIREFRAME) { - g_Renderer.SetTerrainMode(CRenderer::FILL); + case 'W': + if (g_Renderer.GetTerrainRenderMode()==WIREFRAME) { + g_Renderer.SetTerrainRenderMode(SOLID); } else { - g_Renderer.SetTerrainMode(CRenderer::WIREFRAME); + g_Renderer.SetTerrainRenderMode(WIREFRAME); } break; @@ -158,14 +152,14 @@ bool terr_handler(const SDL_Event& ev) g_Camera.m_Orientation.Translate (100, 150, -100); break; - case 'L': +/* case 'L': g_HillShading = !g_HillShading; - break; + break;*/ // tile selection case SDLK_DOWN: if(++SelTX > 15) - if(SelPX == NUM_PATCHES_PER_SIDE-1) + if(SelPX == g_Terrain.GetPatchesPerSide()-1) SelTX = 15; else SelTX = 0, SelPX++; @@ -180,7 +174,7 @@ bool terr_handler(const SDL_Event& ev) break; case SDLK_RIGHT: if(++SelTY > 15) - if(SelPY == NUM_PATCHES_PER_SIDE-1) + if(SelPY == g_Terrain.GetPatchesPerSide()-1) SelTY = 15; else SelTY = 0, SelPY++; @@ -197,8 +191,8 @@ bool terr_handler(const SDL_Event& ev) case SDLK_KP0: { - CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX]; - if (!MPatch->Tex2) + CMiniPatch *MPatch = &g_Terrain.GetPatch(SelPY, SelPX)->m_MiniPatches[SelTY][SelTX]; + /*if (!MPatch->Tex2) { MPatch->m_AlphaMap = AlphaMaps[g_TransTexCounter]; MPatch->Tex2 = BaseTexs[g_SecTexCounter]; @@ -207,13 +201,13 @@ bool terr_handler(const SDL_Event& ev) { MPatch->Tex2 = 0; MPatch->m_AlphaMap = 0; - } + }*/ break; } - case SDLK_KP1: + /*case SDLK_KP1: { - CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX]; + CMiniPatch *MPatch = &g_Terrain.GetPatch(SelPY, SelPX)->m_MiniPatches[SelTY][SelTX]; g_BaseTexCounter++; if (g_BaseTexCounter > 4) @@ -243,7 +237,7 @@ bool terr_handler(const SDL_Event& ev) { CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX]; - if (MPatch->/*m_pTransitionTexture*/m_AlphaMap) + if (MPatch->m_AlphaMap) { g_TransTexCounter++; if (g_TransTexCounter >= NUM_ALPHA_MAPS) @@ -253,7 +247,7 @@ bool terr_handler(const SDL_Event& ev) } break; - } + }*/ } } @@ -267,32 +261,61 @@ bool terr_handler(const SDL_Event& ev) void InitScene () { // setup default lighting environment - g_LightEnv.m_SunColor=RGBColor(0.75f,0.70f,0.65f); - g_LightEnv.m_Rotation=270; - g_LightEnv.m_Elevation=DEGTORAD(30); - g_LightEnv.m_TerrainAmbientColor=RGBColor(0.0f,0.0f,0.0f); + g_LightEnv.m_SunColor=RGBColor(1,1,1); + g_LightEnv.m_Rotation=DEGTORAD(270); + g_LightEnv.m_Elevation=DEGTORAD(45); + g_LightEnv.m_TerrainAmbientColor=RGBColor(0,0,0); + g_LightEnv.m_UnitsAmbientColor=RGBColor(0.4f,0.4f,0.4f); + g_Renderer.SetLightEnv(&g_LightEnv); - g_Terrain.Load("terrain.raw"); - - for (int pj=0; pj 0) { - for (int pi=0; pi0) { + if (g_TexMan.m_TerrainTextures[0].m_Textures.size()) { + texture=g_TexMan.m_TerrainTextures[0].m_Textures[0]; + } + } + + // cover entire terrain with default texture + u32 patchesPerSide=g_Terrain.GetPatchesPerSide(); + for (uint pj=0; pjm_MiniPatches[j][i].Tex1=texture ? texture->m_Handle :0; } } } } - // calculate terrain lighting - g_Terrain.CalcLighting(g_LightEnv); - g_Camera.SetProjection (1, 1000, DEGTORAD(20)); g_Camera.m_Orientation.SetXRotation(DEGTORAD(30)); g_Camera.m_Orientation.RotateY(DEGTORAD(-45)); @@ -304,75 +327,29 @@ void InitScene () void InitResources() { - int i; - char* base_fns[] = - { - "Base1.bmp", - "Base2.bmp", - "Base3.bmp", - "Base4.bmp", - "Base5.bmp" - }; - - for(i = 0; i < 5; i++) - { - BaseTexs[i] = tex_load(base_fns[i]); - tex_upload(BaseTexs[i], GL_LINEAR_MIPMAP_LINEAR); - } - - -int cnt; -#if 1 - - char* fns[NUM_ALPHA_MAPS] = { -"blendcircle.raw", -"blendcorner.raw", -"blendedge.raw", -"blendedgecorner.raw", -"blendedgetwocorners.raw", -"blendfourcorners.raw", -"blendlshape.raw", -"blendlshapecorner.raw", -"blendthreecorners.raw", -"blendtwocorners.raw", -"blendtwoedges.raw", -"blendtwooppositecorners.raw", -"blendushape.raw" - }; - -/* -//for(i = 0; i < NUM_ALPHA_MAPS;i++) -i=5; -{ -FILE* f = fopen(fns[i],"rb"); -u8 buf[5000],buf2[5000]; -fread(buf,5000,1,f); -fclose(f); -for(int j = 0; j < 1024; j++) -buf2[2*j] = buf2[2*j+1] = buf[j]; -f=fopen(fns[i],"wb"); -fwrite(buf2,2048,1,f); -fclose(f); -} -/**/ -cnt=13; +#ifndef _WIN32 + g_TexMan.AddTextureType("grass"); + g_TexMan.AddTexture("Base1.tga", 0); #else - - char* fns[NUM_ALPHA_MAPS] = { -"Transition1.bmp", -"Transition2.bmp", -"Transition3.bmp", -"Transition4.bmp", -"Transition5.bmp", - }; -cnt=5; + g_TexMan.LoadTerrainTextures(); #endif -for(i = 0; i < cnt; i++) -{ - AlphaMaps[i] = tex_load(fns[i]); - tex_upload(AlphaMaps[i], GL_LINEAR, GL_INTENSITY4); -} + const char* fns[CRenderer::NumAlphaMaps] = { + "art/textures/terrain/alphamaps/special/blendcircle.png", + "art/textures/terrain/alphamaps/special/blendlshape.png", + "art/textures/terrain/alphamaps/special/blendedge.png", + "art/textures/terrain/alphamaps/special/blendedgecorner.png", + "art/textures/terrain/alphamaps/special/blendedgetwocorners.png", + "art/textures/terrain/alphamaps/special/blendfourcorners.png", + "art/textures/terrain/alphamaps/special/blendtwooppositecorners.png", + "art/textures/terrain/alphamaps/special/blendlshapecorner.png", + "art/textures/terrain/alphamaps/special/blendtwocorners.png", + "art/textures/terrain/alphamaps/special/blendcorner.png", + "art/textures/terrain/alphamaps/special/blendtwoedges.png", + "art/textures/terrain/alphamaps/special/blendthreecorners.png", + "art/textures/terrain/alphamaps/special/blendushape.png", + "art/textures/terrain/alphamaps/special/blendbad.png" + }; + assert(g_Renderer.LoadAlphaMaps(fns)); } -