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.
This commit is contained in:
Ykkrosh 2005-02-09 23:19:48 +00:00
parent 614e523c89
commit 3b1395d80b
14 changed files with 175 additions and 154 deletions

View File

@ -125,6 +125,17 @@ static CVector3D SkinPoint(const CVector3D& pos,const SVertexBlend& blend,
// CalcBound: calculate the world space bounds of this model // CalcBound: calculate the world space bounds of this model
void CModel::CalcBounds() 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); m_ObjectBounds.Transform(GetTransform(),m_Bounds);
} }
@ -148,13 +159,24 @@ void CModel::CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result)
{ {
result.SetEmpty(); result.SetEmpty();
CSkeletonAnim dummyanim; // Set the current animation on which to perform calculations (if it's necessary)
dummyanim.m_AnimDef=anim; if (anim != m_Anim->m_AnimDef)
if (!SetAnimation(&dummyanim)) return; {
CSkeletonAnim dummyanim;
dummyanim.m_AnimDef=anim;
if (!SetAnimation(&dummyanim)) return;
}
int numverts=m_pModelDef->GetNumVertices(); int numverts=m_pModelDef->GetNumVertices();
SModelVertex* verts=m_pModelDef->GetVertices(); 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 // iterate through every frame of the animation
for (uint j=0;j<anim->GetNumFrames();j++) { for (uint j=0;j<anim->GetNumFrames();j++) {
// extend bounds by vertex positions at the frame // extend bounds by vertex positions at the frame
@ -166,6 +188,8 @@ void CModel::CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result)
m_AnimTime+=anim->GetFrameTime(); m_AnimTime+=anim->GetFrameTime();
m_BoneMatricesValid=false; m_BoneMatricesValid=false;
} }
SetTransform(oldtransform);
} }
///////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -179,7 +203,8 @@ CSkeletonAnim* CModel::BuildAnimation(const char* filename,float speed)
CSkeletonAnim* anim=new CSkeletonAnim; CSkeletonAnim* anim=new CSkeletonAnim;
anim->m_AnimDef=def; anim->m_AnimDef=def;
anim->m_Speed=speed; anim->m_Speed=speed;
CalcAnimatedObjectBound(def,anim->m_ObjectBounds); anim->m_ObjectBounds.SetEmpty();
InvalidateBounds();
return anim; return anim;
} }
@ -268,13 +293,15 @@ bool CModel::SetAnimation(CSkeletonAnim* anim, bool once)
return false; return false;
} }
if (anim->m_AnimDef->GetNumKeys()!=m_pModelDef->GetNumBones()) { if (m_Anim->m_AnimDef->GetNumKeys()!=m_pModelDef->GetNumBones()) {
// mismatch between models skeleton and animations skeleton // mismatch between model's skeleton and animation's skeleton
return false; return false;
} }
// update object bounds to the bounds when given animation applied // reset the cached bounds when the animation is changed
m_ObjectBounds=m_Anim->m_ObjectBounds; m_ObjectBounds.SetEmpty();
InvalidateBounds();
// start anim from beginning // start anim from beginning
m_AnimTime=0; m_AnimTime=0;
} }
@ -348,6 +375,7 @@ void CModel::SetTransform(const CMatrix3D& transform)
// call base class to set transform on this object // call base class to set transform on this object
CRenderableObject::SetTransform(transform); CRenderableObject::SetTransform(transform);
m_BoneMatricesValid=false; m_BoneMatricesValid=false;
InvalidateBounds();
// now set transforms on props // now set transforms on props
const CMatrix3D* bonematrices=GetBoneMatrices(); const CMatrix3D* bonematrices=GetBoneMatrices();

View File

@ -85,8 +85,6 @@ public:
void CalcObjectBounds(); void CalcObjectBounds();
// calculate bounds encompassing all vertex positions for given animation // calculate bounds encompassing all vertex positions for given animation
void CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result); 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 // set transform of this object, and recurse down into props to update their world space transform
void SetTransform(const CMatrix3D& transform); void SetTransform(const CMatrix3D& transform);
@ -134,7 +132,8 @@ private:
// pointer to the model's raw 3d data // pointer to the model's raw 3d data
CModelDefPtr m_pModelDef; CModelDefPtr m_pModelDef;
// object space bounds of model - accounts for bounds of all possible animations // 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; CBound m_ObjectBounds;
// animation currently playing on this model, if any // animation currently playing on this model, if any
CSkeletonAnim* m_Anim; CSkeletonAnim* m_Anim;

