From cc2b6afdac686a392a8c8c30f807e0308d54af5a Mon Sep 17 00:00:00 2001 From: notpete Date: Tue, 25 Nov 2003 18:34:05 +0000 Subject: [PATCH] Initial revision. This was SVN commit r96. --- source/terrain/Bound.cpp | 140 ++++++++++++++ source/terrain/Bound.h | 48 +++++ source/terrain/Color.h | 22 +++ source/terrain/LightEnv.h | 44 +++++ source/terrain/Model.cpp | 128 +++++++++++++ source/terrain/Model.h | 44 +++++ source/terrain/ModelDef.cpp | 109 +++++++++++ source/terrain/ModelDef.h | 120 ++++++++++++ source/terrain/ModelFile.cpp | 352 ++++++++++++++++++++++++++++++++++ source/terrain/ModelFile.h | 116 +++++++++++ source/terrain/Quaternion.cpp | 179 +++++++++++++++++ source/terrain/Quaternion.h | 42 ++++ source/terrain/SHCoeffs.cpp | 64 +++++++ source/terrain/SHCoeffs.h | 34 ++++ source/terrain/Texture.h | 35 ++++ source/terrain/Vector4D.h | 111 +++++++++++ 16 files changed, 1588 insertions(+) create mode 100755 source/terrain/Bound.cpp create mode 100755 source/terrain/Bound.h create mode 100755 source/terrain/Color.h create mode 100755 source/terrain/LightEnv.h create mode 100755 source/terrain/Model.cpp create mode 100755 source/terrain/Model.h create mode 100755 source/terrain/ModelDef.cpp create mode 100755 source/terrain/ModelDef.h create mode 100755 source/terrain/ModelFile.cpp create mode 100755 source/terrain/ModelFile.h create mode 100755 source/terrain/Quaternion.cpp create mode 100755 source/terrain/Quaternion.h create mode 100755 source/terrain/SHCoeffs.cpp create mode 100755 source/terrain/SHCoeffs.h create mode 100755 source/terrain/Texture.h create mode 100755 source/terrain/Vector4D.h diff --git a/source/terrain/Bound.cpp b/source/terrain/Bound.cpp new file mode 100755 index 0000000000..aba1b64336 --- /dev/null +++ b/source/terrain/Bound.cpp @@ -0,0 +1,140 @@ +//----------------------------------------------------------- +// +// Name: Bound.h +// Last Update: 25/11/03 +// Author: Rich Cross +// Contact: rich@0ad.wildfiregames.com +// +// Description: Basic axis aligned bounding box class +// +//----------------------------------------------------------- + +// necessary includes +#include +#include "Bound.h" + +//----------------------------------------------------------- +// operator+=: extend this bound to include given bound +//----------------------------------------------------------- +CBound& CBound::operator+=(const CBound& b) +{ + for (int i=0;i<3;++i) { + if (b[0][i]m_Data[1][i]) + m_Data[1][i]=b[1][i]; + } + + return *this; +} + +//----------------------------------------------------------- +// operator+=: extend this bound to include given point +//----------------------------------------------------------- +CBound& CBound::operator+=(const CVector3D& pt) +{ + for (int i=0;i<3;++i) { + if (pt[i]m_Data[1][i]) + m_Data[1][i]=pt[i]; + } + + return *this; +} + +//----------------------------------------------------------- +// RayIntersect: intersect ray with this bound; return true +// if ray hits (and store entry and exit times), or false +// otherwise +// note: incoming ray direction must be normalised +//----------------------------------------------------------- +bool CBound::RayIntersect(const CVector3D& origin,const CVector3D& dir, + float& tmin,float& tmax) const +{ + float t1,t2; + 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) + 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) { + if (t2>tnear) + tnear = t2; + if (t1tnear) + tnear = t1; + if (t2tfar || tfar<0) + return false; + } + + tmin=tnear; + tmax=tfar; + + 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); +} + + diff --git a/source/terrain/Bound.h b/source/terrain/Bound.h new file mode 100755 index 0000000000..23e0e12ebb --- /dev/null +++ b/source/terrain/Bound.h @@ -0,0 +1,48 @@ +//----------------------------------------------------------- +// +// Name: Bound.h +// Last Update: 25/11/03 +// Author: Rich Cross +// Contact: rich@0ad.wildfiregames.com +// +// Description: Basic axis aligned bounding box class +// +//----------------------------------------------------------- + +#ifndef _BOUND_H +#define _BOUND_H + +// necessary includes +#include "Vector3D.h" + +class CBound +{ +public: + CBound() {} + CBound(const CVector3D& min,const CVector3D& max) { + m_Data[0]=min; m_Data[1]=max; + } + + CVector3D& operator[](int index) { return m_Data[index]; } + const CVector3D& operator[](int index) const { return m_Data[index]; } + + void SetEmpty(); + + CBound& operator+=(const CBound& b); + CBound& operator+=(const CVector3D& pt); + + bool RayIntersect(const CVector3D& origin,const CVector3D& dir,float& tmin,float& tmax) const; + + float GetVolume() const { + CVector3D v=m_Data[1]-m_Data[0]; + return v.X*v.Y*v.Z; + } + + +private: + CVector3D m_Data[2]; +}; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +#endif diff --git a/source/terrain/Color.h b/source/terrain/Color.h new file mode 100755 index 0000000000..b2c70f1cee --- /dev/null +++ b/source/terrain/Color.h @@ -0,0 +1,22 @@ +//----------------------------------------------------------- +// +// Name: Color.h +// Last Update: 25/11/03 +// Author: Rich Cross +// Contact: rich@0ad.wildfiregames.com +// +// Description: Definitions for 3 and 4 component floating +// point colors +// +//----------------------------------------------------------- + +#ifndef _COLOR_H +#define _COLOR_H + +#include "Vector3D.h" +#include "Vector4D.h" + +typedef CVector3D RGBColor; +typedef CVector4D RGBAColor; + +#endif diff --git a/source/terrain/LightEnv.h b/source/terrain/LightEnv.h new file mode 100755 index 0000000000..f9072b166e --- /dev/null +++ b/source/terrain/LightEnv.h @@ -0,0 +1,44 @@ +//---------------------------------------------------------------- +// +// Name: LightEnv.h +// Last Update: 25/11/03 +// Author: Rich Cross +// Contact: rich@0ad.wildfiregames.com +// +// Description: class describing current lighting environment - +// at the minute, this is only sunlight and ambient light +// parameters; will be extended to handle dynamic lights at some +// later date +//---------------------------------------------------------------- + + +#ifndef __LIGHTENV_H +#define __LIGHTENV_H + +#include "Color.h" +#include "Vector3D.h" + +class CLightEnv +{ +public: + RGBColor m_SunColor; + float m_Elevation; + float m_Rotation; + RGBColor m_TerrainAmbientColor; + RGBColor m_UnitsAmbientColor; + + // get sun direction from a rotation and elevation; defined such that: + // 0 rotation = (0,0,1) + // PI/2 rotation = (-1,0,0) + // 0 elevation = (0,0,0) + // PI/2 elevation = (0,-1,0) + void GetSunDirection(CVector3D& lightdir) const { + lightdir.Y=-float(sin(m_Elevation)); + float scale=1+lightdir.Y; + lightdir.X=scale*float(sin(m_Rotation)); + lightdir.Z=scale*float(cos(m_Rotation)); + lightdir.Normalize(); + } +}; + +#endif diff --git a/source/terrain/Model.cpp b/source/terrain/Model.cpp new file mode 100755 index 0000000000..22441861ce --- /dev/null +++ b/source/terrain/Model.cpp @@ -0,0 +1,128 @@ +/************************************************************ + * + * File Name: Model.Cpp + * + * Description: CModel is a specific instance of a model. + * It contains a pointer to CModelDef, and + * includes all instance information, such as + * current animation pose. + * + ************************************************************/ + +#include "Model.h" +#include "Quaternion.h" + +CModel::CModel() +{ + m_pModelDef = NULL; + m_pBonePoses = NULL; +} + +CModel::~CModel() +{ + Destroy(); +} + +bool CModel::InitModel(CModelDef *modeldef) +{ + m_pModelDef = modeldef; + + m_pBonePoses = new CMatrix3D[m_pModelDef->GetNumBones()]; + + ClearPose(); + + return true; +} + +void CModel::Destroy() +{ + m_pModelDef = NULL; + + if (m_pBonePoses) + delete [] m_pBonePoses; + + m_pBonePoses = NULL; +} + + +void CModel::SetPose (const char *anim_name, float time) +{ + int AnimI = -1; + + for (int i=0; iGetNumAnimations(); i++) + { + if ( strcmp(anim_name, m_pModelDef->GetAnimations()[i].m_Name) == 0 ) + { + AnimI = i; + break; + } + } + + if (AnimI == -1) + return; + + SModelAnimation *pAnim = &m_pModelDef->GetAnimations()[AnimI]; + + int StartI = (int)time; + int EndI;// = (int)(time + 0.999999f); + + if ((float)StartI == time) + EndI = StartI; + else + EndI = StartI+1; + + float factor = time - (float)StartI; + + if (EndI > pAnim->m_NumFrames-1) + EndI = 0; + + SModelAnimationFrame *pStartFrame = &m_pModelDef->GetAnimationFrames()[pAnim->m_FirstFrame + StartI]; + SModelAnimationFrame *pEndFrame = &m_pModelDef->GetAnimationFrames()[pAnim->m_FirstFrame + EndI]; + + for (i=0; iGetNumBones(); i++) + { + SModelAnimationKey *pKey1 = &m_pModelDef->GetAnimationKeys()[pStartFrame->m_FirstKey+i]; + SModelAnimationKey *pKey2 = &m_pModelDef->GetAnimationKeys()[pEndFrame->m_FirstKey+i]; + + CVector3D Translation = pKey1->m_Translation + (pKey2->m_Translation - pKey1->m_Translation)*factor; + + m_pBonePoses[i].SetIdentity(); + + CQuaternion from, to, rotation; + from.FromEularAngles (pKey1->m_Rotation.X, pKey1->m_Rotation.Y, pKey1->m_Rotation.Z); + to.FromEularAngles (pKey2->m_Rotation.X, pKey2->m_Rotation.Y, pKey2->m_Rotation.Z); + rotation.Slerp (from, to, factor); + + m_pBonePoses[i] = rotation.ToMatrix(); + + m_pBonePoses[i].Translate(Translation); + + int Parent = m_pModelDef->GetBones()[i].m_Parent; + + if (Parent > -1) + m_pBonePoses[i] = m_pBonePoses[Parent] * m_pBonePoses[i]; + } +} + +void CModel::ClearPose() +{ + //for each bone, set the bone's pose to the intial pose + for (int i=0; iGetNumBones(); i++) + m_pBonePoses[i] = m_pModelDef->GetBones()[i].m_Absolute; +} + + +void RotateX (CMatrix3D *mat, float angle1, float angle2, float factor) +{ + float Cos = cosf(angle1) + (cosf(angle2)-cosf(angle1))*factor; + float Sin = sinf(angle1) + (sinf(angle2)-cosf(angle1))*factor; + + CMatrix3D RotX; + + RotX._11=1.0f; RotX._12=0.0f; RotX._13=0.0f; RotX._14=0.0f; + RotX._21=0.0f; RotX._22=Cos; RotX._23=-Sin; RotX._24=0.0f; + RotX._31=0.0f; RotX._32=Sin; RotX._33=Cos; RotX._34=0.0f; + RotX._41=0.0f; RotX._42=0.0f; RotX._43=0.0f; RotX._44=1.0f; + + *mat = RotX * (*mat); +} diff --git a/source/terrain/Model.h b/source/terrain/Model.h new file mode 100755 index 0000000000..217ae65ca8 --- /dev/null +++ b/source/terrain/Model.h @@ -0,0 +1,44 @@ +/************************************************************ + * + * File Name: Model.H + * + * Description: CModel is a specific instance of a model. + * It contains a pointer to CModelDef, and + * includes all instance information, such as + * current animation pose. + * + ************************************************************/ + +#ifndef MODEL_H +#define MODEL_H + +#include "Texture.h" +#include "ModelDef.h" + +class CModel +{ + public: + CModel(); + ~CModel(); + + bool InitModel(CModelDef *modeldef); + void Destroy(); + + void SetPose (const char *anim_name, float time); + void ClearPose (); + + //access functions + public: + CModelDef *GetModelDef() { return m_pModelDef; } + CMatrix3D *GetBonePoses() { return m_pBonePoses; } + + void SetTexture(const CTexture& tex) { m_Texture=tex; } + CTexture* GetTexture() { return &m_Texture; } + + protected: + CTexture m_Texture; + CModelDef *m_pModelDef; + CMatrix3D *m_pBonePoses; //describes the current pose for each bone +}; + +#endif diff --git a/source/terrain/ModelDef.cpp b/source/terrain/ModelDef.cpp new file mode 100755 index 0000000000..1724bbed16 --- /dev/null +++ b/source/terrain/ModelDef.cpp @@ -0,0 +1,109 @@ +/************************************************************ + * + * File Name: ModelDef.Cpp + * + * Description: CModelDef is essentially a CModelFile, except + * that the data is stored in a more convenient + * way. To create a CModelDef, call + * CModelFile::ReadModelDef(); + * + ************************************************************/ + +#include "ModelDef.h" + +CModelDef::CModelDef() +{ + m_pVertices = NULL; + m_pFaces = NULL; + m_pBones = NULL; + m_pAnimationKeys = NULL; + m_pAnimationFrames = NULL; + m_pAnimations = NULL; + + m_NumVertices = 0; + m_NumFaces = 0; + m_NumBones = 0; + m_NumAnimationKeys = 0; + m_NumAnimationFrames = 0; + m_NumAnimations = 0; +} + +CModelDef::~CModelDef() +{ + Destroy(); +} + +void CModelDef::Destroy() +{ + if (m_pVertices) + delete [] m_pVertices; + if (m_pFaces) + delete [] m_pFaces; + if (m_pBones) + delete [] m_pBones; + if (m_pAnimationKeys) + delete [] m_pAnimationKeys; + if (m_pAnimationFrames) + delete [] m_pAnimationFrames; + if (m_pAnimations) + delete [] m_pAnimations; + + m_pVertices = NULL; + m_pFaces = NULL; + m_pBones = NULL; + m_pAnimationKeys = NULL; + m_pAnimationFrames = NULL; + m_pAnimations = NULL; + + m_NumVertices = 0; + m_NumFaces = 0; + m_NumBones = 0; + m_NumAnimationKeys = 0; + m_NumAnimationFrames = 0; + m_NumAnimations = 0; +} + +void CModelDef::SetupBones() +{ + for (int i=0; im_Relative.SetIdentity(); + pBone->m_Absolute.SetIdentity(); + + pBone->m_Relative.RotateX (pBone->m_Rotation.X); + pBone->m_Relative.RotateY (pBone->m_Rotation.Y); + pBone->m_Relative.RotateZ (pBone->m_Rotation.Z); +// pBone->m_Relative.RotateX (DEGTORAD(90)); + + pBone->m_Relative.Translate (pBone->m_Position); + + if (pBone->m_Parent >= 0) + { + SModelBone *pParent = &m_pBones[pBone->m_Parent]; + + pBone->m_Absolute = pParent->m_Absolute * pBone->m_Relative; + } + else + pBone->m_Absolute = pBone->m_Relative; + } + + //we need to "un-transform" all the vertices by the initial + //pose of the bones they are attached to. + for (i=0; im_Bone]; + + CVector3D BonePos = pBone->m_Absolute.GetTranslation(); + + pVertex->m_Coords.X -= BonePos.X; + pVertex->m_Coords.Y -= BonePos.Y; + pVertex->m_Coords.Z -= BonePos.Z; + + CMatrix3D BoneInvMat = pBone->m_Absolute.GetTranspose(); + + pVertex->m_Coords = BoneInvMat.Rotate (pVertex->m_Coords); + } +} diff --git a/source/terrain/ModelDef.h b/source/terrain/ModelDef.h new file mode 100755 index 0000000000..5f547bd44c --- /dev/null +++ b/source/terrain/ModelDef.h @@ -0,0 +1,120 @@ +/************************************************************ + * + * File Name: ModelDef.H + * + * Description: CModelDef is essentially a CModelFile, except + * that the data is stored in a more convenient + * way. To create a CModelDef, call + * CModelFile::ReadModelDef(); + * + ************************************************************/ + +#ifndef MODELDEF_H +#define MODELDEF_H + +#include "Vector3D.h" +#include "Matrix3D.h" + +#define MAX_NAME_LENGTH (128) + + +struct SModelVertex +{ + CVector3D m_Coords; + CVector3D m_Norm; + + float m_U, m_V; + int m_Bone; +}; + + +struct SModelFace +{ + int m_Verts[3]; +}; + + +struct SModelBone +{ + char m_Name[MAX_NAME_LENGTH]; + + int m_Parent; + CVector3D m_Position; + CVector3D m_Rotation; + + //absolute and relative orientation of this bone + CMatrix3D m_Relative; + CMatrix3D m_Absolute; +}; + +struct SModelAnimationKey +{ + CVector3D m_Translation; + CVector3D m_Rotation; +}; + +//An animation frame contains one animation key for each of +//the bones in the model +struct SModelAnimationFrame +{ + int m_FirstKey; + int m_NumKeys; //this should be that same as number of bones in the model +}; + +//a complete animation for all the bones +struct SModelAnimation +{ + char m_Name[MAX_NAME_LENGTH]; + + int m_FirstFrame; + int m_NumFrames; +}; + + +class CModelDef +{ + friend class CModelFile; + + public: + CModelDef (); + virtual ~CModelDef (); + + void SetupBones(); + + void Destroy(); + + //access functions + public: + SModelVertex *GetVertices() { return m_pVertices; } + SModelFace *GetFaces() { return m_pFaces; } + SModelBone *GetBones() { return m_pBones; } + SModelAnimationKey *GetAnimationKeys() { return m_pAnimationKeys; } + SModelAnimationFrame *GetAnimationFrames() { return m_pAnimationFrames; } + SModelAnimation *GetAnimations() { return m_pAnimations; } + + int GetNumVertices() { return m_NumVertices; } + int GetNumFaces() { return m_NumFaces; } + int GetNumBones() { return m_NumBones; } + int GetNumAnimationKeys() { return m_NumAnimationKeys; } + int GetNumAnimationFrames() { return m_NumAnimationFrames; } + int GetNumAnimations() { return m_NumAnimations; } + + protected: + SModelVertex *m_pVertices; + SModelFace *m_pFaces; + SModelBone *m_pBones; + SModelAnimationKey *m_pAnimationKeys; + SModelAnimationFrame *m_pAnimationFrames; + SModelAnimation *m_pAnimations; + + int m_NumVertices; + int m_NumFaces; + int m_NumBones; + int m_NumAnimationKeys; + int m_NumAnimationFrames; + int m_NumAnimations; + + char m_TextureName[MAX_NAME_LENGTH]; +}; + +#endif diff --git a/source/terrain/ModelFile.cpp b/source/terrain/ModelFile.cpp new file mode 100755 index 0000000000..eeeaac74f9 --- /dev/null +++ b/source/terrain/ModelFile.cpp @@ -0,0 +1,352 @@ +/************************************************************ + * + * File Name: ModelFile.Cpp + * + * Description: A CModelFile holds the structure of a model + * file. A model is easily read/written to disk + * using this interface. + * + ************************************************************/ + +#include + +#include "ModelFile.h" + +CModelFile::CModelFile () +{ + m_pVertices = NULL; + m_pFaces = NULL; + m_pBones = NULL; + m_pAnimationKeys = NULL; + m_pAnimationFrames = NULL; + m_pAnimations = NULL; + + m_NumVertices = 0; + m_NumFaces = 0; + m_NumBones = 0; + m_NumAnimationKeys = 0; + m_NumAnimationFrames = 0; + m_NumAnimations = 0; +} + +CModelFile::~CModelFile() +{ + Destroy(); +} + +void CModelFile::Destroy() +{ + if (m_pVertices) + delete [] m_pVertices; + if (m_pFaces) + delete [] m_pFaces; + if (m_pBones) + delete [] m_pBones; + if (m_pAnimationKeys) + delete [] m_pAnimationKeys; + if (m_pAnimationFrames) + delete [] m_pAnimationFrames; + if (m_pAnimations) + delete [] m_pAnimations; + + m_pVertices = NULL; + m_pFaces = NULL; + m_pBones = NULL; + m_pAnimationKeys = NULL; + m_pAnimationFrames = NULL; + m_pAnimations = NULL; + + m_NumVertices = 0; + m_NumFaces = 0; + m_NumBones = 0; + m_NumAnimationKeys = 0; + m_NumAnimationFrames = 0; + m_NumAnimations = 0; +} + +bool CModelFile::WriteModelDef (const char *filename, CModelDef *modeldef) +{ + FILE *out_f = NULL; + + out_f = fopen (filename, "wb"); + + m_NumVertices = modeldef->m_NumVertices; + m_NumFaces = modeldef->m_NumFaces; + m_NumBones = modeldef->m_NumBones; + m_NumAnimationKeys = modeldef->m_NumAnimationKeys; + m_NumAnimationFrames = modeldef->m_NumAnimationFrames; + m_NumAnimations = modeldef->m_NumAnimations; + + m_pVertices = new SModelFile_Vertex[m_NumVertices]; + m_pFaces = new SModelFile_Face[m_NumFaces]; + m_pBones = new SModelFile_Bone[m_NumBones]; + m_pAnimationKeys = new SModelFile_AnimationKey[m_NumAnimationKeys]; + m_pAnimationFrames = new SModelFile_AnimationFrame[m_NumAnimationFrames]; + m_pAnimations = new SModelFile_Animation[m_NumAnimations]; + + + for (int i=0; im_pVertices[i].m_Coords; + m_pVertices[i].m_Norm = modeldef->m_pVertices[i].m_Norm; + m_pVertices[i].m_U = modeldef->m_pVertices[i].m_U; + m_pVertices[i].m_V = modeldef->m_pVertices[i].m_V; + m_pVertices[i].m_Bone = modeldef->m_pVertices[i].m_Bone; + + if (m_pVertices[i].m_Bone >= 0) + { + SModelBone *pBone = &modeldef->m_pBones[m_pVertices[i].m_Bone]; + m_pVertices[i].m_Coords = pBone->m_Absolute.Transform (m_pVertices[i].m_Coords); + } + } + + for (i=0; im_pFaces[i].m_Verts[0]; + m_pFaces[i].m_Verts[1] = modeldef->m_pFaces[i].m_Verts[1]; + m_pFaces[i].m_Verts[2] = modeldef->m_pFaces[i].m_Verts[2]; + } + + for (i=0; im_pBones[i].m_Name); + m_pBones[i].m_Position = modeldef->m_pBones[i].m_Position; + m_pBones[i].m_Rotation = modeldef->m_pBones[i].m_Rotation; + m_pBones[i].m_Parent = modeldef->m_pBones[i].m_Parent; + } + + for (i=0; im_pAnimationKeys[i].m_Translation; + m_pAnimationKeys[i].m_Rotation = modeldef->m_pAnimationKeys[i].m_Rotation; + } + + for (i=0; im_pAnimationFrames[i].m_FirstKey; + m_pAnimationFrames[i].m_NumKeys = modeldef->m_pAnimationFrames[i].m_NumKeys; + } + + for (i=0; im_pAnimations[i].m_Name); + m_pAnimations[i].m_FirstFrame = modeldef->m_pAnimations[i].m_FirstFrame; + m_pAnimations[i].m_NumFrames = modeldef->m_pAnimations[i].m_NumFrames; + } + + + m_Lumps[MF_VERTICES].m_Offset = MF_NUM_LUMPS*sizeof(SLump); + m_Lumps[MF_VERTICES].m_Length = m_NumVertices*sizeof(SModelFile_Vertex); + + m_Lumps[MF_FACES].m_Offset = m_Lumps[MF_VERTICES].m_Offset + m_Lumps[MF_VERTICES].m_Length; + m_Lumps[MF_FACES].m_Length = m_NumFaces*sizeof(SModelFile_Face); + + m_Lumps[MF_BONES].m_Offset = m_Lumps[MF_FACES].m_Offset + m_Lumps[MF_FACES].m_Length; + m_Lumps[MF_BONES].m_Length = m_NumBones*sizeof(SModelFile_Bone); + + m_Lumps[MF_ANIMKEYS].m_Offset = m_Lumps[MF_BONES].m_Offset + m_Lumps[MF_BONES].m_Length; + m_Lumps[MF_ANIMKEYS].m_Length = m_NumAnimationKeys*sizeof(SModelFile_AnimationKey); + + m_Lumps[MF_ANIMFRAMES].m_Offset = m_Lumps[MF_ANIMKEYS].m_Offset + m_Lumps[MF_ANIMKEYS].m_Length; + m_Lumps[MF_ANIMFRAMES].m_Length = m_NumAnimationFrames*sizeof(SModelFile_AnimationFrame); + + m_Lumps[MF_ANIMS].m_Offset = m_Lumps[MF_ANIMFRAMES].m_Offset + m_Lumps[MF_ANIMFRAMES].m_Length; + m_Lumps[MF_ANIMS].m_Length = m_NumAnimations*sizeof(SModelFile_Animation); + + //write the lumps + if (fwrite (m_Lumps, sizeof(SLump), MF_NUM_LUMPS, out_f) != MF_NUM_LUMPS) + { + fclose (out_f); + return false; + } + + //write all the data + if (fwrite (m_pVertices, sizeof (SModelFile_Vertex), m_NumVertices, out_f) != (unsigned)m_NumVertices) + { + fclose (out_f); + return false; + } + + if (fwrite (m_pFaces, sizeof (SModelFile_Face), m_NumFaces, out_f) != (unsigned)m_NumFaces) + { + fclose (out_f); + return false; + } + + if (fwrite (m_pBones, sizeof (SModelFile_Bone), m_NumBones, out_f) != (unsigned)m_NumBones) + { + fclose (out_f); + return false; + } + + if (fwrite (m_pAnimationKeys, sizeof (SModelFile_AnimationKey), m_NumAnimationKeys, out_f) != (unsigned)m_NumAnimationKeys) + { + fclose (out_f); + return false; + } + + if (fwrite (m_pAnimationFrames, sizeof (SModelFile_AnimationFrame), m_NumAnimationFrames, out_f) != (unsigned)m_NumAnimationFrames) + { + fclose (out_f); + return false; + } + + if (fwrite (m_pAnimations, sizeof (SModelFile_Animation), m_NumAnimations, out_f) != (unsigned)m_NumAnimations) + { + fclose (out_f); + return false; + } + + fclose (out_f); + + Destroy(); + + return true; +} + + +bool CModelFile::ReadModelDef (const char *filename, CModelDef *modeldef) +{ + FILE *in_f = NULL; + + in_f = fopen (filename, "rb"); + if (!in_f) { + return false; + } + + //read the lumps first + if (fread (m_Lumps, sizeof(SLump), MF_NUM_LUMPS, in_f) != MF_NUM_LUMPS) + { + fclose (in_f); + return false; + } + + //calculate the number of each element + m_NumVertices = m_Lumps[MF_VERTICES].m_Length / sizeof(SModelFile_Vertex); + m_NumFaces = m_Lumps[MF_FACES].m_Length / sizeof(SModelFile_Face); + m_NumBones = m_Lumps[MF_BONES].m_Length / sizeof(SModelFile_Bone); + m_NumAnimationKeys = m_Lumps[MF_ANIMKEYS].m_Length / sizeof(SModelFile_AnimationKey); + m_NumAnimationFrames = m_Lumps[MF_ANIMFRAMES].m_Length / sizeof(SModelFile_AnimationFrame); + m_NumAnimations = m_Lumps[MF_ANIMS].m_Length / sizeof(SModelFile_Animation); + + //allocate memory + m_pVertices = new SModelFile_Vertex[m_NumVertices]; + m_pFaces = new SModelFile_Face[m_NumFaces]; + m_pBones = new SModelFile_Bone[m_NumBones]; + m_pAnimationKeys = new SModelFile_AnimationKey[m_NumAnimationKeys]; + m_pAnimationFrames = new SModelFile_AnimationFrame[m_NumAnimationFrames]; + m_pAnimations = new SModelFile_Animation[m_NumAnimations]; + + + //read all the data + fseek (in_f, m_Lumps[MF_VERTICES].m_Offset, SEEK_SET); + if (fread (m_pVertices, sizeof(SModelFile_Vertex), m_NumVertices, in_f) != (unsigned)m_NumVertices) + { + fclose (in_f); + return false; + } + + fseek (in_f, m_Lumps[MF_FACES].m_Offset, SEEK_SET); + if (fread (m_pFaces, sizeof (SModelFile_Face), m_NumFaces, in_f) != (unsigned)m_NumFaces) + { + fclose (in_f); + return false; + } + + fseek (in_f, m_Lumps[MF_BONES].m_Offset, SEEK_SET); + if (fread (m_pBones, sizeof (SModelFile_Bone), m_NumBones, in_f) != (unsigned)m_NumBones) + { + fclose (in_f); + return false; + } + + fseek (in_f, m_Lumps[MF_ANIMKEYS].m_Offset, SEEK_SET); + if (fread (m_pAnimationKeys, sizeof (SModelFile_AnimationKey), m_NumAnimationKeys, in_f) != (unsigned)m_NumAnimationKeys) + { + fclose (in_f); + return false; + } + + fseek (in_f, m_Lumps[MF_ANIMFRAMES].m_Offset, SEEK_SET); + if (fread (m_pAnimationFrames, sizeof (SModelFile_AnimationFrame), m_NumAnimationFrames, in_f) != (unsigned)m_NumAnimationFrames) + { + fclose (in_f); + return false; + } + + fseek (in_f, m_Lumps[MF_ANIMS].m_Offset, SEEK_SET); + if (fread (m_pAnimations, sizeof (SModelFile_Animation), m_NumAnimations, in_f) != (unsigned)m_NumAnimations) + { + fclose (in_f); + return false; + } + + fclose (in_f); + + modeldef->Destroy(); + + modeldef->m_NumVertices = m_NumVertices; + modeldef->m_NumFaces = m_NumFaces; + modeldef->m_NumBones = m_NumBones; + modeldef->m_NumAnimationKeys = m_NumAnimationKeys; + modeldef->m_NumAnimationFrames = m_NumAnimationFrames; + modeldef->m_NumAnimations = m_NumAnimations; + + modeldef->m_pVertices = new SModelVertex[m_NumVertices]; + modeldef->m_pFaces = new SModelFace[m_NumFaces]; + modeldef->m_pBones = new SModelBone[m_NumBones]; + modeldef->m_pAnimationKeys = new SModelAnimationKey[m_NumAnimationKeys]; + modeldef->m_pAnimationFrames = new SModelAnimationFrame[m_NumAnimationFrames]; + modeldef->m_pAnimations = new SModelAnimation[m_NumAnimations]; + + + for (int i=0; im_pVertices[i].m_Coords = m_pVertices[i].m_Coords; + modeldef->m_pVertices[i].m_Norm = m_pVertices[i].m_Norm; + modeldef->m_pVertices[i].m_U = m_pVertices[i].m_U; + modeldef->m_pVertices[i].m_V = m_pVertices[i].m_V; + modeldef->m_pVertices[i].m_Bone = m_pVertices[i].m_Bone; + } + + for (i=0; im_pFaces[i].m_Verts[0] = m_pFaces[i].m_Verts[0]; + modeldef->m_pFaces[i].m_Verts[1] = m_pFaces[i].m_Verts[1]; + modeldef->m_pFaces[i].m_Verts[2] = m_pFaces[i].m_Verts[2]; + } + + for (i=0; im_pBones[i].m_Name, m_pBones[i].m_Name); + modeldef->m_pBones[i].m_Position = m_pBones[i].m_Position; + modeldef->m_pBones[i].m_Rotation = m_pBones[i].m_Rotation; + modeldef->m_pBones[i].m_Parent = m_pBones[i].m_Parent; + } + + for (i=0; im_pAnimationKeys[i].m_Translation = m_pAnimationKeys[i].m_Translation; + modeldef->m_pAnimationKeys[i].m_Rotation = m_pAnimationKeys[i].m_Rotation; + } + + for (i=0; im_pAnimationFrames[i].m_FirstKey = m_pAnimationFrames[i].m_FirstKey; + modeldef->m_pAnimationFrames[i].m_NumKeys = m_pAnimationFrames[i].m_NumKeys; + } + + for (i=0; im_pAnimations[i].m_Name, m_pAnimations[i].m_Name); + modeldef->m_pAnimations[i].m_FirstFrame = m_pAnimations[i].m_FirstFrame; + modeldef->m_pAnimations[i].m_NumFrames = m_pAnimations[i].m_NumFrames; + } + + modeldef->SetupBones(); + + Destroy(); + + return true; +} + diff --git a/source/terrain/ModelFile.h b/source/terrain/ModelFile.h new file mode 100755 index 0000000000..6d0d8f907f --- /dev/null +++ b/source/terrain/ModelFile.h @@ -0,0 +1,116 @@ +/************************************************************ + * + * File Name: ModelFile.H + * + * Description: A CModelFile holds the structure of a model + * file, and is responsible for reading/writing + * a CModelDef from/to a file + * + ************************************************************/ + +#ifndef MODELFILE_H +#define MODELFILE_H + +#include + +#include "Vector3D.h" +#include "ModelDef.h" + +enum EModelFileLumps +{ + MF_VERTICES = 0, + MF_FACES, + MF_BONES, + MF_ANIMKEYS, + MF_ANIMFRAMES, + MF_ANIMS, + MF_NUM_LUMPS +}; + +struct SLump +{ + int m_Offset; + int m_Length; +}; + +struct SModelFile_Vertex +{ + CVector3D m_Coords; + CVector3D m_Norm; + + float m_U, m_V; + int m_Bone; +}; + + +struct SModelFile_Face +{ + int m_Verts[3]; +}; + + +struct SModelFile_Bone +{ + char m_Name[MAX_NAME_LENGTH]; + + int m_Parent; + CVector3D m_Position; + CVector3D m_Rotation; +}; + +struct SModelFile_AnimationKey +{ + CVector3D m_Translation; + CVector3D m_Rotation; +}; + +//animation keys of one animation for one bone +struct SModelFile_AnimationFrame +{ + int m_FirstKey; + int m_NumKeys; //this should always be the same as the number of bones in the model. +}; + +//a complete animation for all the bones +struct SModelFile_Animation +{ + char m_Name[MAX_NAME_LENGTH]; + + int m_FirstFrame; + int m_NumFrames; +}; + + +class CModelFile +{ + public: + CModelFile (); + ~CModelFile (); + + bool ReadModelDef (const char *filename, CModelDef *modeldef); + bool WriteModelDef (const char *filename, CModelDef *modeldef); + + private: + void Destroy(); + + private: + SLump m_Lumps[MF_NUM_LUMPS]; + + SModelFile_Vertex *m_pVertices; + SModelFile_Face *m_pFaces; + SModelFile_Bone *m_pBones; + SModelFile_AnimationKey *m_pAnimationKeys; + SModelFile_AnimationFrame *m_pAnimationFrames; + SModelFile_Animation *m_pAnimations; + + int m_NumVertices; + int m_NumFaces; + int m_NumBones; + int m_NumAnimationKeys; + int m_NumAnimationFrames; + int m_NumAnimations; +}; + + +#endif + diff --git a/source/terrain/Quaternion.cpp b/source/terrain/Quaternion.cpp new file mode 100755 index 0000000000..cff0bdd30f --- /dev/null +++ b/source/terrain/Quaternion.cpp @@ -0,0 +1,179 @@ +/************************************************************ + * + * File Name: Quaternion.Cpp + * + * Description: + * + ************************************************************/ + +#include "Quaternion.h" + +const float EPSILON=0.0001f; + + +CQuaternion::CQuaternion() +{ + m_V.Clear (); + m_W = 0; +} + +//quaternion addition +CQuaternion CQuaternion::operator + (CQuaternion &quat) +{ + CQuaternion Temp; + + Temp.m_W = m_W + quat.m_W; + Temp.m_V = m_V + quat.m_V; + + return Temp; +} + +//quaternion addition/assignment +CQuaternion &CQuaternion::operator += (CQuaternion &quat) +{ + m_W += quat.m_W; + m_V += quat.m_V; + + return (*this); +} + +//quaternion multiplication +CQuaternion CQuaternion::operator * (CQuaternion &quat) +{ + CQuaternion Temp; + + Temp.m_W = (m_W * quat.m_W) - (m_V.Dot(quat.m_V)); + Temp.m_V = (m_V.Cross(quat.m_V)) + (quat.m_V * m_W) + (m_V * quat.m_W); + + return Temp; +} + +//quaternion multiplication/assignment +CQuaternion &CQuaternion::operator *= (CQuaternion &quat) +{ + (*this) = (*this) * quat; + + return (*this); +} + + +void CQuaternion::FromEularAngles (float x, float y, float z) +{ + float cr, cp, cy; + float sr, sp, sy; + + CQuaternion QRoll, QPitch, QYaw; + + cr = cosf(x * 0.5f); + cp = cosf(y * 0.5f); + cy = cosf(z * 0.5f); + + sr = sinf(x * 0.5f); + sp = sinf(y * 0.5f); + sy = sinf(z * 0.5f); + + QRoll.m_V.Set (sr,0,0); + QRoll.m_W = cr; + + QPitch.m_V.Set (0,sp,0); + QPitch.m_W = cp; + + QYaw.m_V.Set (0,0,sy); + QYaw.m_W = cy; + + (*this) = QYaw * QPitch * QRoll; +} + +CMatrix3D CQuaternion::ToMatrix () +{ + CMatrix3D R; + float x2, y2, z2; + float wx, wy, wz, xx, xy, xz, yy, yz, zz; + + // calculate coefficients + x2 = m_V.X + m_V.X; + y2 = m_V.Y + m_V.Y; + z2 = m_V.Z + m_V.Z; + + xx = m_V.X * x2; + xy = m_V.X * y2; + xz = m_V.X * z2; + + yy = m_V.Y * y2; + yz = m_V.Y * z2; + + zz = m_V.Z * z2; + + wx = m_W * x2; + wy = m_W * y2; + wz = m_W * z2; + + R.SetIdentity(); + + R._11 = 1.0f - (yy + zz); + R._12 = xy - wz; + R._13 = xz + wy; + + R._21 = xy + wz; + R._22 = 1.0f - (xx + zz); + R._23 = yz - wx; + + R._31 = xz - wy; + R._32 = yz + wx; + R._33 = 1.0f - (xx + yy); + + return R; +} + +void CQuaternion::Slerp(CQuaternion &from, CQuaternion &to, float ratio) +{ + float to1[4]; + float omega, cosom, sinom, scale0, scale1; + + // calc cosine + cosom = from.m_V.X * to.m_V.X + + from.m_V.Y * to.m_V.Y + + from.m_V.Z * to.m_V.Z + + from.m_W * to.m_W; + + + // adjust signs (if necessary) + if (cosom < 0.0) + { + cosom = -cosom; + to1[0] = -to.m_V.X; + to1[1] = -to.m_V.Y; + to1[2] = -to.m_V.Z; + to1[3] = -to.m_W; + } + else + { + to1[0] = to.m_V.X; + to1[1] = to.m_V.Y; + to1[2] = to.m_V.Z; + to1[3] = to.m_W; + } + + // calculate coefficients + if ((1.0f - cosom) > EPSILON) + { + // standard case (slerp) + omega = acosf(cosom); + sinom = sinf(omega); + scale0 = sinf((1.0f - ratio) * omega) / sinom; + scale1 = sinf(ratio * omega) / sinom; + } + else + { + // "from" and "to" quaternions are very close + // ... so we can do a linear interpolation + scale0 = 1.0f - ratio; + scale1 = ratio; + } + + // calculate final values + m_V.X = scale0 * from.m_V.X + scale1 * to1[0]; + m_V.Y = scale0 * from.m_V.Y + scale1 * to1[1]; + m_V.Z = scale0 * from.m_V.Z + scale1 * to1[2]; + m_W = scale0 * from.m_W + scale1 * to1[3]; +} diff --git a/source/terrain/Quaternion.h b/source/terrain/Quaternion.h new file mode 100755 index 0000000000..7fa61f36f3 --- /dev/null +++ b/source/terrain/Quaternion.h @@ -0,0 +1,42 @@ +/************************************************************ + * + * File Name: Quaternion.H + * + * Description: + * + ************************************************************/ + +#ifndef QUATERNION_H +#define QUATERNION_H + +#include "Matrix3D.h" + +class CQuaternion +{ + public: + CVector3D m_V; + float m_W; + + public: + CQuaternion(); + + //quaternion addition + CQuaternion operator + (CQuaternion &quat); + //quaternion addition/assignment + CQuaternion &operator += (CQuaternion &quat); + + //quaternion multiplication + CQuaternion operator * (CQuaternion &quat); + //quaternion multiplication/assignment + CQuaternion &operator *= (CQuaternion &quat); + + void FromEularAngles (float x, float y, float z); + + //convert the quaternion to matrix + CMatrix3D ToMatrix (); + + //sphere interpolation + void Slerp(CQuaternion &from, CQuaternion &to, float ratio); +}; + +#endif diff --git a/source/terrain/SHCoeffs.cpp b/source/terrain/SHCoeffs.cpp new file mode 100755 index 0000000000..f11be80cb2 --- /dev/null +++ b/source/terrain/SHCoeffs.cpp @@ -0,0 +1,64 @@ +//---------------------------------------------------------------- +// +// Name: SHCoeffs.h +// Last Update: 25/11/03 +// Author: Rich Cross +// Contact: rich@0ad.wildfiregames.com +// +// Description: implementation of 9 component spherical harmonic +// lighting +//---------------------------------------------------------------- + +#include "SHCoeffs.h" + +CSHCoeffs::CSHCoeffs() +{ + for (int i=0;i<9;i++) { + _data[i].Clear(); + } +} + +void CSHCoeffs::AddAmbientLight(const RGBColor& color) +{ + _data[0]+=color; +} + +void CSHCoeffs::AddDirectionalLight(const CVector3D& lightDir,const RGBColor& lightColor) +{ + CVector3D dirToLight(-lightDir.X,-lightDir.Y,-lightDir.Z); + + const float normalisation = PI*16/17; + const float c1 = SQR(0.282095f) * normalisation * 1.0f; + const float c2 = SQR(0.488603f) * normalisation * (2.0f/3.0f); + const float c3 = SQR(1.092548f) * normalisation * (1.0f/4.0f); + const float c4 = SQR(0.315392f) * normalisation * (1.0f/4.0f); + const float c5 = SQR(0.546274f) * normalisation * (1.0f/4.0f); + + _data[0]+=lightColor*c1; + _data[1]+=lightColor*c2*dirToLight.X; + _data[2]+=lightColor*c2*dirToLight.Y; + _data[3]+=lightColor*c2*dirToLight.Z; + _data[4]+=lightColor*c3*dirToLight.X*dirToLight.Z; + _data[5]+=lightColor*c3*dirToLight.Z*dirToLight.Y; + _data[6]+=lightColor*c3*dirToLight.Y*dirToLight.X; + _data[7]+=lightColor*c4*(3.0f*SQR(dirToLight.Z)-1.0f); + _data[8]+=lightColor*c5*(SQR(dirToLight.X)-SQR(dirToLight.Y)); +} + +void CSHCoeffs::Evaluate(const CVector3D& normal,RGBColor& color) +{ +#if 1 + color=_data[0]; + color+=_data[1]*normal.X; + color+=_data[2]*normal.Y; + color+=_data[3]*normal.Z; + color+=_data[4]*(normal.X*normal.Z); + color+=_data[5]*(normal.Z*normal.Y); + color+=_data[6]*(normal.Y*normal.X); + color+=_data[7]*(3*SQR(normal.Z)-1.0f); + color+=_data[8]*(SQR(normal.X)-SQR(normal.Y)); +#else + // debug aid: output quantised normal + color=RGBColor((normal.X+1)*0.5,(normal.Y+1)*0.5,(normal.Z+1)*0.5); +#endif +} diff --git a/source/terrain/SHCoeffs.h b/source/terrain/SHCoeffs.h new file mode 100755 index 0000000000..bcecce76dd --- /dev/null +++ b/source/terrain/SHCoeffs.h @@ -0,0 +1,34 @@ +//---------------------------------------------------------------- +// +// Name: SHCoeffs.h +// Last Update: 25/11/03 +// Author: Rich Cross +// Contact: rich@0ad.wildfiregames.com +// +// Description: implementation of 9 component spherical harmonic +// lighting +//---------------------------------------------------------------- + +#ifndef __SHCOEFFS_H +#define __SHCOEFFS_H + +#include "Color.h" + +class CSHCoeffs +{ +public: + CSHCoeffs(); + + void AddAmbientLight(const RGBColor& color); + void AddDirectionalLight(const CVector3D& lightDir,const RGBColor& lightColor); + + void Evaluate(const CVector3D& normal,RGBColor& color); + + const RGBColor* GetCoefficients() const { return _data; } + +private: + RGBColor _data[9]; +}; + + +#endif diff --git a/source/terrain/Texture.h b/source/terrain/Texture.h new file mode 100755 index 0000000000..92d72c5f7f --- /dev/null +++ b/source/terrain/Texture.h @@ -0,0 +1,35 @@ +//----------------------------------------------------------- +// +// Name: Texture.h +// Last Update: 25/11/03 +// Author: Rich Cross +// Contact: rich@0ad.wildfiregames.com +// +// Description: Basic texture class +// +//----------------------------------------------------------- + +#ifndef _TEXTURE_H +#define _TEXTURE_H + +#include "res.h" +#include "..\ps\CStr.h" + +class CTexture +{ +public: + CTexture() : m_Handle(0) {} + CTexture(const char* name) : m_Name(name), m_Handle(0) {} + + void SetName(const char* name) { m_Name=name; } + const char* GetName() const { return (const char*) m_Name; } + + Handle GetHandle() const { return m_Handle; } + void SetHandle(Handle handle) { m_Handle=handle; } + +private: + CStr m_Name; + Handle m_Handle; +}; + +#endif diff --git a/source/terrain/Vector4D.h b/source/terrain/Vector4D.h new file mode 100755 index 0000000000..fc5b49b1a1 --- /dev/null +++ b/source/terrain/Vector4D.h @@ -0,0 +1,111 @@ +//*********************************************************** +// +// Name: CVector4D.h +// Last Update: 02/11/03 +// Author: Rich Cross +// +// Description: Provides an interface for a vector in R4 and +// allows vector and scalar operations on it +// +//*********************************************************** + +#ifndef _VECTOR4D_H +#define _VECTOR4D_H + + +#include +#include "MathUtil.h" + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// CVector4D: +class CVector4D +{ +public: + CVector4D() {} + CVector4D(const float f[4]) { m_X=f[0]; m_Y=f[1]; m_Z=f[2]; m_W=f[3]; } + CVector4D(float x,float y,float z,float w) { m_X=x; m_Y=y; m_Z=z; m_W=w; } + CVector4D(const CVector4D& p) { m_X=p.m_X; m_Y=p.m_Y; m_Z=p.m_Z; m_W=p.m_W; } + + operator float*() { + return &m_X; + } + + operator const float*() const { + return &m_X; + } + + CVector4D operator-() const { + return CVector4D(-m_X,-m_Y,-m_Z,-m_W); + } + + CVector4D operator+(const CVector4D& t) const { + return CVector4D(m_X+t.m_X,m_Y+t.m_Y,m_Z+t.m_Z,m_W+t.m_W); + } + + CVector4D operator-(const CVector4D& t) const { + return CVector4D(m_X-t.m_X,m_Y-t.m_Y,m_Z-t.m_Z,m_W-t.m_W); + } + + CVector4D operator*(const CVector4D& t) const { + return CVector4D(m_X*t.m_X,m_Y*t.m_Y,m_Z*t.m_Z,m_W*t.m_W); + } + + CVector4D operator*(float f) const { + return CVector4D(m_X*f,m_Y*f,m_Z*f,m_W*f); + } + + CVector4D operator/(float f) const { + float inv=1.0f/f; + return CVector4D(m_X*inv,m_Y*inv,m_Z*inv,m_W*inv); + } + + CVector4D& operator+=(const CVector4D& t) { + m_X+=t.m_X; m_Y+=t.m_Y; m_Z+=t.m_Z; m_W+=t.m_W; + return *this; + } + + CVector4D& operator-=(const CVector4D& t) { + m_X-=t.m_X; m_Y-=t.m_Y; m_Z-=t.m_Z; m_W-=t.m_W; + return *this; + } + + CVector4D& operator*=(const CVector4D& t) { + m_X*=t.m_X; m_Y*=t.m_Y; m_Z*=t.m_Z; m_W*=t.m_W; + return *this; + } + + CVector4D& operator*=(float f) { + m_X*=f; m_Y*=f; m_Z*=f; m_W*=f; + return *this; + } + + CVector4D& operator/=(float f) { + float invf=1.0f/f; + m_X*=invf; m_Y*=invf; m_Z*=invf; m_W*=invf; + return *this; + } + + float dot(const CVector4D& a) const { + return m_X*a.m_X+m_Y*a.m_Y+m_Z*a.m_Z+m_W*a.m_W; + } + + float lengthSquared() const { + return SQR(m_X)+SQR(m_Y)+SQR(m_Z)+SQR(m_W); + } + + float length() const { + return (float) sqrt(lengthSquared()); + } + + void normalize() { + float mag=length(); + m_X/=mag; m_Y/=mag; m_Z/=mag; m_W/=mag; + } + +public: + float m_X,m_Y,m_Z,m_W; +}; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +#endif