From 3b1395d80b896603a67a2d025e73ed5dfdcfc449 Mon Sep 17 00:00:00 2001 From: Ykkrosh Date: Wed, 9 Feb 2005 23:19:48 +0000 Subject: [PATCH] Optimised game-loading, by not reading terrain textures or calculating bounding boxes when not necessary; maps load about twenty seconds faster (at least in Debug mode). Also fixed possible minor bug (FLT_MIN vs -FLT_MAX) and other trivial things. This was SVN commit r1917. --- source/graphics/Model.cpp | 46 +++++-- source/graphics/Model.h | 5 +- source/graphics/ObjectEntry.cpp | 3 - source/graphics/Patch.cpp | 2 +- source/graphics/RenderableObject.h | 22 +++- source/graphics/Terrain.cpp | 2 +- source/graphics/TextureEntry.h | 3 + source/graphics/TextureManager.cpp | 6 +- source/maths/Bound.cpp | 180 ++++++++++++++------------- source/maths/Bound.h | 13 +- source/maths/Vector3D.cpp | 39 +----- source/maths/Vector3D.h | 4 +- source/renderer/ModelRData.cpp | 2 +- source/simulation/PathfindSparse.cpp | 2 +- 14 files changed, 175 insertions(+), 154 deletions(-) diff --git a/source/graphics/Model.cpp b/source/graphics/Model.cpp index 1c3c896eee..8560bb45c7 100755 --- a/source/graphics/Model.cpp +++ b/source/graphics/Model.cpp @@ -125,6 +125,17 @@ static CVector3D SkinPoint(const CVector3D& pos,const SVertexBlend& blend, // CalcBound: calculate the world space bounds of this model void CModel::CalcBounds() { + // Need to calculate the object bounds first, if that hasn't already been done + if (! m_Anim) + CalcObjectBounds(); + else + { + if (m_Anim->m_ObjectBounds.IsEmpty()) + CalcAnimatedObjectBound(m_Anim->m_AnimDef, m_Anim->m_ObjectBounds); + assert(! m_Anim->m_ObjectBounds.IsEmpty()); // (if this happens, it'll be recalculating the bounds every time) + m_ObjectBounds = m_Anim->m_ObjectBounds; + } + m_ObjectBounds.Transform(GetTransform(),m_Bounds); } @@ -148,13 +159,24 @@ void CModel::CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result) { result.SetEmpty(); - CSkeletonAnim dummyanim; - dummyanim.m_AnimDef=anim; - if (!SetAnimation(&dummyanim)) return; + // Set the current animation on which to perform calculations (if it's necessary) + if (anim != m_Anim->m_AnimDef) + { + CSkeletonAnim dummyanim; + dummyanim.m_AnimDef=anim; + if (!SetAnimation(&dummyanim)) return; + } int numverts=m_pModelDef->GetNumVertices(); SModelVertex* verts=m_pModelDef->GetVertices(); - + + // Remove any transformations, so that we calculate the bounding box + // at the origin. The box is later re-transformed onto the object, without + // having to recalculate the size of the box. + CMatrix3D transform, oldtransform = GetTransform(); + transform.SetIdentity(); + SetTransform(transform); + // iterate through every frame of the animation for (uint j=0;jGetNumFrames();j++) { // extend bounds by vertex positions at the frame @@ -166,6 +188,8 @@ void CModel::CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result) m_AnimTime+=anim->GetFrameTime(); m_BoneMatricesValid=false; } + + SetTransform(oldtransform); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -179,7 +203,8 @@ CSkeletonAnim* CModel::BuildAnimation(const char* filename,float speed) CSkeletonAnim* anim=new CSkeletonAnim; anim->m_AnimDef=def; anim->m_Speed=speed; - CalcAnimatedObjectBound(def,anim->m_ObjectBounds); + anim->m_ObjectBounds.SetEmpty(); + InvalidateBounds(); return anim; } @@ -268,13 +293,15 @@ bool CModel::SetAnimation(CSkeletonAnim* anim, bool once) return false; } - if (anim->m_AnimDef->GetNumKeys()!=m_pModelDef->GetNumBones()) { - // mismatch between models skeleton and animations skeleton + if (m_Anim->m_AnimDef->GetNumKeys()!=m_pModelDef->GetNumBones()) { + // mismatch between model's skeleton and animation's skeleton return false; } - // update object bounds to the bounds when given animation applied - m_ObjectBounds=m_Anim->m_ObjectBounds; + // reset the cached bounds when the animation is changed + m_ObjectBounds.SetEmpty(); + InvalidateBounds(); + // start anim from beginning m_AnimTime=0; } @@ -348,6 +375,7 @@ void CModel::SetTransform(const CMatrix3D& transform) // call base class to set transform on this object CRenderableObject::SetTransform(transform); m_BoneMatricesValid=false; + InvalidateBounds(); // now set transforms on props const CMatrix3D* bonematrices=GetBoneMatrices(); diff --git a/source/graphics/Model.h b/source/graphics/Model.h index 4237e676fe..b16486c886 100755 --- a/source/graphics/Model.h +++ b/source/graphics/Model.h @@ -85,8 +85,6 @@ public: void CalcObjectBounds(); // calculate bounds encompassing all vertex positions for given animation void CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result); - // return object space bounds - const CBound& GetObjectBounds() const { return m_ObjectBounds; } // set transform of this object, and recurse down into props to update their world space transform void SetTransform(const CMatrix3D& transform); @@ -134,7 +132,8 @@ private: // pointer to the model's raw 3d data CModelDefPtr m_pModelDef; // object space bounds of model - accounts for bounds of all possible animations - // that can play on a model + // that can play on a model. Not always up-to-date - currently CalcBounds() + // updates it when necessary. CBound m_ObjectBounds; // animation currently playing on this model, if any CSkeletonAnim* m_Anim; diff --git a/source/graphics/ObjectEntry.cpp b/source/graphics/ObjectEntry.cpp index af9f8987a0..9a86653044 100755 --- a/source/graphics/ObjectEntry.cpp +++ b/source/graphics/ObjectEntry.cpp @@ -135,9 +135,6 @@ bool CObjectEntry::BuildModel() m_Model->SetFlags(m_Model->GetFlags()|MODELFLAG_CASTSHADOWS); } - // build world space bounds - m_Model->CalcBounds(); - // replace any units using old model to now use new model; also reprop models, if necessary // FIXME, RC - ugh, doesn't recurse correctly through props const std::vector& units=g_UnitMan.GetUnits(); diff --git a/source/graphics/Patch.cpp b/source/graphics/Patch.cpp index 90a053844b..7f7a8663bb 100755 --- a/source/graphics/Patch.cpp +++ b/source/graphics/Patch.cpp @@ -42,7 +42,7 @@ void CPatch::Initialize(CTerrain* parent,u32 x,u32 z) } } - CalcBounds(); + InvalidateBounds(); } /////////////////////////////////////////////////////////////////////////////// diff --git a/source/graphics/RenderableObject.h b/source/graphics/RenderableObject.h index 5c92190ccf..3aa4740c8f 100755 --- a/source/graphics/RenderableObject.h +++ b/source/graphics/RenderableObject.h @@ -42,7 +42,7 @@ class CRenderableObject { public: // constructor - CRenderableObject() : m_RenderData(0) { + CRenderableObject() : m_RenderData(0), m_BoundsValid(false) { m_Transform.SetIdentity(); } // destructor @@ -55,8 +55,8 @@ public: m_Transform.GetInverse(m_InvTransform); // normal recalculation likely required on transform change; flag it SetDirty(RENDERDATA_UPDATE_VERTICES); - // rebuild world space bounds - CalcBounds(); + // need to rebuild world space bounds + InvalidateBounds(); } // get object to world space transform const CMatrix3D& GetTransform() const { return m_Transform; } @@ -71,10 +71,18 @@ public: // calculate (and store in m_Bounds) the world space bounds of this object // - must be implemented by all concrete subclasses - virtual void CalcBounds() = 0; + virtual void CalcBounds() = 0; // return world space bounds of this object - const CBound& GetBounds() const { return m_Bounds; } + const CBound& GetBounds() { + if (! m_BoundsValid) { + CalcBounds(); + m_BoundsValid = true; + } + return m_Bounds; + } + + void InvalidateBounds() { m_BoundsValid = false; } // set the object renderdata // TODO,RC 10/04/04 - need to delete existing renderdata here, or can we @@ -98,6 +106,10 @@ protected: CMatrix3D m_InvTransform; // object renderdata CRenderData* m_RenderData; + +private: + // remembers whether m_bounds needs to be recalculated + bool m_BoundsValid; }; #endif diff --git a/source/graphics/Terrain.cpp b/source/graphics/Terrain.cpp index 0022f1ae68..373b20b029 100755 --- a/source/graphics/Terrain.cpp +++ b/source/graphics/Terrain.cpp @@ -326,7 +326,7 @@ void CTerrain::SetHeightMap(u16* heightmap) for (u32 j=0;jCalcBounds(); + patch->InvalidateBounds(); patch->SetDirty(RENDERDATA_UPDATE_VERTICES); } } diff --git a/source/graphics/TextureEntry.h b/source/graphics/TextureEntry.h index 5c923af532..c740a9c081 100755 --- a/source/graphics/TextureEntry.h +++ b/source/graphics/TextureEntry.h @@ -34,6 +34,9 @@ public: // accessor - return texture type int GetType() const { return m_Type; } + // returns whether this texture-entry has loaded any data yet + bool IsLoaded() { return (m_Handle!=-1); } + private: // load texture from file void LoadTexture(); diff --git a/source/graphics/TextureManager.cpp b/source/graphics/TextureManager.cpp index 789f49294c..4fa1e41536 100755 --- a/source/graphics/TextureManager.cpp +++ b/source/graphics/TextureManager.cpp @@ -57,7 +57,11 @@ CTextureEntry* CTextureManager::FindTexture(Handle handle) for (uint k=0;kGetHandle()) { + // Don't bother looking at textures that haven't been loaded yet - since + // the caller has given us a Handle to the texture, it must be loaded. + // (This matters because GetHandle would load the texture, even though + // there's no need to.) + if (ttype.m_Textures[i]->IsLoaded() && handle==ttype.m_Textures[i]->GetHandle()) { return ttype.m_Textures[i]; } } diff --git a/source/maths/Bound.cpp b/source/maths/Bound.cpp index bc620c413f..f739c75351 100755 --- a/source/maths/Bound.cpp +++ b/source/maths/Bound.cpp @@ -47,90 +47,98 @@ CBound& CBound::operator+=(const CVector3D& pt) // otherwise // note: incoming ray direction must be normalised bool CBound::RayIntersect(const CVector3D& origin,const CVector3D& dir, - float& tmin,float& tmax) const + float& tmin,float& tmax) const { float t1,t2; - float tnear,tfar; + float tnear,tfar; - if (dir[0]==0) { - if (origin[0]m_Data[1][0]) - return false; - else { - tnear=(float) FLT_MIN; - tfar=(float) FLT_MAX; - } - } else { - t1=(m_Data[0][0]-origin[0])/dir[0]; - t2=(m_Data[1][0]-origin[0])/dir[0]; - - if (dir[0]<0) { - tnear = t2; - tfar = t1; - } else { - tnear = t1; - tfar = t2; - } - - if (tfar<0) - return false; - } - - if (dir[1]==0 && (origin[1]m_Data[1][1])) - return false; - else { - t1=(m_Data[0][1]-origin[1])/dir[1]; - t2=(m_Data[1][1]-origin[1])/dir[1]; - - if (dir[1]<0) { - if (t2>tnear) - tnear = t2; - if (t1tnear) - tnear = t1; - if (t2tfar || tfar<0) + if (dir[0]==0) { + if (origin[0]m_Data[1][0]) return false; - } + else { + tnear=(float) -FLT_MAX; + tfar=(float) FLT_MAX; + } + } else { + t1=(m_Data[0][0]-origin[0])/dir[0]; + t2=(m_Data[1][0]-origin[0])/dir[0]; + + if (dir[0]<0) { + tnear = t2; + tfar = t1; + } else { + tnear = t1; + tfar = t2; + } + + if (tfar<0) + return false; + } + + if (dir[1]==0 && (origin[1]m_Data[1][1])) + return false; + else { + t1=(m_Data[0][1]-origin[1])/dir[1]; + t2=(m_Data[1][1]-origin[1])/dir[1]; + + if (dir[1]<0) { + if (t2>tnear) + tnear = t2; + if (t1tnear) + tnear = t1; + if (t2tfar || tfar<0) + return false; + } + + if (dir[2]==0 && (origin[2]m_Data[1][2])) + return false; + else { + t1=(m_Data[0][2]-origin[2])/dir[2]; + t2=(m_Data[1][2]-origin[2])/dir[2]; - if (dir[2]==0 && (origin[2]m_Data[1][2])) - return false; - else { - t1=(m_Data[0][2]-origin[2])/dir[2]; - t2=(m_Data[1][2]-origin[2])/dir[2]; - if (dir[2]<0) { - if (t2>tnear) - tnear = t2; - if (t1tnear) - tnear = t1; - if (t2tnear) + tnear = t2; + if (t1tnear) + tnear = t1; + if (t2tfar || tfar<0) - return false; - } + if (tnear>tfar || tfar<0) + return false; + } - tmin=tnear; - tmax=tfar; + tmin=tnear; + tmax=tfar; - return true; + return true; } /////////////////////////////////////////////////////////////////////////////// // SetEmpty: initialise this bound as empty void CBound::SetEmpty() { - m_Data[0]=CVector3D(FLT_MAX,FLT_MAX,FLT_MAX); - m_Data[1]=CVector3D(FLT_MIN,FLT_MIN,FLT_MIN); + m_Data[0]=CVector3D( FLT_MAX, FLT_MAX, FLT_MAX); + m_Data[1]=CVector3D(-FLT_MAX,-FLT_MAX,-FLT_MAX); +} + +/////////////////////////////////////////////////////////////////////////////// +// IsEmpty: tests whether this bound is empty +bool CBound::IsEmpty() +{ + return (m_Data[0].X == FLT_MAX && m_Data[0].Y == FLT_MAX && m_Data[0].Z == FLT_MAX + && m_Data[1].X == -FLT_MAX && m_Data[1].Y == -FLT_MAX && m_Data[1].Z == -FLT_MAX); } /////////////////////////////////////////////////////////////////////////////// @@ -141,23 +149,23 @@ 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(i,3); + for (int i=0;i<3;++i) { + // handle translation + result[0][i]=result[1][i]=m(i,3); - // 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(j,i)*m_Data[0][j]; - float b=m(j,i)*m_Data[1][j]; + // 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(j,i)*m_Data[0][j]; + float b=m(j,i)*m_Data[1][j]; - if (aGetTexture(),GL_CLAMP_TO_EDGE); // setup model render flags /*if (g_Renderer.IsTextureTransparent(m_Model->GetTexture())) { diff --git a/source/simulation/PathfindSparse.cpp b/source/simulation/PathfindSparse.cpp index 596b8e1ffe..76502c3d61 100755 --- a/source/simulation/PathfindSparse.cpp +++ b/source/simulation/PathfindSparse.cpp @@ -47,7 +47,7 @@ bool sparsePathTree::slice() if( len == 0.0f ) { - // Too wierd. (Heavy traffic, obstacles in positions leading to this degenerate state. + // Too weird. (Heavy traffic, obstacles in positions leading to this degenerate state. type = SPF_IMPOSSIBLE; return( true ); }