View File

@ -135,9 +135,6 @@ bool CObjectEntry::BuildModel()
m_Model->SetFlags(m_Model->GetFlags()|MODELFLAG_CASTSHADOWS); 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 // 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 // FIXME, RC - ugh, doesn't recurse correctly through props
const std::vector<CUnit*>& units=g_UnitMan.GetUnits(); const std::vector<CUnit*>& units=g_UnitMan.GetUnits();

View File

@ -42,7 +42,7 @@ void CPatch::Initialize(CTerrain* parent,u32 x,u32 z)
} }
} }
CalcBounds(); InvalidateBounds();
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -42,7 +42,7 @@ class CRenderableObject
{ {
public: public:
// constructor // constructor
CRenderableObject() : m_RenderData(0) { CRenderableObject() : m_RenderData(0), m_BoundsValid(false) {
m_Transform.SetIdentity(); m_Transform.SetIdentity();
} }
// destructor // destructor
@ -55,8 +55,8 @@ public:
m_Transform.GetInverse(m_InvTransform); m_Transform.GetInverse(m_InvTransform);
// normal recalculation likely required on transform change; flag it // normal recalculation likely required on transform change; flag it
SetDirty(RENDERDATA_UPDATE_VERTICES); SetDirty(RENDERDATA_UPDATE_VERTICES);
// rebuild world space bounds // need to rebuild world space bounds
CalcBounds(); InvalidateBounds();
} }
// get object to world space transform // get object to world space transform
const CMatrix3D& GetTransform() const { return m_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 // calculate (and store in m_Bounds) the world space bounds of this object
// - must be implemented by all concrete subclasses // - must be implemented by all concrete subclasses
virtual void CalcBounds() = 0; virtual void CalcBounds() = 0;
// return world space bounds of this object // 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 // set the object renderdata
// TODO,RC 10/04/04 - need to delete existing renderdata here, or can we // TODO,RC 10/04/04 - need to delete existing renderdata here, or can we
@ -98,6 +106,10 @@ protected:
CMatrix3D m_InvTransform; CMatrix3D m_InvTransform;
// object renderdata // object renderdata
CRenderData* m_RenderData; CRenderData* m_RenderData;
private:
// remembers whether m_bounds needs to be recalculated
bool m_BoundsValid;
}; };
#endif #endif

View File

@ -326,7 +326,7 @@ void CTerrain::SetHeightMap(u16* heightmap)
for (u32 j=0;j<m_MapSizePatches;j++) { for (u32 j=0;j<m_MapSizePatches;j++) {
for (u32 i=0;i<m_MapSizePatches;i++) { for (u32 i=0;i<m_MapSizePatches;i++) {
CPatch* patch=GetPatch(i,j); CPatch* patch=GetPatch(i,j);
patch->CalcBounds(); patch->InvalidateBounds();
patch->SetDirty(RENDERDATA_UPDATE_VERTICES); patch->SetDirty(RENDERDATA_UPDATE_VERTICES);
} }
} }

View File

@ -34,6 +34,9 @@ public:
// accessor - return texture type // accessor - return texture type
int GetType() const { return m_Type; } int GetType() const { return m_Type; }
// returns whether this texture-entry has loaded any data yet
bool IsLoaded() { return (m_Handle!=-1); }
private: private:
// load texture from file // load texture from file
void LoadTexture(); void LoadTexture();

View File

@ -57,7 +57,11 @@ CTextureEntry* CTextureManager::FindTexture(Handle handle)
for (uint k=0;k<m_TerrainTextures.size();k++) { for (uint k=0;k<m_TerrainTextures.size();k++) {
STextureType& ttype=m_TerrainTextures[k]; STextureType& ttype=m_TerrainTextures[k];
for (uint i=0;i<ttype.m_Textures.size();i++) { for (uint i=0;i<ttype.m_Textures.size();i++) {
if (handle==ttype.m_Textures[i]->GetHandle()) { // 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]; return ttype.m_Textures[i];
} }
} }

View File

@ -47,90 +47,98 @@ CBound& CBound::operator+=(const CVector3D& pt)
// otherwise // otherwise
// note: incoming ray direction must be normalised // note: incoming ray direction must be normalised
bool CBound::RayIntersect(const CVector3D& origin,const CVector3D& dir, bool CBound::RayIntersect(const CVector3D& origin,const CVector3D& dir,
float& tmin,float& tmax) const float& tmin,float& tmax) const
{ {
float t1,t2; float t1,t2;
float tnear,tfar; float tnear,tfar;
if (dir[0]==0) { if (dir[0]==0) {
if (origin[0]<m_Data[0][0] || origin[0]>m_Data[1][0]) if (origin[0]<m_Data[0][0] || 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[0][1] || 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 (t1<tfar)
tfar = t1;
} else {
if (t1>tnear)
tnear = t1;
if (t2<tfar)
tfar = t2;
}
if (tnear>tfar || tfar<0)
return false; 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[0][1] || 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 (t1<tfar)
tfar = t1;
} else {
if (t1>tnear)
tnear = t1;
if (t2<tfar)
tfar = t2;
}
if (tnear>tfar || tfar<0)
return false;
}
if (dir[2]==0 && (origin[2]<m_Data[0][2] || 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[0][2] || 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 (dir[2]<0) {
if (t2>tnear) if (t2>tnear)
tnear = t2; tnear = t2;
if (t1<tfar) if (t1<tfar)
tfar = t1; tfar = t1;
} else { } else {
if (t1>tnear) if (t1>tnear)
tnear = t1; tnear = t1;
if (t2<tfar) if (t2<tfar)
tfar = t2; tfar = t2;
} }
if (tnear>tfar || tfar<0) if (tnear>tfar || tfar<0)
return false; return false;
} }
tmin=tnear; tmin=tnear;
tmax=tfar; tmax=tfar;
return true; return true;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// SetEmpty: initialise this bound as empty // SetEmpty: initialise this bound as empty
void CBound::SetEmpty() void CBound::SetEmpty()
{ {
m_Data[0]=CVector3D(FLT_MAX,FLT_MAX,FLT_MAX); m_Data[0]=CVector3D( FLT_MAX, FLT_MAX, FLT_MAX);
m_Data[1]=CVector3D(FLT_MIN,FLT_MIN,FLT_MIN); 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); assert(this!=&result);
for (int i=0;i<3;++i) { for (int i=0;i<3;++i) {
// handle translation // handle translation
result[0][i]=result[1][i]=m(i,3); result[0][i]=result[1][i]=m(i,3);
// Now find the extreme points by considering the product of the // Now find the extreme points by considering the product of the
// min and max with each component of matrix // min and max with each component of matrix
for(int j=0;j<3;j++) { for(int j=0;j<3;j++) {
float a=m(j,i)*m_Data[0][j]; float a=m(j,i)*m_Data[0][j];
float b=m(j,i)*m_Data[1][j]; float b=m(j,i)*m_Data[1][j];
if (a<b) { if (a<b) {
result[0][i]+=a; result[0][i]+=a;
result[1][i]+=b; result[1][i]+=b;
} else { } else {
result[0][i]+=b; result[0][i]+=b;
result[1][i]+=a; result[1][i]+=a;
} }
} }
} }
} }

View File

@ -18,22 +18,23 @@
class CBound class CBound
{ {
public: public:
CBound() {} CBound() {}
CBound(const CVector3D& min,const CVector3D& max) { CBound(const CVector3D& min,const CVector3D& max) {
m_Data[0]=min; m_Data[1]=max; m_Data[0]=min; m_Data[1]=max;
} }
void Transform(const CMatrix3D& m,CBound& result) const; void Transform(const CMatrix3D& m,CBound& result) const;
CVector3D& operator[](int index) { return m_Data[index]; } CVector3D& operator[](int index) { return m_Data[index]; }
const CVector3D& operator[](int index) const { return m_Data[index]; } const CVector3D& operator[](int index) const { return m_Data[index]; }
void SetEmpty(); void SetEmpty();
bool IsEmpty();
CBound& operator+=(const CBound& b); CBound& operator+=(const CBound& b);
CBound& operator+=(const CVector3D& pt); CBound& operator+=(const CVector3D& pt);
bool RayIntersect(const CVector3D& origin,const CVector3D& dir,float& tmin,float& tmax) const; bool RayIntersect(const CVector3D& origin,const CVector3D& dir,float& tmin,float& tmax) const;
// return the volume of this bounding box // return the volume of this bounding box
float GetVolume() const { float GetVolume() const {
@ -47,7 +48,7 @@ public:
} }
private: private:
CVector3D m_Data[2]; CVector3D m_Data[2];
}; };
////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -13,13 +13,6 @@
#include "Vector3D.h" #include "Vector3D.h"
CVector3D::CVector3D (float x, float y, float z)
{
X = x;
Y = y;
Z = z;
}
int CVector3D::operator ! () const int CVector3D::operator ! () const
{ {
if (X != 0.0f || if (X != 0.0f ||
@ -34,13 +27,7 @@ int CVector3D::operator ! () const
//vector addition //vector addition
CVector3D CVector3D::operator + (const CVector3D &vector) const CVector3D CVector3D::operator + (const CVector3D &vector) const
{ {
CVector3D Temp; return CVector3D(X+vector.X, Y+vector.Y, Z+vector.Z);
Temp.X = X + vector.X;
Temp.Y = Y + vector.Y;
Temp.Z = Z + vector.Z;
return Temp;
} }
//vector addition/assignment //vector addition/assignment
@ -56,25 +43,13 @@ CVector3D &CVector3D::operator += (const CVector3D &vector)
//vector subtraction //vector subtraction
CVector3D CVector3D::operator - (const CVector3D &vector) const CVector3D CVector3D::operator - (const CVector3D &vector) const
{ {
CVector3D Temp; return CVector3D(X-vector.X, Y-vector.Y, Z-vector.Z);
Temp.X = X - vector.X;
Temp.Y = Y - vector.Y;
Temp.Z = Z - vector.Z;
return Temp;
} }
//vector negation //vector negation
CVector3D CVector3D::operator-() const CVector3D CVector3D::operator-() const
{ {
CVector3D Temp; return CVector3D(-X, -Y, -Z);
Temp.X = -X;
Temp.Y = -Y;
Temp.Z = -Z;
return Temp;
} }
//vector subtrcation/assignment //vector subtrcation/assignment
CVector3D &CVector3D::operator -= (const CVector3D &vector) CVector3D &CVector3D::operator -= (const CVector3D &vector)
@ -89,13 +64,7 @@ CVector3D &CVector3D::operator -= (const CVector3D &vector)
//scalar multiplication //scalar multiplication
CVector3D CVector3D::operator * (float value) const CVector3D CVector3D::operator * (float value) const
{ {
CVector3D Temp; return CVector3D(X*value, Y*value, Z*value);
Temp.X = X * value;
Temp.Y = Y * value;
Temp.Z = Z * value;
return Temp;
} }
//scalar multiplication/assignment //scalar multiplication/assignment

View File

@ -22,8 +22,8 @@ class CVector3D
float X, Y, Z; float X, Y, Z;
public: public:
CVector3D () { X = 0.0f; Y = 0.0f; Z = 0.0f; } CVector3D () : X(0.0f), Y(0.0f), Z(0.0f) {}
CVector3D (float x, float y, float z); CVector3D (float x, float y, float z) : X(x), Y(y), Z(z) {}
int operator!() const; int operator!() const;

View File

@ -44,7 +44,7 @@ void CModelRData::Build()
// build data // build data
BuildVertices(); BuildVertices();
BuildIndices(); BuildIndices();
// force a texture load on models texture // force a texture load on model's texture
g_Renderer.LoadTexture(m_Model->GetTexture(),GL_CLAMP_TO_EDGE); g_Renderer.LoadTexture(m_Model->GetTexture(),GL_CLAMP_TO_EDGE);
// setup model render flags // setup model render flags
/*if (g_Renderer.IsTextureTransparent(m_Model->GetTexture())) { /*if (g_Renderer.IsTextureTransparent(m_Model->GetTexture())) {

View File

@ -47,7 +47,7 @@ bool sparsePathTree::slice()
if( len == 0.0f ) 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; type = SPF_IMPOSSIBLE;
return( true ); return( true );
} }