Either moved from terrain directory, or an inital revision, depending on the file. Whole bunch of changes related to props and animation.
This was SVN commit r306.
This commit is contained in:
parent
4d826bb5f2
commit
7fb944a1e1
146
source/graphics/Camera.cpp
Executable file
146
source/graphics/Camera.cpp
Executable file
@ -0,0 +1,146 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Camera.Cpp
|
||||
// Last Update: 24/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: CCamera holds a view and a projection matrix.
|
||||
// It also has a frustum which can be used to
|
||||
// cull objects for rendering.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#include "Camera.h"
|
||||
|
||||
CCamera::CCamera ()
|
||||
{
|
||||
// set viewport to something anything should handle, but should be initialised
|
||||
// to window size before use
|
||||
m_ViewPort.m_X = 0;
|
||||
m_ViewPort.m_Y = 0;
|
||||
m_ViewPort.m_Width = 800;
|
||||
m_ViewPort.m_Height = 600;
|
||||
}
|
||||
|
||||
CCamera::~CCamera ()
|
||||
{
|
||||
}
|
||||
|
||||
void CCamera::SetProjection (float nearp, float farp, float fov)
|
||||
{
|
||||
float h, w, Q;
|
||||
|
||||
m_NearPlane = nearp;
|
||||
m_FarPlane = farp;
|
||||
m_FOV = fov;
|
||||
|
||||
float Aspect = (float)m_ViewPort.m_Width/(float)m_ViewPort.m_Height;
|
||||
|
||||
w = 1/tanf (fov*0.5f*Aspect);
|
||||
h = 1/tanf (fov*0.5f);
|
||||
Q = m_FarPlane / (m_FarPlane - m_NearPlane);
|
||||
|
||||
m_ProjMat.SetZero ();
|
||||
m_ProjMat._11 = w;
|
||||
m_ProjMat._22 = h;
|
||||
m_ProjMat._33 = (m_FarPlane+m_NearPlane)/(m_FarPlane-m_NearPlane);;
|
||||
m_ProjMat._34 = -2*m_FarPlane*m_NearPlane/(m_FarPlane-m_NearPlane);
|
||||
m_ProjMat._43 = 1.0f;
|
||||
}
|
||||
|
||||
//Updates the frustum planes. Should be called
|
||||
//everytime the view or projection matrices are
|
||||
//altered.
|
||||
void CCamera::UpdateFrustum ()
|
||||
{
|
||||
CMatrix3D MatFinal;
|
||||
CMatrix3D MatView;
|
||||
|
||||
m_Orientation.GetInverse(MatView);
|
||||
|
||||
MatFinal = m_ProjMat * MatView;
|
||||
|
||||
//get the RIGHT plane
|
||||
m_ViewFrustum.SetNumPlanes (6);
|
||||
|
||||
m_ViewFrustum.m_aPlanes[0].m_Norm.X = MatFinal._41-MatFinal._11;
|
||||
m_ViewFrustum.m_aPlanes[0].m_Norm.Y = MatFinal._42-MatFinal._12;
|
||||
m_ViewFrustum.m_aPlanes[0].m_Norm.Z = MatFinal._43-MatFinal._13;
|
||||
m_ViewFrustum.m_aPlanes[0].m_Dist = MatFinal._44-MatFinal._14;
|
||||
|
||||
//get the LEFT plane
|
||||
m_ViewFrustum.m_aPlanes[1].m_Norm.X = MatFinal._41+MatFinal._11;
|
||||
m_ViewFrustum.m_aPlanes[1].m_Norm.Y = MatFinal._42+MatFinal._12;
|
||||
m_ViewFrustum.m_aPlanes[1].m_Norm.Z = MatFinal._43+MatFinal._13;
|
||||
m_ViewFrustum.m_aPlanes[1].m_Dist = MatFinal._44+MatFinal._14;
|
||||
|
||||
//get the BOTTOM plane
|
||||
m_ViewFrustum.m_aPlanes[2].m_Norm.X = MatFinal._41+MatFinal._21;
|
||||
m_ViewFrustum.m_aPlanes[2].m_Norm.Y = MatFinal._42+MatFinal._22;
|
||||
m_ViewFrustum.m_aPlanes[2].m_Norm.Z = MatFinal._43+MatFinal._23;
|
||||
m_ViewFrustum.m_aPlanes[2].m_Dist = MatFinal._44+MatFinal._24;
|
||||
|
||||
//get the TOP plane
|
||||
m_ViewFrustum.m_aPlanes[3].m_Norm.X = MatFinal._41-MatFinal._21;
|
||||
m_ViewFrustum.m_aPlanes[3].m_Norm.Y = MatFinal._42-MatFinal._22;
|
||||
m_ViewFrustum.m_aPlanes[3].m_Norm.Z = MatFinal._43-MatFinal._23;
|
||||
m_ViewFrustum.m_aPlanes[3].m_Dist = MatFinal._44-MatFinal._24;
|
||||
|
||||
//get the FAR plane
|
||||
m_ViewFrustum.m_aPlanes[4].m_Norm.X = MatFinal._41-MatFinal._31;
|
||||
m_ViewFrustum.m_aPlanes[4].m_Norm.Y = MatFinal._42-MatFinal._32;
|
||||
m_ViewFrustum.m_aPlanes[4].m_Norm.Z = MatFinal._43-MatFinal._33;
|
||||
m_ViewFrustum.m_aPlanes[4].m_Dist = MatFinal._44-MatFinal._34;
|
||||
|
||||
//get the NEAR plane
|
||||
m_ViewFrustum.m_aPlanes[5].m_Norm.X = MatFinal._41+MatFinal._31;
|
||||
m_ViewFrustum.m_aPlanes[5].m_Norm.Y = MatFinal._42+MatFinal._32;
|
||||
m_ViewFrustum.m_aPlanes[5].m_Norm.Z = MatFinal._43+MatFinal._33;
|
||||
m_ViewFrustum.m_aPlanes[5].m_Dist = MatFinal._44+MatFinal._34;
|
||||
}
|
||||
|
||||
void CCamera::SetViewPort (SViewPort *viewport)
|
||||
{
|
||||
m_ViewPort.m_X = viewport->m_X;
|
||||
m_ViewPort.m_Y = viewport->m_Y;
|
||||
m_ViewPort.m_Width = viewport->m_Width;
|
||||
m_ViewPort.m_Height = viewport->m_Height;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GetCameraPlanePoints: return four points in camera space at given distance from camera
|
||||
void CCamera::GetCameraPlanePoints(float dist,CVector3D pts[4]) const
|
||||
{
|
||||
float aspect=float(m_ViewPort.m_Width)/float(m_ViewPort.m_Height);
|
||||
|
||||
float x=dist*float(tan(GetFOV()*aspect*0.5));
|
||||
float y=dist*float(tan(GetFOV()*0.5));
|
||||
pts[0].X=-x;
|
||||
pts[0].Y=-y;
|
||||
pts[0].Z=dist;
|
||||
pts[1].X=x;
|
||||
pts[1].Y=-y;
|
||||
pts[1].Z=dist;
|
||||
pts[2].X=x;
|
||||
pts[2].Y=y;
|
||||
pts[2].Z=dist;
|
||||
pts[3].X=-x;
|
||||
pts[3].Y=y;
|
||||
pts[3].Z=dist;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GetFrustumPoints: calculate and return the position of the 8 points of the frustum in world space
|
||||
void CCamera::GetFrustumPoints(CVector3D pts[8]) const
|
||||
{
|
||||
// get camera space points for near and far planes
|
||||
CVector3D cpts[8];
|
||||
GetCameraPlanePoints(m_NearPlane,pts);
|
||||
GetCameraPlanePoints(m_FarPlane,pts+4);
|
||||
|
||||
// transform to world space
|
||||
for (int i=0;i<8;i++) {
|
||||
m_Orientation.Transform(cpts[i],pts[i]);
|
||||
}
|
||||
}
|
78
source/graphics/Camera.h
Executable file
78
source/graphics/Camera.h
Executable file
@ -0,0 +1,78 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Camera.H
|
||||
// Last Update: 24/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: CCamera holds a view and a projection matrix.
|
||||
// It also has a frustum which can be used to
|
||||
// cull objects for rendering.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef CAMERA_H
|
||||
#define CAMERA_H
|
||||
|
||||
#include "Frustum.h"
|
||||
#include "Matrix3D.h"
|
||||
|
||||
//view port
|
||||
struct SViewPort
|
||||
{
|
||||
unsigned int m_X;
|
||||
unsigned int m_Y;
|
||||
unsigned int m_Width;
|
||||
unsigned int m_Height;
|
||||
};
|
||||
|
||||
|
||||
class CCamera
|
||||
{
|
||||
public:
|
||||
CCamera ();
|
||||
~CCamera ();
|
||||
|
||||
//Methods for projection
|
||||
void SetProjection (CMatrix3D *proj) { m_ProjMat = *proj; }
|
||||
void SetProjection (float nearp, float farp, float fov);
|
||||
CMatrix3D GetProjection () { return m_ProjMat; }
|
||||
|
||||
//Updates the frustum planes. Should be called
|
||||
//everytime the view or projection matrices are
|
||||
//altered.
|
||||
void UpdateFrustum ();
|
||||
CFrustum GetFustum () { return m_ViewFrustum; }
|
||||
|
||||
void SetViewPort (SViewPort *viewport);
|
||||
SViewPort GetViewPort () { return m_ViewPort; }
|
||||
|
||||
//getters
|
||||
float GetNearPlane() const { return m_NearPlane; }
|
||||
float GetFarPlane() const { return m_FarPlane; }
|
||||
float GetFOV() const { return m_FOV; }
|
||||
|
||||
// calculate and return the position of the 8 points of the frustum in world space
|
||||
void GetFrustumPoints(CVector3D pts[8]) const;
|
||||
|
||||
// return four points in camera space at given distance from camera
|
||||
void GetCameraPlanePoints(float dist,CVector3D pts[4]) const;
|
||||
|
||||
public:
|
||||
//This is the orientation matrix. The inverse of this
|
||||
//is the view matrix
|
||||
CMatrix3D m_Orientation;
|
||||
|
||||
private:
|
||||
//keep the projection matrix private
|
||||
//so we can't fiddle with it.
|
||||
CMatrix3D m_ProjMat;
|
||||
|
||||
float m_NearPlane;
|
||||
float m_FarPlane;
|
||||
float m_FOV;
|
||||
SViewPort m_ViewPort;
|
||||
|
||||
CFrustum m_ViewFrustum;
|
||||
};
|
||||
|
||||
#endif
|
30
source/graphics/Color.h
Executable file
30
source/graphics/Color.h
Executable file
@ -0,0 +1,30 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: Color.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _COLOR_H
|
||||
#define _COLOR_H
|
||||
|
||||
#include "Vector3D.h"
|
||||
#include "Vector4D.h"
|
||||
|
||||
// simple defines for 3 and 4 component floating point colors - just map to
|
||||
// corresponding vector types
|
||||
typedef CVector3D RGBColor;
|
||||
typedef CVector4D RGBAColor;
|
||||
|
||||
// SColor4ub: structure for packed RGBA colors
|
||||
struct SColor4ub
|
||||
{
|
||||
u8 R;
|
||||
u8 G;
|
||||
u8 B;
|
||||
u8 A;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
144
source/graphics/Frustum.cpp
Executable file
144
source/graphics/Frustum.cpp
Executable file
@ -0,0 +1,144 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Frustum.Cpp
|
||||
// Last Update: 24/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: CFrustum is a collection of planes which define
|
||||
// a viewing space. Usually associated with the
|
||||
// camera, there are 6 planes which define the
|
||||
// view pyramid. But we allow more planes per
|
||||
// frustum which maybe used for portal rendering,
|
||||
// where a portal may have 3 or more edges.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#include "Frustum.h"
|
||||
|
||||
CFrustum::CFrustum ()
|
||||
{
|
||||
m_NumPlanes = 0;
|
||||
}
|
||||
|
||||
CFrustum::~CFrustum ()
|
||||
{
|
||||
}
|
||||
|
||||
void CFrustum::SetNumPlanes (int num)
|
||||
{
|
||||
m_NumPlanes = num;
|
||||
|
||||
//clip it
|
||||
if (m_NumPlanes >= MAX_NUM_FRUSTUM_PLANES)
|
||||
m_NumPlanes = MAX_NUM_FRUSTUM_PLANES-1;
|
||||
else if (m_NumPlanes < 0)
|
||||
m_NumPlanes = 0;
|
||||
}
|
||||
|
||||
bool CFrustum::IsPointVisible (const CVector3D &point) const
|
||||
{
|
||||
PLANESIDE Side;
|
||||
|
||||
for (int i=0; i<m_NumPlanes; i++)
|
||||
{
|
||||
Side = m_aPlanes[i].ClassifyPoint (point);
|
||||
|
||||
if (Side == PS_BACK)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CFrustum::IsSphereVisible (const CVector3D ¢er, float radius) const
|
||||
{
|
||||
for (int i=0; i<m_NumPlanes; i++)
|
||||
{
|
||||
float Dist = m_aPlanes[i].DistanceToPlane (center);
|
||||
|
||||
//is it behind the plane
|
||||
if (Dist < 0)
|
||||
{
|
||||
//if non of it falls in front its outside the
|
||||
//frustum
|
||||
if (-Dist > radius)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CFrustum::IsBoxVisible (const CVector3D &position,const CBound &bounds) const
|
||||
{
|
||||
//basically for every plane we calculate the furthust point
|
||||
//in the box to that plane. If that point is beyond the plane
|
||||
//then the box is not visible
|
||||
CVector3D FarPoint;
|
||||
PLANESIDE Side;
|
||||
CVector3D Min = position+bounds[0];
|
||||
CVector3D Max = position+bounds[1];
|
||||
|
||||
for (int i=0; i<m_NumPlanes; i++)
|
||||
{
|
||||
if (m_aPlanes[i].m_Norm.X > 0.0f)
|
||||
{
|
||||
if (m_aPlanes[i].m_Norm.Y > 0.0f)
|
||||
{
|
||||
if (m_aPlanes[i].m_Norm.Z > 0.0f)
|
||||
{
|
||||
FarPoint.X = Max.X; FarPoint.Y = Max.Y; FarPoint.Z = Max.Z;
|
||||
}
|
||||
else
|
||||
{
|
||||
FarPoint.X = Max.X; FarPoint.Y = Max.Y; FarPoint.Z = Min.Z;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_aPlanes[i].m_Norm.Z > 0.0f)
|
||||
{
|
||||
FarPoint.X = Max.X; FarPoint.Y = Min.Y; FarPoint.Z = Max.Z;
|
||||
}
|
||||
else
|
||||
{
|
||||
FarPoint.X = Max.X; FarPoint.Y = Min.Y; FarPoint.Z = Min.Z;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_aPlanes[i].m_Norm.Y > 0.0f)
|
||||
{
|
||||
if (m_aPlanes[i].m_Norm.Z > 0.0f)
|
||||
{
|
||||
FarPoint.X = Min.X; FarPoint.Y = Max.Y; FarPoint.Z = Max.Z;
|
||||
}
|
||||
else
|
||||
{
|
||||
FarPoint.X = Min.X; FarPoint.Y = Max.Y; FarPoint.Z = Min.Z;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_aPlanes[i].m_Norm.Z > 0.0f)
|
||||
{
|
||||
FarPoint.X = Min.X; FarPoint.Y = Min.Y; FarPoint.Z = Max.Z;
|
||||
}
|
||||
else
|
||||
{
|
||||
FarPoint.X = Min.X; FarPoint.Y = Min.Y; FarPoint.Z = Min.Z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Side = m_aPlanes[i].ClassifyPoint (FarPoint);
|
||||
|
||||
if (Side == PS_BACK)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
51
source/graphics/Frustum.h
Executable file
51
source/graphics/Frustum.h
Executable file
@ -0,0 +1,51 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Frustum.H
|
||||
// Last Update: 24/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: CFrustum is a collection of planes which define
|
||||
// a viewing space. Usually associated with the
|
||||
// camera, there are 6 planes which define the
|
||||
// view pyramid. But we allow more planes per
|
||||
// frustum which maybe used for portal rendering,
|
||||
// where a portal may have 3 or more edges.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef FRUSTUM_H
|
||||
#define FRUSTUM_H
|
||||
|
||||
#include "Plane.h"
|
||||
#include "Bound.h"
|
||||
|
||||
//10 planes should be enough
|
||||
#define MAX_NUM_FRUSTUM_PLANES (10)
|
||||
|
||||
|
||||
class CFrustum
|
||||
{
|
||||
public:
|
||||
CFrustum ();
|
||||
~CFrustum ();
|
||||
|
||||
//Set the number of planes to use for
|
||||
//calculations. This is clipped to
|
||||
//[0,MAX_NUM_FRUSTUM_PLANES]
|
||||
void SetNumPlanes (int num);
|
||||
|
||||
//The following methods return true if the shape is
|
||||
//partially or completely in front of the frustum planes
|
||||
bool IsPointVisible (const CVector3D &point) const;
|
||||
bool IsSphereVisible (const CVector3D ¢er, float radius) const;
|
||||
bool IsBoxVisible (const CVector3D &position,const CBound &bounds) const;
|
||||
|
||||
public:
|
||||
//make the planes public for ease of use
|
||||
CPlane m_aPlanes[MAX_NUM_FRUSTUM_PLANES];
|
||||
|
||||
private:
|
||||
int m_NumPlanes;
|
||||
};
|
||||
|
||||
#endif
|
177
source/graphics/HFTracer.cpp
Executable file
177
source/graphics/HFTracer.cpp
Executable file
@ -0,0 +1,177 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: HFTracer.cpp
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "HFTracer.h"
|
||||
#include "Terrain.h"
|
||||
#include "Bound.h"
|
||||
#include "Vector3D.h"
|
||||
|
||||
extern CTerrain g_Terrain;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CHFTracer constructor
|
||||
CHFTracer::CHFTracer(const u16* hf,u32 mapsize,float cellsize,float heightscale)
|
||||
: m_Heightfield(hf), m_MapSize(mapsize), m_CellSize(cellsize),
|
||||
m_HeightScale(heightscale)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RayTriIntersect: intersect a ray with triangle defined by vertices
|
||||
// v0,v1,v2; return true if ray hits triangle at distance less than dist,
|
||||
// or false otherwise
|
||||
bool CHFTracer::RayTriIntersect(const CVector3D& v0,const CVector3D& v1,const CVector3D& v2,
|
||||
const CVector3D& origin,const CVector3D& dir,float& dist) const
|
||||
{
|
||||
const float EPSILON=0.00001f;
|
||||
|
||||
// calculate edge vectors
|
||||
CVector3D edge0=v1-v0;
|
||||
CVector3D edge1=v2-v0;
|
||||
|
||||
// begin calculating determinant - also used to calculate U parameter
|
||||
CVector3D pvec=dir.Cross(edge1);
|
||||
|
||||
// if determinant is near zero, ray lies in plane of triangle
|
||||
float det = edge0.Dot(pvec);
|
||||
if (fabs(det)<EPSILON)
|
||||
return false;
|
||||
|
||||
float inv_det = 1.0f/det;
|
||||
|
||||
// calculate vector from vert0 to ray origin
|
||||
CVector3D tvec=origin-v0;
|
||||
|
||||
// calculate U parameter, test bounds
|
||||
float u=tvec.Dot(pvec)*inv_det;
|
||||
if (u<-0.01f || u>1.01f)
|
||||
return false;
|
||||
|
||||
// prepare to test V parameter
|
||||
CVector3D qvec=tvec.Cross(edge0);
|
||||
|
||||
// calculate V parameter and test bounds
|
||||
float v=dir.Dot(qvec)*inv_det;
|
||||
if (v<0.0f || u+v>1.0f)
|
||||
return false;
|
||||
|
||||
// calculate distance to intersection point from ray origin
|
||||
float d=edge1.Dot(qvec)*inv_det;
|
||||
if (d>=0 && d<dist) {
|
||||
dist=d;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CellIntersect: test if ray intersects either of the triangles in the given
|
||||
// cell - return hit result, and distance to hit, if hit occurred
|
||||
bool CHFTracer::CellIntersect(int cx,int cz,CVector3D& origin,CVector3D& dir,float& dist) const
|
||||
{
|
||||
bool res=false;
|
||||
|
||||
// get vertices for this cell
|
||||
CVector3D vpos[4];
|
||||
g_Terrain.CalcPosition(cx,cz,vpos[0]);
|
||||
g_Terrain.CalcPosition(cx+1,cz,vpos[1]);
|
||||
g_Terrain.CalcPosition(cx+1,cz+1,vpos[2]);
|
||||
g_Terrain.CalcPosition(cx,cz+1,vpos[3]);
|
||||
|
||||
dist=1.0e30f;
|
||||
if (RayTriIntersect(vpos[0],vpos[1],vpos[2],origin,dir,dist)) {
|
||||
res=true;
|
||||
}
|
||||
|
||||
if (RayTriIntersect(vpos[0],vpos[2],vpos[3],origin,dir,dist)) {
|
||||
res=true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RayIntersect: intersect ray with this heightfield; return true if
|
||||
// intersection occurs (and fill in grid coordinates of intersection), or false
|
||||
// otherwise
|
||||
bool CHFTracer::RayIntersect(CVector3D& origin,CVector3D& dir,int& x,int& z,CVector3D& ipt) const
|
||||
{
|
||||
// intersect first against bounding box
|
||||
CBound bound;
|
||||
bound[0]=CVector3D(0,0,0);
|
||||
bound[1]=CVector3D(m_MapSize*m_CellSize,65535*m_HeightScale,m_MapSize*m_CellSize);
|
||||
|
||||
float tmin,tmax;
|
||||
if (!bound.RayIntersect(origin,dir,tmin,tmax)) {
|
||||
// ray missed world bounds; no intersection
|
||||
return false;
|
||||
}
|
||||
|
||||
// project origin onto grid, if necessary, to get starting point for traversal
|
||||
CVector3D traversalPt;
|
||||
if (tmin>0) {
|
||||
traversalPt=origin+dir*tmin;
|
||||
} else {
|
||||
traversalPt=origin;
|
||||
}
|
||||
|
||||
// setup traversal variables
|
||||
int sx=dir.X<0 ? -1 : 1;
|
||||
int sz=dir.Z<0 ? -1 : 1;
|
||||
|
||||
float invCellSize=1.0f/float(m_CellSize);
|
||||
|
||||
float fcx=traversalPt.X*invCellSize;
|
||||
int cx=int(fcx);
|
||||
|
||||
float fcz=traversalPt.Z*invCellSize;
|
||||
int cz=int(fcz);
|
||||
|
||||
float invdx=float(1.0/fabs(dir.X));
|
||||
float invdz=float(1.0/fabs(dir.Z));
|
||||
|
||||
float dist;
|
||||
do {
|
||||
// test current cell
|
||||
if (cx>=0 && cx<int(m_MapSize-1) && cz>=0 && cz<int(m_MapSize-1)) {
|
||||
if (CellIntersect(cx,cz,origin,dir,dist)) {
|
||||
x=cx;
|
||||
z=cz;
|
||||
ipt=origin+dir*dist;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// get coords of current cell
|
||||
fcx=traversalPt.X*invCellSize;
|
||||
fcz=traversalPt.Z*invCellSize;
|
||||
|
||||
// get distance to next cell in x,z
|
||||
float dx=(sx==-1) ? fcx-float(cx) : 1-(fcx-float(cx));
|
||||
dx*=invdx;
|
||||
float dz=(sz==-1) ? fcz-float(cz) : 1-(fcz-float(cz));
|
||||
dz*=invdz;
|
||||
|
||||
// advance ..
|
||||
float dist;
|
||||
if (dx<dz) {
|
||||
cx+=sx;
|
||||
dist=dx;
|
||||
} else {
|
||||
cz+=sz;
|
||||
dist=dz;
|
||||
}
|
||||
|
||||
traversalPt+=dir*dist;
|
||||
} while (traversalPt.Y>=0);
|
||||
|
||||
// fell off end of heightmap with no intersection; return a miss
|
||||
return false;
|
||||
}
|
48
source/graphics/HFTracer.h
Executable file
48
source/graphics/HFTracer.h
Executable file
@ -0,0 +1,48 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: HFTracer.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _HFTRACER_H
|
||||
#define _HFTRACER_H
|
||||
|
||||
class CVector3D;
|
||||
|
||||
#include "res/res.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CHFTracer: a class for determining ray intersections with a heightfield
|
||||
class CHFTracer
|
||||
{
|
||||
public:
|
||||
// constructor; setup data
|
||||
CHFTracer(const u16* hf,u32 mapsize,float cellsize,float heightscale);
|
||||
|
||||
// intersect ray with this heightfield; return true if intersection
|
||||
// occurs (and fill in grid coordinates and point of intersection), or false otherwise
|
||||
bool RayIntersect(CVector3D& origin,CVector3D& dir,int& x,int& z,CVector3D& ipt) const;
|
||||
|
||||
private:
|
||||
// intersect a ray with triangle defined by vertices
|
||||
// v0,v1,v2; return true if ray hits triangle at distance less than dist,
|
||||
// or false otherwise
|
||||
bool RayTriIntersect(const CVector3D& v0,const CVector3D& v1,const CVector3D& v2,
|
||||
const CVector3D& origin,const CVector3D& dir,float& dist) const;
|
||||
|
||||
// test if ray intersects either of the triangles in the given
|
||||
bool CellIntersect(int cx,int cz,CVector3D& origin,CVector3D& dir,float& dist) const;
|
||||
|
||||
// the heightfield were tracing
|
||||
const u16* m_Heightfield;
|
||||
// size of the heightfield
|
||||
u32 m_MapSize;
|
||||
// cell size - size of each cell in x and z
|
||||
float m_CellSize;
|
||||
// vertical scale - size of each cell in y
|
||||
float m_HeightScale;
|
||||
};
|
||||
|
||||
#endif
|
47
source/graphics/LightEnv.h
Executable file
47
source/graphics/LightEnv.h
Executable file
@ -0,0 +1,47 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: LightEnv.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@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"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CLightEnv: description of a lighting environment - contains all the
|
||||
// necessary parameters for representation of the lighting within a scenario
|
||||
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
|
35
source/graphics/MapIO.h
Executable file
35
source/graphics/MapIO.h
Executable file
@ -0,0 +1,35 @@
|
||||
#ifndef _MAPIO_H
|
||||
#define _MAPIO_H
|
||||
|
||||
class CMapIO
|
||||
{
|
||||
public:
|
||||
// current file version given to saved maps
|
||||
enum { FILE_VERSION = 2 };
|
||||
// supported file read version - file with version less than this will be reject
|
||||
enum { FILE_READ_VERSION = 1 };
|
||||
|
||||
#pragma pack(push, 1)
|
||||
// description of a tile for I/O purposes
|
||||
struct STileDesc {
|
||||
// index into the texture array of first texture on tile
|
||||
u16 m_Tex1Index;
|
||||
// index into the texture array of second texture; (0xffff) if none
|
||||
u16 m_Tex2Index;
|
||||
// priority
|
||||
u32 m_Priority;
|
||||
};
|
||||
|
||||
// description of an object for I/O purposes
|
||||
struct SObjectDesc {
|
||||
// index into the object array
|
||||
u16 m_ObjectIndex;
|
||||
// transformation matrix
|
||||
float m_Transform[16];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
186
source/graphics/MapReader.cpp
Executable file
186
source/graphics/MapReader.cpp
Executable file
@ -0,0 +1,186 @@
|
||||
// switch off warnings before including stl files
|
||||
#pragma warning(disable : 4786) // identifier truncated to 255 chars
|
||||
|
||||
#include "Types.h"
|
||||
#include "MapReader.h"
|
||||
#include "UnitManager.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "BaseEntity.h"
|
||||
#include "BaseEntityCollection.h"
|
||||
#include "EntityManager.h"
|
||||
|
||||
#include "Model.h"
|
||||
#include "Terrain.h"
|
||||
#include "TextureManager.h"
|
||||
|
||||
extern CTerrain g_Terrain;
|
||||
extern CLightEnv g_LightEnv;
|
||||
|
||||
#include <set>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
// CMapReader constructor: nothing to do at the minute
|
||||
CMapReader::CMapReader()
|
||||
{
|
||||
}
|
||||
|
||||
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful
|
||||
void CMapReader::LoadMap(const char* filename)
|
||||
{
|
||||
CFileUnpacker unpacker;
|
||||
unpacker.Read(filename,"PSMP");
|
||||
|
||||
// check version
|
||||
if (unpacker.GetVersion()<FILE_READ_VERSION) {
|
||||
throw CFileUnpacker::CFileVersionError();
|
||||
}
|
||||
|
||||
// unpack the data
|
||||
UnpackMap(unpacker);
|
||||
|
||||
// finally, apply data to the world
|
||||
ApplyData(unpacker);
|
||||
}
|
||||
|
||||
// UnpackMap: unpack the given data from the raw data stream into local variables
|
||||
void CMapReader::UnpackMap(CFileUnpacker& unpacker)
|
||||
{
|
||||
// now unpack everything into local data
|
||||
UnpackTerrain(unpacker);
|
||||
UnpackObjects(unpacker);
|
||||
if (unpacker.GetVersion()>=2) {
|
||||
UnpackLightEnv(unpacker);
|
||||
}
|
||||
}
|
||||
|
||||
// UnpackLightEnv: unpack lighting parameters from input stream
|
||||
void CMapReader::UnpackLightEnv(CFileUnpacker& unpacker)
|
||||
{
|
||||
unpacker.UnpackRaw(&m_LightEnv.m_SunColor,sizeof(m_LightEnv.m_SunColor));
|
||||
unpacker.UnpackRaw(&m_LightEnv.m_Elevation,sizeof(m_LightEnv.m_Elevation));
|
||||
unpacker.UnpackRaw(&m_LightEnv.m_Rotation,sizeof(m_LightEnv.m_Rotation));
|
||||
unpacker.UnpackRaw(&m_LightEnv.m_TerrainAmbientColor,sizeof(m_LightEnv.m_TerrainAmbientColor));
|
||||
unpacker.UnpackRaw(&m_LightEnv.m_UnitsAmbientColor,sizeof(m_LightEnv.m_UnitsAmbientColor));
|
||||
}
|
||||
|
||||
// UnpackObjects: unpack world objects from input stream
|
||||
void CMapReader::UnpackObjects(CFileUnpacker& unpacker)
|
||||
{
|
||||
// unpack object types
|
||||
u32 numObjTypes;
|
||||
unpacker.UnpackRaw(&numObjTypes,sizeof(numObjTypes));
|
||||
m_ObjectTypes.resize(numObjTypes);
|
||||
for (uint i=0;i<numObjTypes;i++) {
|
||||
CStr objname;
|
||||
unpacker.UnpackString(objname);
|
||||
|
||||
CObjectEntry* object=g_ObjMan.FindObject((const char*) objname);
|
||||
m_ObjectTypes[i]=object;
|
||||
}
|
||||
|
||||
// unpack object data
|
||||
u32 numObjects;
|
||||
unpacker.UnpackRaw(&numObjects,sizeof(numObjects));
|
||||
m_Objects.resize(numObjects);
|
||||
unpacker.UnpackRaw(&m_Objects[0],sizeof(SObjectDesc)*numObjects);
|
||||
}
|
||||
|
||||
// UnpackTerrain: unpack the terrain from the end of the input data stream
|
||||
// - data: map size, heightmap, list of textures used by map, texture tile assignments
|
||||
void CMapReader::UnpackTerrain(CFileUnpacker& unpacker)
|
||||
{
|
||||
// unpack map size
|
||||
unpacker.UnpackRaw(&m_MapSize,sizeof(m_MapSize));
|
||||
|
||||
// unpack heightmap
|
||||
u32 verticesPerSide=m_MapSize*PATCH_SIZE+1;
|
||||
m_Heightmap.resize(SQR(verticesPerSide));
|
||||
unpacker.UnpackRaw(&m_Heightmap[0],SQR(verticesPerSide)*sizeof(u16));
|
||||
|
||||
// unpack texture names; find handle for each texture
|
||||
u32 numTextures;
|
||||
unpacker.UnpackRaw(&numTextures,sizeof(numTextures));
|
||||
|
||||
m_TerrainTextures.reserve(numTextures);
|
||||
for (uint i=0;i<numTextures;i++) {
|
||||
CStr texturename;
|
||||
unpacker.UnpackString(texturename);
|
||||
|
||||
Handle handle;
|
||||
CTextureEntry* texentry=g_TexMan.FindTexture(texturename);
|
||||
if (!texentry) {
|
||||
// ack; mismatch between texture datasets?
|
||||
handle=0;
|
||||
} else {
|
||||
handle=texentry->m_Handle;
|
||||
}
|
||||
m_TerrainTextures.push_back(handle);
|
||||
}
|
||||
|
||||
// unpack tile data
|
||||
u32 tilesPerSide=m_MapSize*PATCH_SIZE;
|
||||
m_Tiles.resize(SQR(tilesPerSide));
|
||||
unpacker.UnpackRaw(&m_Tiles[0],sizeof(STileDesc)*m_Tiles.size());
|
||||
}
|
||||
|
||||
// ApplyData: take all the input data, and rebuild the scene from it
|
||||
void CMapReader::ApplyData(CFileUnpacker& unpacker)
|
||||
{
|
||||
// initialise the terrain
|
||||
g_Terrain.Initialize(m_MapSize,&m_Heightmap[0]);
|
||||
|
||||
// setup the textures on the minipatches
|
||||
STileDesc* tileptr=&m_Tiles[0];
|
||||
for (u32 j=0;j<m_MapSize;j++) {
|
||||
for (u32 i=0;i<m_MapSize;i++) {
|
||||
for (u32 m=0;m<PATCH_SIZE;m++) {
|
||||
for (u32 k=0;k<PATCH_SIZE;k++) {
|
||||
CMiniPatch& mp=g_Terrain.GetPatch(i,j)->m_MiniPatches[m][k];
|
||||
|
||||
mp.Tex1=m_TerrainTextures[tileptr->m_Tex1Index];
|
||||
mp.Tex1Priority=tileptr->m_Priority;
|
||||
|
||||
tileptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// empty out existing units
|
||||
g_UnitMan.DeleteAll();
|
||||
|
||||
// add new objects
|
||||
for (u32 i=0;i<m_Objects.size();i++) {
|
||||
CObjectEntry* objentry=m_ObjectTypes[m_Objects[i].m_ObjectIndex];
|
||||
if (objentry && objentry->m_Model) {
|
||||
// Hijack the standard actor instantiation for actors that correspond to entities.
|
||||
// Not an ideal solution; we'll have to figure out a map format that can define entities seperately or somesuch.
|
||||
|
||||
CBaseEntity* templateObject = g_EntityTemplateCollection.getTemplateByActor( objentry );
|
||||
if( templateObject )
|
||||
{
|
||||
CVector3D orient = ((CMatrix3D*)m_Objects[i].m_Transform)->GetIn();
|
||||
CVector3D position = ((CMatrix3D*)m_Objects[i].m_Transform)->GetTranslation();
|
||||
|
||||
g_EntityManager.create( templateObject, position, atan2( orient.X, orient.Z ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
CUnit* unit=new CUnit(objentry,objentry->m_Model->Clone());
|
||||
|
||||
CMatrix3D transform;
|
||||
memcpy(&transform._11,m_Objects[i].m_Transform,sizeof(float)*16);
|
||||
unit->GetModel()->SetTransform(transform);
|
||||
|
||||
// add this unit to list of units stored in unit manager
|
||||
g_UnitMan.AddUnit(unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (unpacker.GetVersion()>=2) {
|
||||
// copy over the lighting parameters
|
||||
g_LightEnv=m_LightEnv;
|
||||
}
|
||||
}
|
48
source/graphics/MapReader.h
Executable file
48
source/graphics/MapReader.h
Executable file
@ -0,0 +1,48 @@
|
||||
#ifndef _MAPREADER_H
|
||||
#define _MAPREADER_H
|
||||
|
||||
#include "MapIO.h"
|
||||
#include "CStr.h"
|
||||
#include "LightEnv.h"
|
||||
#include "FileUnpacker.h"
|
||||
|
||||
class CObjectEntry;
|
||||
|
||||
class CMapReader : public CMapIO
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CMapReader();
|
||||
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful
|
||||
void LoadMap(const char* filename);
|
||||
|
||||
private:
|
||||
// UnpackMap: unpack the given data from the raw data stream into local variables
|
||||
void UnpackMap(CFileUnpacker& unpacker);
|
||||
// UnpackTerrain: unpack the terrain from the input stream
|
||||
void UnpackTerrain(CFileUnpacker& unpacker);
|
||||
// UnpackObjects: unpack world objects from the input stream
|
||||
void UnpackObjects(CFileUnpacker& unpacker);
|
||||
// UnpackObjects: unpack lighting parameters from the input stream
|
||||
void UnpackLightEnv(CFileUnpacker& unpacker);
|
||||
|
||||
// ApplyData: take all the input data, and rebuild the scene from it
|
||||
void ApplyData(CFileUnpacker& unpacker);
|
||||
|
||||
// size of map
|
||||
u32 m_MapSize;
|
||||
// heightmap for map
|
||||
std::vector<u16> m_Heightmap;
|
||||
// list of terrain textures used by map
|
||||
std::vector<Handle> m_TerrainTextures;
|
||||
// tile descriptions for each tile
|
||||
std::vector<STileDesc> m_Tiles;
|
||||
// list of object types used by map
|
||||
std::vector<CObjectEntry*> m_ObjectTypes;
|
||||
// descriptions for each objects
|
||||
std::vector<SObjectDesc> m_Objects;
|
||||
// lightenv stored in file
|
||||
CLightEnv m_LightEnv;
|
||||
};
|
||||
|
||||
#endif
|
226
source/graphics/MapWriter.cpp
Executable file
226
source/graphics/MapWriter.cpp
Executable file
@ -0,0 +1,226 @@
|
||||
// switch off warnings before including stl files
|
||||
#pragma warning(disable : 4786) // identifier truncated to 255 chars
|
||||
|
||||
#include "Types.h"
|
||||
#include "MapWriter.h"
|
||||
#include "UnitManager.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "Model.h"
|
||||
#include "Terrain.h"
|
||||
#include "LightEnv.h"
|
||||
#include "TextureManager.h"
|
||||
|
||||
extern CTerrain g_Terrain;
|
||||
extern CLightEnv g_LightEnv;
|
||||
|
||||
#include <set>
|
||||
#include <stdio.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CMapWriter constructor: nothing to do at the minute
|
||||
CMapWriter::CMapWriter()
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SaveMap: try to save the current map to the given file
|
||||
void CMapWriter::SaveMap(const char* filename)
|
||||
{
|
||||
CFilePacker packer;
|
||||
|
||||
// build necessary data
|
||||
PackMap(packer);
|
||||
|
||||
// write it out
|
||||
packer.Write(filename,FILE_VERSION,"PSMP");
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GetHandleIndex: return the index of the given handle in the given list; or 0xffff if
|
||||
// handle isn't in list
|
||||
static u16 GetHandleIndex(const Handle handle,const std::vector<Handle>& handles)
|
||||
{
|
||||
for (uint i=0;i<handles.size();i++) {
|
||||
if (handles[i]==handle) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GetObjectIndex: return the index of the given object in the given list; or 0xffff if
|
||||
// object isn't in list
|
||||
static u16 GetObjectIndex(const CObjectEntry* object,const std::vector<CObjectEntry*>& objects)
|
||||
{
|
||||
for (uint i=0;i<objects.size();i++) {
|
||||
if (objects[i]==object) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// EnumTerrainTextures: build lists of textures used by map, and tile descriptions for
|
||||
// each tile on the terrain
|
||||
void CMapWriter::EnumTerrainTextures(std::vector<CStr>& textures,
|
||||
std::vector<STileDesc>& tiles)
|
||||
{
|
||||
// the list of all handles in use
|
||||
std::vector<Handle> handles;
|
||||
|
||||
// resize tile array to required size
|
||||
tiles.resize(SQR(g_Terrain.GetVerticesPerSide()-1));
|
||||
STileDesc* tileptr=&tiles[0];
|
||||
|
||||
// now iterate through all the tiles
|
||||
u32 mapsize=g_Terrain.GetPatchesPerSide();
|
||||
for (u32 j=0;j<mapsize;j++) {
|
||||
for (u32 i=0;i<mapsize;i++) {
|
||||
for (u32 m=0;m<PATCH_SIZE;m++) {
|
||||
for (u32 k=0;k<PATCH_SIZE;k++) {
|
||||
CMiniPatch& mp=g_Terrain.GetPatch(i,j)->m_MiniPatches[m][k];
|
||||
u16 index=u16(GetHandleIndex(mp.Tex1,handles));
|
||||
if (index==0xffff) {
|
||||
index=handles.size();
|
||||
handles.push_back(mp.Tex1);
|
||||
}
|
||||
|
||||
tileptr->m_Tex1Index=index;
|
||||
tileptr->m_Tex2Index=0xffff;
|
||||
tileptr->m_Priority=mp.Tex1Priority;
|
||||
tileptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now find the texture names for each handle
|
||||
for (uint i=0;i<handles.size();i++) {
|
||||
CStr texturename;
|
||||
CTextureEntry* texentry=g_TexMan.FindTexture(handles[i]);
|
||||
if (!texentry) {
|
||||
// uh-oh, this shouldn't happen; set texturename to empty string
|
||||
texturename="";
|
||||
} else {
|
||||
texturename=texentry->m_Name;
|
||||
}
|
||||
textures.push_back(texturename);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// EnumObjects: build lists of object types used by map, and object descriptions for
|
||||
// each object in the world
|
||||
void CMapWriter::EnumObjects(std::vector<CStr>& objectTypes,std::vector<SObjectDesc>& objects)
|
||||
{
|
||||
// the list of all object entries in use
|
||||
std::vector<CObjectEntry*> objectsInUse;
|
||||
|
||||
// resize object array to required size
|
||||
const std::vector<CUnit*>& units=g_UnitMan.GetUnits();
|
||||
objects.resize(units.size());
|
||||
SObjectDesc* objptr=&objects[0];
|
||||
|
||||
// now iterate through all the units
|
||||
for (u32 j=0;j<units.size();j++) {
|
||||
CUnit* unit=units[j];
|
||||
|
||||
u16 index=u16(GetObjectIndex(unit->GetObject(),objectsInUse));
|
||||
if (index==0xffff) {
|
||||
index=objectsInUse.size();
|
||||
objectsInUse.push_back(unit->GetObject());
|
||||
}
|
||||
|
||||
objptr->m_ObjectIndex=index;
|
||||
memcpy(objptr->m_Transform,&unit->GetModel()->GetTransform()._11,sizeof(float)*16);
|
||||
objptr++;
|
||||
}
|
||||
|
||||
// now build outgoing objectTypes array
|
||||
for (uint i=0;i<objectsInUse.size();i++) {
|
||||
objectTypes.push_back(objectsInUse[i]->m_Name);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PackMap: pack the current world into a raw data stream
|
||||
void CMapWriter::PackMap(CFilePacker& packer)
|
||||
{
|
||||
// now pack everything up
|
||||
PackTerrain(packer);
|
||||
PackObjects(packer);
|
||||
PackLightEnv(packer);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PackLightEnv: pack lighting parameters onto the end of the output data stream
|
||||
void CMapWriter::PackLightEnv(CFilePacker& packer)
|
||||
{
|
||||
packer.PackRaw(&g_LightEnv.m_SunColor,sizeof(g_LightEnv.m_SunColor));
|
||||
packer.PackRaw(&g_LightEnv.m_Elevation,sizeof(g_LightEnv.m_Elevation));
|
||||
packer.PackRaw(&g_LightEnv.m_Rotation,sizeof(g_LightEnv.m_Rotation));
|
||||
packer.PackRaw(&g_LightEnv.m_TerrainAmbientColor,sizeof(g_LightEnv.m_TerrainAmbientColor));
|
||||
packer.PackRaw(&g_LightEnv.m_UnitsAmbientColor,sizeof(g_LightEnv.m_UnitsAmbientColor));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PackObjects: pack world objects onto the end of the output data stream
|
||||
// - data: list of objects types used by map, list of object descriptions
|
||||
void CMapWriter::PackObjects(CFilePacker& packer)
|
||||
{
|
||||
// the list of object types used by map
|
||||
std::vector<CStr> objectTypes;
|
||||
// descriptions of each object
|
||||
std::vector<SObjectDesc> objects;
|
||||
|
||||
// build lists by scanning through the world
|
||||
EnumObjects(objectTypes,objects);
|
||||
|
||||
// pack object types
|
||||
u32 numObjTypes=objectTypes.size();
|
||||
packer.PackRaw(&numObjTypes,sizeof(numObjTypes));
|
||||
for (uint i=0;i<numObjTypes;i++) {
|
||||
packer.PackString(objectTypes[i]);
|
||||
}
|
||||
|
||||
// pack object data
|
||||
u32 numObjects=objects.size();
|
||||
packer.PackRaw(&numObjects,sizeof(numObjects));
|
||||
packer.PackRaw(&objects[0],sizeof(SObjectDesc)*numObjects);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PackTerrain: pack the terrain onto the end of the output data stream
|
||||
// - data: map size, heightmap, list of textures used by map, texture tile assignments
|
||||
void CMapWriter::PackTerrain(CFilePacker& packer)
|
||||
{
|
||||
// pack map size
|
||||
u32 mapsize=g_Terrain.GetPatchesPerSide();
|
||||
packer.PackRaw(&mapsize,sizeof(mapsize));
|
||||
|
||||
// pack heightmap
|
||||
packer.PackRaw(g_Terrain.GetHeightMap(),sizeof(u16)*SQR(g_Terrain.GetVerticesPerSide()));
|
||||
|
||||
// the list of textures used by map
|
||||
std::vector<CStr> terrainTextures;
|
||||
// descriptions of each tile
|
||||
std::vector<STileDesc> tiles;
|
||||
|
||||
// build lists by scanning through the terrain
|
||||
EnumTerrainTextures(terrainTextures,tiles);
|
||||
|
||||
// pack texture names
|
||||
u32 numTextures=terrainTextures.size();
|
||||
packer.PackRaw(&numTextures,sizeof(numTextures));
|
||||
for (uint i=0;i<numTextures;i++) {
|
||||
packer.PackString(terrainTextures[i]);
|
||||
}
|
||||
|
||||
// pack tile data
|
||||
packer.PackRaw(&tiles[0],sizeof(STileDesc)*tiles.size());
|
||||
}
|
||||
|
36
source/graphics/MapWriter.h
Executable file
36
source/graphics/MapWriter.h
Executable file
@ -0,0 +1,36 @@
|
||||
#ifndef _MAPWRITER_H
|
||||
#define _MAPWRITER_H
|
||||
|
||||
#include <vector>
|
||||
#include "MapIO.h"
|
||||
#include "CStr.h"
|
||||
#include "FilePacker.h"
|
||||
|
||||
class CMapWriter : public CMapIO
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CMapWriter();
|
||||
// SaveMap: try to save the current map to the given file
|
||||
void SaveMap(const char* filename);
|
||||
|
||||
private:
|
||||
// PackMap: pack the current world into a raw data stream
|
||||
void PackMap(CFilePacker& packer);
|
||||
// PackTerrain: pack the terrain onto the end of the data stream
|
||||
void PackTerrain(CFilePacker& packer);
|
||||
// PackObjects: pack world objects onto the end of the output data stream
|
||||
void PackObjects(CFilePacker& packer);
|
||||
// PackLightEnv: pack lighting parameters onto the end of the output data stream
|
||||
void PackLightEnv(CFilePacker& packer);
|
||||
|
||||
// EnumTerrainTextures: build lists of textures used by map, and indices into this list
|
||||
// for each tile on the terrain
|
||||
void EnumTerrainTextures(std::vector<CStr>& textures,std::vector<STileDesc>& tileIndices);
|
||||
|
||||
// EnumObjects: build lists of object types used by map, and object descriptions for
|
||||
// each object in the world
|
||||
void EnumObjects(std::vector<CStr>& objectTypes,std::vector<SObjectDesc>& objects);
|
||||
};
|
||||
|
||||
#endif
|
34
source/graphics/MiniPatch.cpp
Executable file
34
source/graphics/MiniPatch.cpp
Executable file
@ -0,0 +1,34 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: MiniPatch.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "MiniPatch.h"
|
||||
#include "Patch.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
CMiniPatch::CMiniPatch() : Tex1(0), Tex1Priority(0), m_Parent(0)
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Destructor
|
||||
CMiniPatch::~CMiniPatch()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GetTileIndex: get the index of this tile in the root terrain object;
|
||||
// on return, parameters x,y contain index in [0,MapSize)
|
||||
void CMiniPatch::GetTileIndex(u32& x,u32& z)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
39
source/graphics/MiniPatch.h
Executable file
39
source/graphics/MiniPatch.h
Executable file
@ -0,0 +1,39 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: MiniPatch.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MINIPATCH_H
|
||||
#define _MINIPATCH_H
|
||||
|
||||
#include "res/res.h"
|
||||
|
||||
class CPatch;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CMiniPatch: definition of a single terrain tile
|
||||
class CMiniPatch
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CMiniPatch();
|
||||
// destructor
|
||||
~CMiniPatch();
|
||||
|
||||
// get the index of this tile in the root terrain object; x,y in [0,MapSize)
|
||||
void GetTileIndex(u32& x,u32& z);
|
||||
|
||||
public:
|
||||
// texture applied to tile
|
||||
Handle Tex1;
|
||||
// 'priority' of the texture - determines drawing order of terrain textures
|
||||
int Tex1Priority;
|
||||
// parent patch
|
||||
CPatch* m_Parent;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
336
source/graphics/Model.cpp
Executable file
336
source/graphics/Model.cpp
Executable file
@ -0,0 +1,336 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: Model.cpp
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Model.h"
|
||||
#include "Quaternion.h"
|
||||
#include "Bound.h"
|
||||
#include "SkeletonAnim.h"
|
||||
#include "SkeletonAnimDef.h"
|
||||
#include "SkeletonAnimManager.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
CModel::CModel()
|
||||
: m_pModelDef(0), m_Anim(0), m_AnimTime(0),
|
||||
m_BoneMatrices(0), m_InvBoneMatrices(0), m_BoneMatricesValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Destructor
|
||||
CModel::~CModel()
|
||||
{
|
||||
ReleaseData();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ReleaseData: delete anything allocated by the model
|
||||
void CModel::ReleaseData()
|
||||
{
|
||||
delete[] m_BoneMatrices;
|
||||
delete[] m_InvBoneMatrices;
|
||||
for (size_t i=0;i<m_Props.size();i++) {
|
||||
delete m_Props[i].m_Model;
|
||||
}
|
||||
m_Props.clear();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// InitModel: setup model from given geometry
|
||||
bool CModel::InitModel(CModelDef* modeldef)
|
||||
{
|
||||
// clean up any existing data first
|
||||
ReleaseData();
|
||||
|
||||
m_pModelDef = modeldef;
|
||||
|
||||
u32 numBones=modeldef->GetNumBones();
|
||||
if (numBones>0) {
|
||||
// allocate matrices for bone transformations
|
||||
m_BoneMatrices=new CMatrix3D[numBones];
|
||||
m_InvBoneMatrices=new CMatrix3D[numBones];
|
||||
// store default pose until animation assigned
|
||||
CBoneState* defpose=modeldef->GetBones();
|
||||
for (uint i=0;i<numBones;i++) {
|
||||
CMatrix3D& m=m_BoneMatrices[i];
|
||||
m.SetIdentity();
|
||||
m.Rotate(defpose[i].m_Rotation);
|
||||
m.Translate(defpose[i].m_Translation);
|
||||
m.GetInverse(m_InvBoneMatrices[i]);
|
||||
}
|
||||
m_BoneMatricesValid=true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SkinPoint: skin the given point using the given blend and bonestate data
|
||||
static CVector3D SkinPoint(const CVector3D& pos,const SVertexBlend& blend,
|
||||
const CBoneState* bonestates)
|
||||
{
|
||||
CVector3D result(0,0,0);
|
||||
for (int i=0;i<SVertexBlend::SIZE && blend.m_Bone[i]!=0xff;i++) {
|
||||
CMatrix3D m;
|
||||
m.SetIdentity();
|
||||
m.Rotate(bonestates[blend.m_Bone[i]].m_Rotation);
|
||||
m.Translate(bonestates[blend.m_Bone[i]].m_Translation);
|
||||
|
||||
CVector3D tmp=m.Transform(pos);
|
||||
result+=tmp*blend.m_Weight[i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SkinPoint: skin the given point using the given blend and matrix data
|
||||
static CVector3D SkinPoint(const CVector3D& pos,const SVertexBlend& blend,
|
||||
const CMatrix3D* bonestates)
|
||||
{
|
||||
CVector3D result(0,0,0);
|
||||
for (int i=0;i<SVertexBlend::SIZE && blend.m_Bone[i]!=0xff;i++) {
|
||||
const CMatrix3D& m=bonestates[blend.m_Bone[i]];
|
||||
|
||||
CVector3D tmp=m.Transform(pos);
|
||||
result+=tmp*blend.m_Weight[i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CalcBound: calculate the world space bounds of this model
|
||||
void CModel::CalcBounds()
|
||||
{
|
||||
m_ObjectBounds.Transform(GetTransform(),m_Bounds);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CalcObjectBounds: calculate object space bounds of this model, based solely on vertex positions
|
||||
void CModel::CalcObjectBounds()
|
||||
{
|
||||
m_ObjectBounds.SetEmpty();
|
||||
|
||||
int numverts=m_pModelDef->GetNumVertices();
|
||||
SModelVertex* verts=m_pModelDef->GetVertices();
|
||||
|
||||
for (int i=0;i<numverts;i++) {
|
||||
m_ObjectBounds+=verts[i].m_Coords;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CalcAnimatedObjectBound: calculate bounds encompassing all vertex positions for given animation
|
||||
void CModel::CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result)
|
||||
{
|
||||
result.SetEmpty();
|
||||
|
||||
CSkeletonAnim dummyanim;
|
||||
dummyanim.m_AnimDef=anim;
|
||||
if (!SetAnimation(&dummyanim)) return;
|
||||
|
||||
int numverts=m_pModelDef->GetNumVertices();
|
||||
SModelVertex* verts=m_pModelDef->GetVertices();
|
||||
|
||||
// iterate through every frame of the animation
|
||||
for (uint j=0;j<anim->GetNumFrames();j++) {
|
||||
// extend bounds by vertex positions at the frame
|
||||
for (int i=0;i<numverts;i++) {
|
||||
CVector3D tmp=SkinPoint(verts[i].m_Coords,verts[i].m_Blend,GetBoneMatrices());
|
||||
result+=tmp;
|
||||
}
|
||||
// advance to next frame
|
||||
m_AnimTime+=anim->GetFrameTime();
|
||||
m_BoneMatricesValid=false;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BuildAnimation: load raw animation frame animation from given file, and build a
|
||||
// animation specific to this model
|
||||
CSkeletonAnim* CModel::BuildAnimation(const char* filename,float speed)
|
||||
{
|
||||
CSkeletonAnimDef* def=g_SkelAnimMan.GetAnimation(filename);
|
||||
if (!def) return 0;
|
||||
|
||||
CSkeletonAnim* anim=new CSkeletonAnim;
|
||||
anim->m_AnimDef=def;
|
||||
anim->m_Speed=speed;
|
||||
CalcAnimatedObjectBound(def,anim->m_ObjectBounds);
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Update: update this model by the given time, in seconds
|
||||
void CModel::Update(float time)
|
||||
{
|
||||
if (m_Anim && m_BoneMatrices) {
|
||||
// convert to ms and adjust for animation speed
|
||||
float animtime=time*1000*m_Anim->m_Speed;
|
||||
|
||||
// update animation time, but don't calculate bone matrices - do that (lazily) when
|
||||
// something requests them; that saves some calculation work for offscreen models,
|
||||
// and also assures the world space, inverted bone matrices (required for normal
|
||||
// skinning) are up to date with respect to m_Transform
|
||||
m_AnimTime+=animtime;
|
||||
|
||||
float duration=m_Anim->m_AnimDef->GetDuration();
|
||||
if (m_AnimTime>duration) {
|
||||
m_AnimTime=(float) fmod(m_AnimTime,duration);
|
||||
}
|
||||
|
||||
// mark vertices as dirty
|
||||
SetDirty(RENDERDATA_UPDATE_VERTICES);
|
||||
|
||||
// mark matrices as dirty
|
||||
m_BoneMatricesValid=false;
|
||||
}
|
||||
|
||||
// update props
|
||||
for (uint i=0;i<m_Props.size();i++) {
|
||||
m_Props[i].m_Model->Update(time);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GenerateBoneMatrices: calculate necessary bone transformation matrices for skinning
|
||||
void CModel::GenerateBoneMatrices()
|
||||
{
|
||||
if (!m_Anim || !m_BoneMatrices) return;
|
||||
|
||||
m_Anim->m_AnimDef->BuildBoneMatrices(m_AnimTime,m_BoneMatrices);
|
||||
|
||||
const CMatrix3D& transform=GetTransform();
|
||||
for (int i=0;i<m_pModelDef->GetNumBones();i++) {
|
||||
CMatrix3D m=m_BoneMatrices[i];
|
||||
m.Concatenate(transform);
|
||||
m.GetInverse(m_InvBoneMatrices[i]);
|
||||
}
|
||||
|
||||
// update transform of boned props
|
||||
// TODO, RC - ugh, we'll be doing this twice (for boned props, at least) - once here,
|
||||
// and once again in SetTransform; better to just do it in Update?
|
||||
for (size_t i=0;i<m_Props.size();i++) {
|
||||
const Prop& prop=m_Props[i];
|
||||
|
||||
if (prop.m_Point->m_BoneIndex!=0xff) {
|
||||
CMatrix3D proptransform=prop.m_Point->m_Transform;;
|
||||
if (prop.m_Point->m_BoneIndex!=0xff) {
|
||||
proptransform.Concatenate(m_BoneMatrices[prop.m_Point->m_BoneIndex]);
|
||||
}
|
||||
proptransform.Concatenate(transform);
|
||||
prop.m_Model->SetTransform(proptransform);
|
||||
}
|
||||
}
|
||||
|
||||
m_BoneMatricesValid=true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetAnimation: set the given animation as the current animation on this model;
|
||||
// return false on error, else true
|
||||
bool CModel::SetAnimation(CSkeletonAnim* anim)
|
||||
{
|
||||
m_Anim=anim;
|
||||
if (m_Anim) {
|
||||
if (!m_BoneMatrices) {
|
||||
// not boned, can't animate
|
||||
return false;
|
||||
}
|
||||
|
||||
if (anim->m_AnimDef->GetNumKeys()!=m_pModelDef->GetNumBones()) {
|
||||
// mismatch between models skeleton and animations skeleton
|
||||
return false;
|
||||
}
|
||||
|
||||
// update object bounds to the bounds when given animation applied
|
||||
m_ObjectBounds=m_Anim->m_ObjectBounds;
|
||||
// start anim from beginning
|
||||
m_AnimTime=0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AddProp: add a prop to the model on the given point
|
||||
void CModel::AddProp(SPropPoint* point,CModel* model)
|
||||
{
|
||||
// position model according to prop point position
|
||||
model->SetTransform(point->m_Transform);
|
||||
|
||||
// check if we're already using this point, and replace
|
||||
// model on it if so
|
||||
uint i;
|
||||
for (i=0;i<m_Props.size();i++) {
|
||||
if (m_Props[i].m_Point==point) {
|
||||
m_Props[i].m_Model=model;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// not using point; add new prop
|
||||
Prop prop;
|
||||
prop.m_Point=point;
|
||||
prop.m_Model=model;
|
||||
m_Props.push_back(prop);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RemoveProp: remove a prop from the given point
|
||||
void CModel::RemoveProp(SPropPoint* point)
|
||||
{
|
||||
typedef std::vector<Prop>::iterator Iter;
|
||||
for (Iter iter=m_Props.begin();iter!=m_Props.end();++iter) {
|
||||
const Prop& prop=*iter;
|
||||
if (prop.m_Point==point) {
|
||||
m_Props.erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Clone: return a clone of this model
|
||||
CModel* CModel::Clone() const
|
||||
{
|
||||
CModel* clone=new CModel;
|
||||
clone->m_ObjectBounds=m_ObjectBounds;
|
||||
clone->InitModel(m_pModelDef);
|
||||
clone->SetTexture(m_Texture);
|
||||
clone->SetAnimation(m_Anim);
|
||||
for (uint i=0;i<m_Props.size();i++) {
|
||||
// eek! TODO, RC - need to investigate shallow clone here
|
||||
clone->AddProp(m_Props[i].m_Point,m_Props[i].m_Model->Clone());
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetTransform: set the transform on this object, and reorientate props accordingly
|
||||
void CModel::SetTransform(const CMatrix3D& transform)
|
||||
{
|
||||
// call base class to set transform on this object
|
||||
CRenderableObject::SetTransform(transform);
|
||||
|
||||
// now set transforms on props
|
||||
const CMatrix3D* bonematrices=GetBoneMatrices();
|
||||
for (size_t i=0;i<m_Props.size();i++) {
|
||||
const Prop& prop=m_Props[i];
|
||||
|
||||
CMatrix3D proptransform=prop.m_Point->m_Transform;;
|
||||
if (prop.m_Point->m_BoneIndex!=0xff) {
|
||||
proptransform.Concatenate(m_BoneMatrices[prop.m_Point->m_BoneIndex]);
|
||||
}
|
||||
proptransform.Concatenate(transform);
|
||||
prop.m_Model->SetTransform(proptransform);
|
||||
}
|
||||
}
|
117
source/graphics/Model.h
Executable file
117
source/graphics/Model.h
Executable file
@ -0,0 +1,117 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: Model.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MODEL_H
|
||||
#define _MODEL_H
|
||||
|
||||
#include "Texture.h"
|
||||
#include "ModelDef.h"
|
||||
#include "RenderableObject.h"
|
||||
#include "SkeletonAnim.h"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CModel: basically, a mesh object - holds the texturing and skinning
|
||||
// information for a model in game
|
||||
class CModel : public CRenderableObject
|
||||
{
|
||||
public:
|
||||
struct Prop {
|
||||
SPropPoint* m_Point;
|
||||
CModel* m_Model;
|
||||
};
|
||||
|
||||
public:
|
||||
// constructor
|
||||
CModel();
|
||||
// destructor
|
||||
~CModel();
|
||||
|
||||
// setup model from given geometry
|
||||
bool InitModel(CModelDef *modeldef);
|
||||
// calculate the world space bounds of this model
|
||||
void CalcBounds();
|
||||
// update this model's state; 'time' is the time since the last update, in MS
|
||||
void Update(float time);
|
||||
|
||||
// get the model's geometry data
|
||||
CModelDef *GetModelDef() { return m_pModelDef; }
|
||||
|
||||
// set the model's texture
|
||||
void SetTexture(const CTexture& tex) { m_Texture=tex; }
|
||||
// get the model's texture
|
||||
CTexture* GetTexture() { return &m_Texture; }
|
||||
|
||||
// set the given animation as the current animation on this model
|
||||
bool SetAnimation(CSkeletonAnim* anim);
|
||||
// get the currently playing animation, if any
|
||||
CSkeletonAnim* GetAnimation() { return m_Anim; }
|
||||
|
||||
// calculate object space bounds of this model, based solely on vertex positions
|
||||
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);
|
||||
|
||||
// return the models bone matrices
|
||||
const CMatrix3D* GetBoneMatrices() {
|
||||
if (!m_BoneMatricesValid) GenerateBoneMatrices();
|
||||
return m_BoneMatrices;
|
||||
}
|
||||
// return the models inverted bone matrices
|
||||
const CMatrix3D* GetInvBoneMatrices() {
|
||||
if (!m_BoneMatricesValid) GenerateBoneMatrices();
|
||||
return m_InvBoneMatrices;
|
||||
}
|
||||
|
||||
// load raw animation frame animation from given file, and build a
|
||||
// animation specific to this model
|
||||
CSkeletonAnim* BuildAnimation(const char* filename,float speed);
|
||||
|
||||
// add a prop to the model on the given point
|
||||
void AddProp(SPropPoint* point,CModel* model);
|
||||
// remove a prop from the given point
|
||||
void RemoveProp(SPropPoint* point);
|
||||
// return prop list
|
||||
const std::vector<Prop>& GetProps() { return m_Props; }
|
||||
|
||||
// return a clone of this model
|
||||
CModel* Clone() const;
|
||||
|
||||
private:
|
||||
// delete anything allocated by the model
|
||||
void ReleaseData();
|
||||
// calculate necessary bone transformation matrices for skinning
|
||||
void GenerateBoneMatrices();
|
||||
|
||||
// texture used by model
|
||||
CTexture m_Texture;
|
||||
// pointer to the model's raw 3d data
|
||||
CModelDef* m_pModelDef;
|
||||
// object space bounds of model - accounts for bounds of all possible animations
|
||||
// that can play on a model
|
||||
CBound m_ObjectBounds;
|
||||
// animation currently playing on this model, if any
|
||||
CSkeletonAnim* m_Anim;
|
||||
// time (in MS) into the current animation
|
||||
float m_AnimTime;
|
||||
// flag stating whether bone matrices are currently valid
|
||||
bool m_BoneMatricesValid;
|
||||
// current state of all bones on this model; null if associated modeldef isn't skeletal
|
||||
CMatrix3D* m_BoneMatrices;
|
||||
// inverse of the above world space transform of the above matrices
|
||||
CMatrix3D* m_InvBoneMatrices;
|
||||
// list of current props on model
|
||||
std::vector<Prop> m_Props;
|
||||
};
|
||||
|
||||
#endif
|
134
source/graphics/ModelDef.cpp
Executable file
134
source/graphics/ModelDef.cpp
Executable file
@ -0,0 +1,134 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: ModelDef.cpp
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "ModelDef.h"
|
||||
#include "FilePacker.h"
|
||||
#include "FileUnpacker.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CModelDef Constructor
|
||||
CModelDef::CModelDef()
|
||||
: m_pVertices(0), m_NumVertices(0), m_pFaces(0), m_NumFaces(0), m_Bones(0), m_NumBones(0),
|
||||
m_NumPropPoints(0), m_PropPoints(0)
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CModelDef Destructor
|
||||
CModelDef::~CModelDef()
|
||||
{
|
||||
delete[] m_pVertices;
|
||||
delete[] m_pFaces;
|
||||
delete[] m_Bones;
|
||||
delete[] m_PropPoints;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// FindPropPoint: find and return pointer to prop point matching given name;
|
||||
// return null if no match (case insensitive search)
|
||||
SPropPoint* CModelDef::FindPropPoint(const char* name) const
|
||||
{
|
||||
for (uint i=0;i<m_NumPropPoints;i++) {
|
||||
if (stricmp(name,m_PropPoints[i].m_Name)==0) {
|
||||
return &m_PropPoints[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Load: read and return a new CModelDef initialised with data from given file
|
||||
CModelDef* CModelDef::Load(const char* filename)
|
||||
{
|
||||
CFileUnpacker unpacker;
|
||||
|
||||
// read everything in from file
|
||||
unpacker.Read(filename,"PSMD");
|
||||
|
||||
// check version
|
||||
if (unpacker.GetVersion()<FILE_READ_VERSION) {
|
||||
throw CFileUnpacker::CFileVersionError();
|
||||
}
|
||||
|
||||
CModelDef* mdef=new CModelDef;
|
||||
try {
|
||||
// now unpack everything
|
||||
unpacker.UnpackRaw(&mdef->m_NumVertices,sizeof(mdef->m_NumVertices));
|
||||
mdef->m_pVertices=new SModelVertex[mdef->m_NumVertices];
|
||||
unpacker.UnpackRaw(mdef->m_pVertices,sizeof(SModelVertex)*mdef->m_NumVertices);
|
||||
|
||||
unpacker.UnpackRaw(&mdef->m_NumFaces,sizeof(mdef->m_NumFaces));
|
||||
mdef->m_pFaces=new SModelFace[mdef->m_NumFaces];
|
||||
unpacker.UnpackRaw(mdef->m_pFaces,sizeof(SModelFace)*mdef->m_NumFaces);
|
||||
|
||||
unpacker.UnpackRaw(&mdef->m_NumBones,sizeof(mdef->m_NumBones));
|
||||
if (mdef->m_NumBones) {
|
||||
mdef->m_Bones=new CBoneState[mdef->m_NumBones];
|
||||
unpacker.UnpackRaw(mdef->m_Bones,mdef->m_NumBones*sizeof(CBoneState));
|
||||
}
|
||||
|
||||
if (unpacker.GetVersion()>=2) {
|
||||
// versions >=2 also have prop point data
|
||||
unpacker.UnpackRaw(&mdef->m_NumPropPoints,sizeof(mdef->m_NumPropPoints));
|
||||
if (mdef->m_NumPropPoints) {
|
||||
mdef->m_PropPoints=new SPropPoint[mdef->m_NumPropPoints];
|
||||
for (u32 i=0;i<mdef->m_NumPropPoints;i++) {
|
||||
unpacker.UnpackString(mdef->m_PropPoints[i].m_Name);
|
||||
unpacker.UnpackRaw(&mdef->m_PropPoints[i].m_Position.X,sizeof(mdef->m_PropPoints[i].m_Position));
|
||||
unpacker.UnpackRaw(&mdef->m_PropPoints[i].m_Rotation.m_V.X,sizeof(mdef->m_PropPoints[i].m_Rotation));
|
||||
unpacker.UnpackRaw(&mdef->m_PropPoints[i].m_BoneIndex,sizeof(mdef->m_PropPoints[i].m_BoneIndex));
|
||||
|
||||
// build prop point transform
|
||||
mdef->m_PropPoints[i].m_Transform.SetIdentity();
|
||||
mdef->m_PropPoints[i].m_Transform.Rotate(mdef->m_PropPoints[i].m_Rotation);
|
||||
mdef->m_PropPoints[i].m_Transform.Translate(mdef->m_PropPoints[i].m_Position);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
delete mdef;
|
||||
throw CFileUnpacker::CFileEOFError();
|
||||
}
|
||||
|
||||
return mdef;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Save: write the given CModelDef to the given file
|
||||
void CModelDef::Save(const char* filename,const CModelDef* mdef)
|
||||
{
|
||||
CFilePacker packer;
|
||||
|
||||
// pack everything up
|
||||
u32 numVertices=mdef->GetNumVertices();
|
||||
packer.PackRaw(&numVertices,sizeof(numVertices));
|
||||
packer.PackRaw(mdef->GetVertices(),sizeof(SModelVertex)*numVertices);
|
||||
|
||||
u32 numFaces=mdef->GetNumFaces();
|
||||
packer.PackRaw(&numFaces,sizeof(numFaces));
|
||||
packer.PackRaw(mdef->GetFaces(),sizeof(SModelFace)*numFaces);
|
||||
|
||||
packer.PackRaw(&mdef->m_NumBones,sizeof(mdef->m_NumBones));
|
||||
if (mdef->m_NumBones) {
|
||||
packer.PackRaw(mdef->m_Bones,sizeof(CBoneState)*mdef->m_NumBones);
|
||||
}
|
||||
|
||||
packer.PackRaw(&mdef->m_NumPropPoints,sizeof(mdef->m_NumPropPoints));
|
||||
for (u32 i=0;i<mdef->m_NumPropPoints;i++) {
|
||||
packer.PackString(mdef->m_PropPoints[i].m_Name);
|
||||
packer.PackRaw(&mdef->m_PropPoints[i].m_Position.X,sizeof(mdef->m_PropPoints[i].m_Position));
|
||||
packer.PackRaw(&mdef->m_PropPoints[i].m_Rotation.m_V.X,sizeof(mdef->m_PropPoints[i].m_Rotation));
|
||||
packer.PackRaw(&mdef->m_PropPoints[i].m_BoneIndex,sizeof(mdef->m_PropPoints[i].m_BoneIndex));
|
||||
}
|
||||
|
||||
|
||||
// flush everything out to file
|
||||
packer.Write(filename,FILE_VERSION,"PSMD");
|
||||
}
|
||||
|
123
source/graphics/ModelDef.h
Executable file
123
source/graphics/ModelDef.h
Executable file
@ -0,0 +1,123 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: ModelDef.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MODELDEF_H
|
||||
#define _MODELDEF_H
|
||||
|
||||
#include "res/res.h"
|
||||
#include "CStr.h"
|
||||
#include "Vector3D.h"
|
||||
#include "SkeletonAnimDef.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SPropPoint: structure describing a prop point
|
||||
struct SPropPoint
|
||||
{
|
||||
// name of the prop point
|
||||
CStr m_Name;
|
||||
// position of the point
|
||||
CVector3D m_Position;
|
||||
// rotation of the point
|
||||
CQuaternion m_Rotation;
|
||||
// object to parent space transformation
|
||||
CMatrix3D m_Transform;
|
||||
// index of parent bone; 0xff if unboned
|
||||
u8 m_BoneIndex;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SVertexBlend: structure containing the necessary data for blending vertices
|
||||
// with multiple bones
|
||||
struct SVertexBlend
|
||||
{
|
||||
enum { SIZE = 4 };
|
||||
// index of the influencing bone, or 0xff if none
|
||||
u8 m_Bone[SIZE];
|
||||
// weight of the influence; all weights sum to 1
|
||||
float m_Weight[SIZE];
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SModelVertex: structure containing per-vertex data
|
||||
struct SModelVertex
|
||||
{
|
||||
// vertex position
|
||||
CVector3D m_Coords;
|
||||
// vertex normal
|
||||
CVector3D m_Norm;
|
||||
// vertex UVs
|
||||
float m_U, m_V;
|
||||
// vertex blend data
|
||||
SVertexBlend m_Blend;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SModelFace: structure containing per-face data
|
||||
struct SModelFace
|
||||
{
|
||||
// indices of the 3 vertices on this face
|
||||
u16 m_Verts[3];
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CModelDef: a raw 3D model; describes the vertices, faces, skinning and skeletal
|
||||
// information of a model
|
||||
class CModelDef
|
||||
{
|
||||
public:
|
||||
// current file version given to saved animations
|
||||
enum { FILE_VERSION = 2 };
|
||||
// supported file read version - files with a version less than this will be rejected
|
||||
enum { FILE_READ_VERSION = 1 };
|
||||
|
||||
|
||||
public:
|
||||
// constructor
|
||||
CModelDef();
|
||||
// destructor
|
||||
virtual ~CModelDef();
|
||||
|
||||
// model I/O functions
|
||||
static CModelDef* Load(const char* filename);
|
||||
static void Save(const char* filename,const CModelDef* mdef);
|
||||
|
||||
public:
|
||||
// accessor: get vertex data
|
||||
int GetNumVertices() const { return m_NumVertices; }
|
||||
SModelVertex *GetVertices() const { return m_pVertices; }
|
||||
|
||||
// accessor: get face data
|
||||
int GetNumFaces() const { return m_NumFaces; }
|
||||
SModelFace *GetFaces() const { return m_pFaces; }
|
||||
|
||||
// accessor: get bone data
|
||||
int GetNumBones() const { return m_NumBones; }
|
||||
CBoneState *GetBones() const { return m_Bones; }
|
||||
|
||||
// find and return pointer to prop point matching given name; return
|
||||
// null if no match (case insensitive search)
|
||||
SPropPoint* FindPropPoint(const char* name) const;
|
||||
|
||||
public:
|
||||
// vertex data
|
||||
u32 m_NumVertices;
|
||||
SModelVertex* m_pVertices;
|
||||
// face data
|
||||
u32 m_NumFaces;
|
||||
SModelFace* m_pFaces;
|
||||
// bone data - default model pose
|
||||
u32 m_NumBones;
|
||||
CBoneState* m_Bones;
|
||||
// prop point data
|
||||
u32 m_NumPropPoints;
|
||||
SPropPoint* m_PropPoints;
|
||||
};
|
||||
|
||||
#endif
|
321
source/graphics/ObjectEntry.cpp
Executable file
321
source/graphics/ObjectEntry.cpp
Executable file
@ -0,0 +1,321 @@
|
||||
#include "ObjectEntry.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "Model.h"
|
||||
#include "ModelDef.h"
|
||||
|
||||
#include "UnitManager.h"
|
||||
|
||||
// xerces XML stuff
|
||||
#include <xercesc/dom/DOM.hpp>
|
||||
#include <xercesc/parsers/XercesDOMParser.hpp>
|
||||
#include <xercesc/framework/LocalFileInputSource.hpp>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
#include <xercesc/util/PlatformUtils.hpp>
|
||||
|
||||
// Gee's custom error handler
|
||||
#include <ps/XercesErrorHandler.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "xerces-c_2.lib")
|
||||
#endif
|
||||
|
||||
// automatically use namespace ..
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
|
||||
CObjectEntry::CObjectEntry(int type) : m_Model(0), m_Type(type)
|
||||
{
|
||||
m_IdleAnim=0;
|
||||
m_WalkAnim=0;
|
||||
m_DeathAnim=0;
|
||||
m_MeleeAnim=0;
|
||||
m_RangedAnim=0;
|
||||
}
|
||||
|
||||
CObjectEntry::~CObjectEntry()
|
||||
{
|
||||
for (size_t i=0;i<m_Animations.size();i++) {
|
||||
CSkeletonAnim* anim=m_Animations[i].m_AnimData;
|
||||
delete anim;
|
||||
}
|
||||
|
||||
delete m_Model;
|
||||
}
|
||||
|
||||
bool CObjectEntry::BuildModel()
|
||||
{
|
||||
debug_out("Building model %s\n",(const char*) m_Name);
|
||||
|
||||
// check we've enough data to consider building the object
|
||||
if (m_ModelName.Length()==0 || m_TextureName.Length()==0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get the root directory of this object
|
||||
CStr dirname=g_ObjMan.m_ObjectTypes[m_Type].m_Name;
|
||||
|
||||
// remember the old model so we can replace any models using it later on
|
||||
CModelDef* oldmodel=m_Model ? m_Model->GetModelDef() : 0;
|
||||
|
||||
// build filename
|
||||
CStr modelfilename("mods\\official\\");
|
||||
modelfilename+=m_ModelName;
|
||||
|
||||
// try and create a model
|
||||
CModelDef* modeldef;
|
||||
|
||||
try {
|
||||
modeldef=CModelDef::Load((const char*) modelfilename);
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// create new Model
|
||||
m_Model=new CModel;
|
||||
m_Model->SetTexture((const char*) m_TextureName);
|
||||
m_Model->InitModel(modeldef);
|
||||
|
||||
// calculate initial object space bounds, based on vertex positions
|
||||
m_Model->CalcObjectBounds();
|
||||
|
||||
// load animations
|
||||
for( uint t = 0; t < m_Animations.size(); t++ )
|
||||
{
|
||||
if( m_Animations[t].m_FileName.Length() > 0 )
|
||||
{
|
||||
CStr animfilename( "mods\\official\\" );
|
||||
animfilename += m_Animations[t].m_FileName;
|
||||
m_Animations[t].m_AnimData = m_Model->BuildAnimation((const char*) animfilename,m_Animations[t].m_Speed);
|
||||
|
||||
if( m_Animations[t].m_AnimName.LowerCase() == CStr( "idle" ) )
|
||||
m_IdleAnim = m_Animations[t].m_AnimData;
|
||||
if( m_Animations[t].m_AnimName.LowerCase() == CStr( "walk" ) )
|
||||
m_WalkAnim = m_Animations[t].m_AnimData;
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME, RC - don't store invalid animations
|
||||
m_Animations[t].m_AnimData=0;
|
||||
}
|
||||
}
|
||||
// start up idling
|
||||
m_Model->SetAnimation( m_IdleAnim );
|
||||
|
||||
// build props - TODO, RC - need to fix up bounds here
|
||||
for (uint p=0;p<m_Props.size();p++) {
|
||||
const Prop& prop=m_Props[p];
|
||||
SPropPoint* proppoint=modeldef->FindPropPoint((const char*) prop.m_PropPointName);
|
||||
if (proppoint) {
|
||||
CObjectEntry* oe=g_ObjMan.FindObject(prop.m_ModelName);
|
||||
if (oe) {
|
||||
// try and build model if we haven't already got it
|
||||
if (!oe->m_Model) oe->BuildModel();
|
||||
if (oe->m_Model) {
|
||||
CModel* propmodel=oe->m_Model->Clone();
|
||||
m_Model->AddProp(proppoint,propmodel);
|
||||
if (oe->m_WalkAnim) propmodel->SetAnimation(oe->m_WalkAnim);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build world space bounds
|
||||
m_Model->CalcBounds();
|
||||
|
||||
// replace any units using old model to now use new model; also reprop models, if necessary
|
||||
const std::vector<CUnit*>& units=g_UnitMan.GetUnits();
|
||||
for (uint i=0;i<units.size();++i) {
|
||||
CModel* unitmodel=units[i]->GetModel();
|
||||
if (unitmodel->GetModelDef()==oldmodel) {
|
||||
unitmodel->InitModel(m_Model->GetModelDef());
|
||||
|
||||
const std::vector<CModel::Prop>& newprops=m_Model->GetProps();
|
||||
for (uint j=0;j<newprops.size();j++) {
|
||||
unitmodel->AddProp(newprops[j].m_Point,newprops[j].m_Model->Clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// and were done with the old model ..
|
||||
delete oldmodel;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CSkeletonAnim* CObjectEntry::GetNamedAnimation( CStr animationName )
|
||||
{
|
||||
for( uint t = 0; t < m_Animations.size(); t++ )
|
||||
{
|
||||
if( m_Animations[t].m_AnimName == animationName )
|
||||
return( m_Animations[t].m_AnimData );
|
||||
}
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
CStr Transcode(const XMLCh* xmltext)
|
||||
{
|
||||
char* str=XMLString::transcode(xmltext);
|
||||
CStr result(str);
|
||||
XMLString::release(&str);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CObjectEntry::Load(const char* filename)
|
||||
{
|
||||
bool parseOK = false;
|
||||
|
||||
|
||||
// Initialize XML library
|
||||
XMLPlatformUtils::Initialize();
|
||||
{
|
||||
XMLCh* attachpointtext=XMLString::transcode("attachpoint");
|
||||
XMLCh* modeltext=XMLString::transcode("model");
|
||||
XMLCh* nametext=XMLString::transcode("name");
|
||||
XMLCh* filetext=XMLString::transcode("file");
|
||||
XMLCh* speedtext=XMLString::transcode("speed");
|
||||
|
||||
// Create parser instance
|
||||
XercesDOMParser *parser = new XercesDOMParser();
|
||||
|
||||
// Setup parser
|
||||
parser->setValidationScheme(XercesDOMParser::Val_Auto);
|
||||
parser->setDoNamespaces(false);
|
||||
parser->setDoSchema(false);
|
||||
parser->setCreateEntityReferenceNodes(false);
|
||||
|
||||
// Set customized error handler
|
||||
CXercesErrorHandler *errorHandler = new CXercesErrorHandler();
|
||||
parser->setErrorHandler(errorHandler);
|
||||
|
||||
// Push the CLogger to mark it's reading this file.
|
||||
|
||||
// Get main node
|
||||
XMLCh* xfilename=XMLString::transcode(filename);
|
||||
LocalFileInputSource source(xfilename);
|
||||
XMLString::release(&xfilename);
|
||||
|
||||
// Parse file
|
||||
parser->parse(source);
|
||||
|
||||
// Check how many errors
|
||||
parseOK = parser->getErrorCount() == 0;
|
||||
|
||||
if (parseOK) {
|
||||
// parsed successfully - grab our data
|
||||
DOMDocument *doc = parser->getDocument();
|
||||
DOMElement *element = doc->getDocumentElement();
|
||||
|
||||
// root_name should be Object
|
||||
CStr root_name = Transcode( element->getNodeName() );
|
||||
|
||||
// should have at least 3 children - Name, ModelName and TextureName
|
||||
DOMNodeList *children = element->getChildNodes();
|
||||
int numChildren=children->getLength();
|
||||
for (int i=0; i<numChildren; ++i) {
|
||||
// Get node
|
||||
DOMNode *child = children->item(i);
|
||||
|
||||
// A child element
|
||||
if (child->getNodeType() == DOMNode::ELEMENT_NODE)
|
||||
{
|
||||
// First get element and not node
|
||||
DOMElement *child_element = (DOMElement*)child;
|
||||
|
||||
CStr element_name = Transcode( child_element->getNodeName() );
|
||||
DOMNode *value_node= child_element->getChildNodes()->item(0);
|
||||
CStr element_value=value_node ? Transcode(value_node->getNodeValue()) : "";
|
||||
|
||||
if (element_name==CStr("Name")) {
|
||||
m_Name=element_value;
|
||||
} else if (element_name==CStr("ModelName")) {
|
||||
m_ModelName=element_value;
|
||||
} else if (element_name==CStr("TextureName")) {
|
||||
m_TextureName=element_value;
|
||||
} else if (element_name==CStr("Animations")) {
|
||||
DOMNodeList* animations=(DOMNodeList*) child_element->getChildNodes();
|
||||
|
||||
for (uint j=0; j<animations->getLength(); ++j) {
|
||||
DOMElement *anim_element = (DOMElement*) animations->item(j);
|
||||
CStr element_name = Transcode( anim_element->getNodeName() );
|
||||
DOMNamedNodeMap* attributes=anim_element->getAttributes();
|
||||
if (attributes) {
|
||||
Anim anim;
|
||||
|
||||
DOMNode *nameattr=attributes->getNamedItem(nametext);
|
||||
anim.m_AnimName=Transcode(nameattr->getChildNodes()->item(0)->getNodeValue());
|
||||
DOMNode *fileattr=attributes->getNamedItem(filetext);
|
||||
anim.m_FileName=Transcode(fileattr->getChildNodes()->item(0)->getNodeValue());
|
||||
|
||||
DOMNode *speedattr=attributes->getNamedItem(speedtext);
|
||||
CStr speedstr=Transcode(speedattr->getChildNodes()->item(0)->getNodeValue());
|
||||
|
||||
anim.m_Speed=float(atoi((const char*) speedstr))/100.0f;
|
||||
if (anim.m_Speed<=0) anim.m_Speed=1.0f;
|
||||
|
||||
m_Animations.push_back(anim);
|
||||
}
|
||||
}
|
||||
} else if (element_name==CStr("Props")) {
|
||||
DOMNodeList* props=(DOMNodeList*) child_element->getChildNodes();
|
||||
|
||||
for (uint j=0; j<props->getLength(); ++j) {
|
||||
DOMElement *prop_element = (DOMElement*) props->item(j);
|
||||
CStr element_name = Transcode( prop_element->getNodeName() );
|
||||
DOMNamedNodeMap* attributes=prop_element->getAttributes();
|
||||
if (attributes) {
|
||||
Prop prop;
|
||||
|
||||
DOMNode *nameattr=attributes->getNamedItem(attachpointtext);
|
||||
prop.m_PropPointName=Transcode(nameattr->getChildNodes()->item(0)->getNodeValue());
|
||||
DOMNode *modelattr=attributes->getNamedItem(modeltext);
|
||||
prop.m_ModelName=XMLString::transcode(modelattr->getChildNodes()->item(0)->getNodeValue());
|
||||
|
||||
m_Props.push_back(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XMLString::release(&attachpointtext);
|
||||
XMLString::release(&modeltext);
|
||||
XMLString::release(&nametext);
|
||||
XMLString::release(&filetext);
|
||||
XMLString::release(&speedtext);
|
||||
|
||||
delete parser;
|
||||
delete errorHandler;
|
||||
}
|
||||
XMLPlatformUtils::Terminate();
|
||||
|
||||
return parseOK;
|
||||
}
|
||||
|
||||
bool CObjectEntry::Save(const char* filename)
|
||||
{
|
||||
FILE* fp=fopen(filename,"w");
|
||||
if (!fp) return false;
|
||||
|
||||
// write XML header
|
||||
fprintf(fp,"<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>\n\n");
|
||||
fprintf(fp,"<!DOCTYPE Object SYSTEM \"..\\object.dtd\">\n\n");
|
||||
|
||||
// write the object itself
|
||||
fprintf(fp,"<!-- File automatically generated by ScEd -->\n");
|
||||
fprintf(fp,"<Object>\n");
|
||||
fprintf(fp,"\t<Name>%s</Name>\n",(const char*) m_Name);
|
||||
fprintf(fp,"\t<ModelName>%s</ModelName>\n",(const char*) m_ModelName);
|
||||
fprintf(fp,"\t<TextureName>%s</TextureName>\n",(const char*) m_TextureName);
|
||||
if (m_Animations.size()>0) {
|
||||
fprintf(fp,"\t<Animations>\n");
|
||||
for (uint i=0;i<m_Animations.size();i++) {
|
||||
fprintf(fp,"\t\t<Animation name=\"%s\" file=\"%s\"> </Animation>\n",(const char*) m_Animations[i].m_AnimName,(const char*) m_Animations[i].m_FileName);
|
||||
}
|
||||
fprintf(fp,"\t</Animations>\n");
|
||||
}
|
||||
fprintf(fp,"</Object>\n");
|
||||
fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
65
source/graphics/ObjectEntry.h
Executable file
65
source/graphics/ObjectEntry.h
Executable file
@ -0,0 +1,65 @@
|
||||
#ifndef _OBJECTENTRY_H
|
||||
#define _OBJECTENTRY_H
|
||||
|
||||
class CModel;
|
||||
class CSkeletonAnim;
|
||||
|
||||
#include <vector>
|
||||
#include "CStr.h"
|
||||
#include "Bound.h"
|
||||
#include "ModelDef.h"
|
||||
|
||||
class CObjectEntry
|
||||
{
|
||||
public:
|
||||
struct Anim {
|
||||
// name of the animation - "Idle", "Run", etc
|
||||
CStr m_AnimName;
|
||||
// filename of the animation - manidle.psa, manrun.psa, etc
|
||||
CStr m_FileName;
|
||||
// animation speed, as specified in XML actor file
|
||||
float m_Speed;
|
||||
// the animation data, specific to the this model
|
||||
CSkeletonAnim* m_AnimData;
|
||||
};
|
||||
|
||||
struct Prop {
|
||||
// name of the prop point to attach to - "Prop01", "Prop02", "Head", "LeftHand", etc ..
|
||||
CStr m_PropPointName;
|
||||
// name of the model file - art/actors/props/sword.xml or whatever
|
||||
CStr m_ModelName;
|
||||
};
|
||||
|
||||
public:
|
||||
CObjectEntry(int type);
|
||||
~CObjectEntry();
|
||||
|
||||
bool BuildModel();
|
||||
|
||||
bool Load(const char* filename);
|
||||
bool Save(const char* filename);
|
||||
|
||||
// object name
|
||||
CStr m_Name;
|
||||
// texture name
|
||||
CStr m_TextureName;
|
||||
// model name
|
||||
CStr m_ModelName;
|
||||
// list of valid animations for this object
|
||||
std::vector<Anim> m_Animations;
|
||||
CSkeletonAnim* m_IdleAnim;
|
||||
CSkeletonAnim* m_WalkAnim;
|
||||
CSkeletonAnim* m_DeathAnim;
|
||||
CSkeletonAnim* m_MeleeAnim;
|
||||
CSkeletonAnim* m_RangedAnim;
|
||||
CSkeletonAnim* GetNamedAnimation( CStr animationName );
|
||||
// list of props attached to object
|
||||
std::vector<Prop> m_Props;
|
||||
// corresponding model
|
||||
CModel* m_Model;
|
||||
// type of object; index into object managers types array
|
||||
int m_Type;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
151
source/graphics/ObjectManager.cpp
Executable file
151
source/graphics/ObjectManager.cpp
Executable file
@ -0,0 +1,151 @@
|
||||
#include "ObjectManager.h"
|
||||
#include <io.h>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
CObjectManager::CObjectManager() : m_SelectedObject(0)
|
||||
{
|
||||
m_ObjectTypes.reserve(32);
|
||||
}
|
||||
|
||||
CObjectManager::~CObjectManager()
|
||||
{
|
||||
m_SelectedObject=0;
|
||||
for (size_t i=0;i<m_ObjectTypes.size();i++) {
|
||||
for (size_t j=0;j<m_ObjectTypes[i].m_Objects.size();j++) {
|
||||
delete m_ObjectTypes[i].m_Objects[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CObjectEntry* CObjectManager::FindObject(const char* objectname)
|
||||
{
|
||||
for (uint k=0;k<m_ObjectTypes.size();k++) {
|
||||
std::vector<CObjectEntry*>& objects=m_ObjectTypes[k].m_Objects;
|
||||
|
||||
for (uint i=0;i<objects.size();i++) {
|
||||
if (strcmp(objectname,(const char*) objects[i]->m_Name)==0) {
|
||||
return objects[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CObjectManager::AddObjectType(const char* name)
|
||||
{
|
||||
m_ObjectTypes.resize(m_ObjectTypes.size()+1);
|
||||
SObjectType& type=m_ObjectTypes.back();
|
||||
type.m_Name=name;
|
||||
type.m_Index=m_ObjectTypes.size()-1;
|
||||
}
|
||||
|
||||
void CObjectManager::AddObject(CObjectEntry* object,int type)
|
||||
{
|
||||
assert((uint)type<m_ObjectTypes.size());
|
||||
m_ObjectTypes[type].m_Objects.push_back(object);
|
||||
}
|
||||
|
||||
void CObjectManager::DeleteObject(CObjectEntry* entry)
|
||||
{
|
||||
std::vector<CObjectEntry*>& objects=m_ObjectTypes[entry->m_Type].m_Objects;
|
||||
|
||||
typedef std::vector<CObjectEntry*>::iterator Iter;
|
||||
Iter i=std::find(objects.begin(),objects.end(),entry);
|
||||
if (i!=objects.end()) {
|
||||
objects.erase(i);
|
||||
}
|
||||
delete entry;
|
||||
}
|
||||
|
||||
void CObjectManager::LoadObjects()
|
||||
{
|
||||
// find all the object types by directory name
|
||||
BuildObjectTypes();
|
||||
|
||||
// now iterate through terrain types loading all textures of that type
|
||||
uint i;
|
||||
for (i=0;i<m_ObjectTypes.size();i++) {
|
||||
LoadObjects(i);
|
||||
}
|
||||
|
||||
// now build all the models
|
||||
for (i=0;i<m_ObjectTypes.size();i++) {
|
||||
std::vector<CObjectEntry*>& objects=m_ObjectTypes[i].m_Objects;
|
||||
|
||||
for (uint j=0;j<objects.size();j++) {
|
||||
// object might have already been built (eg if it's a prop);
|
||||
// and only build if we haven't a model
|
||||
if (!objects[j]->m_Model) {
|
||||
if (!objects[j]->BuildModel()) {
|
||||
DeleteObject(objects[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CObjectManager::BuildObjectTypes()
|
||||
{
|
||||
struct _finddata_t file;
|
||||
long handle;
|
||||
|
||||
// Find first matching directory in terrain\textures
|
||||
if ((handle=_findfirst("mods\\official\\art\\actors\\*",&file))!=-1) {
|
||||
|
||||
if ((file.attrib & _A_SUBDIR) && file.name[0]!='.') {
|
||||
AddObjectType(file.name);
|
||||
}
|
||||
|
||||
// Find the rest of the matching files
|
||||
while( _findnext(handle,&file)==0) {
|
||||
if ((file.attrib & _A_SUBDIR) && file.name[0]!='.') {
|
||||
AddObjectType(file.name);
|
||||
}
|
||||
}
|
||||
|
||||
_findclose(handle);
|
||||
}
|
||||
}
|
||||
|
||||
void CObjectManager::LoadObjects(int type)
|
||||
{
|
||||
struct _finddata_t file;
|
||||
long handle;
|
||||
|
||||
// build pathname
|
||||
CStr pathname("mods\\official\\art\\actors\\");
|
||||
pathname+=m_ObjectTypes[type].m_Name;
|
||||
pathname+="\\";
|
||||
|
||||
CStr findname(pathname);
|
||||
findname+="*.xml";
|
||||
|
||||
// Find first matching file in directory for this terrain type
|
||||
if ((handle=_findfirst((const char*) findname,&file))!=-1) {
|
||||
|
||||
CObjectEntry* object=new CObjectEntry(type);
|
||||
CStr filename(pathname);
|
||||
filename+=file.name;
|
||||
if (!object->Load((const char*) filename)) {
|
||||
delete object;
|
||||
} else {
|
||||
AddObject(object,type);
|
||||
}
|
||||
|
||||
// Find the rest of the matching files
|
||||
while( _findnext(handle,&file)==0) {
|
||||
CObjectEntry* object=new CObjectEntry(type);
|
||||
CStr filename(pathname);
|
||||
filename+=file.name;
|
||||
if (!object->Load((const char*) filename)) {
|
||||
delete object;
|
||||
} else {
|
||||
AddObject(object,type);
|
||||
}
|
||||
}
|
||||
|
||||
_findclose(handle);
|
||||
}
|
||||
}
|
52
source/graphics/ObjectManager.h
Executable file
52
source/graphics/ObjectManager.h
Executable file
@ -0,0 +1,52 @@
|
||||
#ifndef _OBJECTMANAGER_H
|
||||
#define _OBJECTMANAGER_H
|
||||
|
||||
#include <vector>
|
||||
#include "Singleton.h"
|
||||
#include "ObjectEntry.h"
|
||||
|
||||
// access to sole CObjectManager object
|
||||
#define g_ObjMan CObjectManager::GetSingleton()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CObjectManager: manager class for all possible actor types
|
||||
class CObjectManager : public Singleton<CObjectManager>
|
||||
{
|
||||
public:
|
||||
struct SObjectType
|
||||
{
|
||||
// name of this object type (derived from directory name)
|
||||
CStr m_Name;
|
||||
// index in parent array
|
||||
int m_Index;
|
||||
// list of objects of this type (found from the objects directory)
|
||||
std::vector<CObjectEntry*> m_Objects;
|
||||
};
|
||||
|
||||
public:
|
||||
// constructor, destructor
|
||||
CObjectManager();
|
||||
~CObjectManager();
|
||||
|
||||
void LoadObjects();
|
||||
|
||||
void AddObjectType(const char* name);
|
||||
|
||||
CObjectEntry* FindObject(const char* objname);
|
||||
void AddObject(CObjectEntry* entry,int type);
|
||||
void DeleteObject(CObjectEntry* entry);
|
||||
|
||||
CObjectEntry* GetSelectedObject() const { return m_SelectedObject; }
|
||||
void SetSelectedObject(CObjectEntry* obj) { m_SelectedObject=obj; }
|
||||
|
||||
std::vector<SObjectType> m_ObjectTypes;
|
||||
|
||||
private:
|
||||
void BuildObjectTypes();
|
||||
void LoadObjects(int type);
|
||||
|
||||
CObjectEntry* m_SelectedObject;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
86
source/graphics/Particle.cpp
Executable file
86
source/graphics/Particle.cpp
Executable file
@ -0,0 +1,86 @@
|
||||
/*==================================================================
|
||||
|
|
||||
| Name: Particle.cpp
|
||||
|
|
||||
|===================================================================
|
||||
|
|
||||
| Author: Ben Vinegar
|
||||
| Contact: benvinegar () hotmail ! com
|
||||
|
|
||||
|
|
||||
| Last Modified: 03/08/04
|
||||
|
|
||||
| Overview: A single particle, currently only utilized by
|
||||
| CParticleEmitter. Public variables are for performance
|
||||
| reasons.
|
||||
|
|
||||
|
|
||||
| Usage: Instantiate a particle, set public variables, then call
|
||||
| Frame() every frame.
|
||||
|
|
||||
| To do: TBA
|
||||
|
|
||||
| More Information: TBA
|
||||
|
|
||||
==================================================================*/
|
||||
|
||||
#include "Particle.h"
|
||||
#include "timer.h"
|
||||
#include "ogl.h"
|
||||
#include <assert.h>
|
||||
|
||||
CParticle::CParticle() :
|
||||
m_duration(0.0f),
|
||||
m_timeElapsedTotal(0.0f),
|
||||
m_position(0.0f, 0.0f, 0.0f),
|
||||
m_velocity(0.0f, 0.0f, 0.0f),
|
||||
m_gravity(0.0f, 0.0f, 0.0f)
|
||||
{
|
||||
m_timeOfLastFrame = get_time();
|
||||
|
||||
// default white colour
|
||||
m_colour[0] = m_colour[1] = m_colour[2] = m_colour[3] = 1.0f;
|
||||
}
|
||||
|
||||
CParticle::~CParticle()
|
||||
{
|
||||
}
|
||||
|
||||
void CParticle::Init()
|
||||
{
|
||||
// calculate colour increment per second in order to fade to black
|
||||
m_colourInc[0] = - (m_colour[0] / m_duration);
|
||||
m_colourInc[1] = - (m_colour[1] / m_duration);
|
||||
m_colourInc[2] = - (m_colour[2] / m_duration);
|
||||
}
|
||||
|
||||
void CParticle::Frame()
|
||||
{
|
||||
Update();
|
||||
Render();
|
||||
}
|
||||
|
||||
void CParticle::Render()
|
||||
{
|
||||
assert(m_sprite);
|
||||
|
||||
m_sprite->SetColour(m_colour);
|
||||
m_sprite->SetTranslation(m_position);
|
||||
m_sprite->Render();
|
||||
}
|
||||
|
||||
void CParticle::Update()
|
||||
{
|
||||
float timeElapsed = float(get_time() - m_timeOfLastFrame);
|
||||
|
||||
m_velocity += m_gravity * timeElapsed;
|
||||
m_position += m_velocity * timeElapsed;
|
||||
|
||||
// fade colour
|
||||
m_colour[0] += m_colourInc[0] * timeElapsed;
|
||||
m_colour[1] += m_colourInc[1] * timeElapsed;
|
||||
m_colour[2] += m_colourInc[2] * timeElapsed;
|
||||
|
||||
m_timeOfLastFrame = get_time();
|
||||
m_timeElapsedTotal += timeElapsed;
|
||||
}
|
71
source/graphics/Particle.h
Executable file
71
source/graphics/Particle.h
Executable file
@ -0,0 +1,71 @@
|
||||
/*==================================================================
|
||||
|
|
||||
| Name: Particle.h
|
||||
|
|
||||
|===================================================================
|
||||
|
|
||||
| Author: Ben Vinegar
|
||||
| Contact: benvinegar () hotmail ! com
|
||||
|
|
||||
|
|
||||
| Last Modified: 03/08/04
|
||||
|
|
||||
| Overview: A single particle, currently only utilized by
|
||||
| CParticleEmitter. Public variables are for performance
|
||||
| reasons.
|
||||
|
|
||||
|
|
||||
| Usage: Instantiate a particle, set public variables, then call
|
||||
| Frame() every frame.
|
||||
|
|
||||
| To do: TBA
|
||||
|
|
||||
| More Information: TBA
|
||||
|
|
||||
==================================================================*/
|
||||
|
||||
#ifndef PARTICLE_H
|
||||
#define PARTICLE_H
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Includes / Compiler directives
|
||||
//--------------------------------------------------------
|
||||
|
||||
#include "Vector3D.h"
|
||||
#include "Sprite.h"
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Declarations
|
||||
//--------------------------------------------------------
|
||||
|
||||
class CParticle
|
||||
{
|
||||
public:
|
||||
CParticle();
|
||||
~CParticle();
|
||||
|
||||
// necessary pre-processing immediately before first update call
|
||||
void Init();
|
||||
|
||||
void Frame();
|
||||
void Update();
|
||||
void Render();
|
||||
|
||||
void SetColour(float r, float g, float b, float a);
|
||||
|
||||
CSprite * m_sprite;
|
||||
|
||||
float m_duration;
|
||||
double m_timeOfLastFrame;
|
||||
double m_timeElapsedTotal;
|
||||
|
||||
CVector3D m_position;
|
||||
CVector3D m_velocity;
|
||||
CVector3D m_gravity;
|
||||
|
||||
float m_colour[4];
|
||||
float m_colourInc[3];
|
||||
};
|
||||
|
||||
|
||||
#endif // PARTICLE_H
|
277
source/graphics/ParticleEmitter.cpp
Executable file
277
source/graphics/ParticleEmitter.cpp
Executable file
@ -0,0 +1,277 @@
|
||||
/*==================================================================
|
||||
|
|
||||
| Name: ParticleEmitter.cpp
|
||||
|
|
||||
|===================================================================
|
||||
|
|
||||
| Author: Ben Vinegar
|
||||
| Contact: benvinegar () hotmail ! com
|
||||
|
|
||||
|
|
||||
| Last Modified: 03/08/04
|
||||
|
|
||||
| Overview: Particle emitter class that emits particles from
|
||||
| an origin (or area) with a variety of set colours,
|
||||
| durations, forces and a single common sprite.
|
||||
|
|
||||
|
|
||||
| Usage: Instantiate one emitter per desired effect. Set the
|
||||
| various fields (preferably all, the defaults are rather
|
||||
| boring) and then call Frame() - you guessed it - every
|
||||
| frame.
|
||||
|
|
||||
| To do: TBA
|
||||
|
|
||||
| More Information: TBA
|
||||
|
|
||||
==================================================================*/
|
||||
|
||||
#include "ParticleEmitter.h"
|
||||
#include "timer.h"
|
||||
#include "ogl.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
CParticleEmitter::CParticleEmitter() :
|
||||
m_particles(NULL),
|
||||
m_origin(0.0f, 0.0f, 0.0f),
|
||||
m_originSpread(0.0f, 0.0f, 0.0f),
|
||||
m_velocity(0.0f, 0.0f, 0.0f),
|
||||
m_velocitySpread(0.0f, 0.0f, 0.0f),
|
||||
m_gravity(0.0f, 0.0f, 0.0f),
|
||||
m_maxParticles(0),
|
||||
m_minParticles(0),
|
||||
m_numParticles(0),
|
||||
m_maxLifetime(0),
|
||||
m_minLifetime(0),
|
||||
m_timeOfLastFrame(0.0f),
|
||||
m_timeSinceLastEmit(0.0f)
|
||||
{
|
||||
m_particles.clear();
|
||||
}
|
||||
|
||||
CParticleEmitter::~CParticleEmitter()
|
||||
{
|
||||
}
|
||||
|
||||
void CParticleEmitter::Frame()
|
||||
{
|
||||
Update();
|
||||
Render();
|
||||
}
|
||||
|
||||
void CParticleEmitter::Render()
|
||||
{
|
||||
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glAlphaFunc(GL_GREATER, 0.0f);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
|
||||
|
||||
vector<CParticle *>::iterator itor = m_particles.begin();
|
||||
while (itor != m_particles.end())
|
||||
{
|
||||
CParticle * curParticle = (*itor);
|
||||
|
||||
curParticle->Frame();
|
||||
++itor;
|
||||
}
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void CParticleEmitter::Update()
|
||||
{
|
||||
double timeElapsed = get_time() - m_timeOfLastFrame;
|
||||
|
||||
// update existing particles
|
||||
vector<CParticle *>::iterator itor = m_particles.begin();
|
||||
while (itor != m_particles.end())
|
||||
{
|
||||
CParticle * curParticle = (*itor);
|
||||
|
||||
curParticle->Update();
|
||||
|
||||
// destroy particle if it has lived beyond its duration
|
||||
if (curParticle->m_timeElapsedTotal >= curParticle->m_duration)
|
||||
{
|
||||
m_particles.erase(itor);
|
||||
delete curParticle;
|
||||
--m_numParticles;
|
||||
}
|
||||
|
||||
++itor;
|
||||
}
|
||||
|
||||
double secondsPerEmit = 1 / (m_minParticles / m_minLifetime);
|
||||
|
||||
if (m_timeSinceLastEmit > secondsPerEmit)
|
||||
{
|
||||
|
||||
float duration;
|
||||
CVector3D position, velocity;
|
||||
float colour[4];
|
||||
|
||||
bool moreParticlesToEmit = true;
|
||||
while (moreParticlesToEmit) {
|
||||
CParticle * newParticle = new CParticle();
|
||||
|
||||
// calculate particle duration
|
||||
duration = (float)m_minLifetime;
|
||||
duration += (rand() % (int)((m_maxLifetime - m_minLifetime) * 1000.0f + 1)) / 1000.0f;
|
||||
newParticle->m_duration = duration;
|
||||
|
||||
// calculate particle start position from spread
|
||||
position = m_origin;
|
||||
position.X += (rand() % (int)(m_originSpread.X * 2000.0f + 1)) / 1000.0f - m_originSpread.X;
|
||||
position.Y += (rand() % (int)(m_originSpread.Y * 2000.0f + 1)) / 1000.0f - m_originSpread.Y;
|
||||
position.Z += (rand() % (int)(m_originSpread.Z * 2000.0f + 1)) / 1000.0f - m_originSpread.Z;
|
||||
newParticle->m_position = position;
|
||||
|
||||
// calculate particle velocity from spread
|
||||
velocity = m_velocity;
|
||||
velocity.X += (rand() % (int)(m_velocitySpread.X * 2000.0f + 1)) / 1000.0f - m_velocitySpread.X;
|
||||
velocity.Y += (rand() % (int)(m_velocitySpread.Y * 2000.0f + 1)) / 1000.0f - m_velocitySpread.Y;
|
||||
velocity.Z += (rand() % (int)(m_velocitySpread.Z * 2000.0f + 1)) / 1000.0f - m_velocitySpread.Z;
|
||||
newParticle->m_velocity = velocity;
|
||||
|
||||
newParticle->m_gravity = m_gravity;
|
||||
|
||||
// calculate and assign colour
|
||||
memcpy(colour, m_startColour, sizeof(float) * 4);
|
||||
colour[0] += (rand() % (int)((m_endColour[0] - m_startColour[0]) * 1000.0f + 1)) / 1000.0f;
|
||||
colour[1] += (rand() % (int)((m_endColour[1] - m_startColour[1]) * 1000.0f + 1)) / 1000.0f;
|
||||
colour[2] += (rand() % (int)((m_endColour[2] - m_startColour[2]) * 1000.0f + 1)) / 1000.0f;
|
||||
colour[3] += (rand() % (int)((m_endColour[3] - m_startColour[3]) * 1000.0f + 1)) / 1000.0f;
|
||||
memcpy(newParticle->m_colour, colour, sizeof(float) * 4);
|
||||
|
||||
// assign sprite
|
||||
newParticle->m_sprite = m_sprite;
|
||||
|
||||
// final pre-processing init call
|
||||
newParticle->Init();
|
||||
|
||||
// add to vector of particles
|
||||
m_particles.push_back(newParticle);
|
||||
|
||||
timeElapsed -= secondsPerEmit;
|
||||
if (timeElapsed < secondsPerEmit)
|
||||
{
|
||||
moreParticlesToEmit = false;
|
||||
}
|
||||
|
||||
|
||||
++m_numParticles;
|
||||
}
|
||||
m_timeSinceLastEmit = 0.0f;
|
||||
}
|
||||
else
|
||||
m_timeSinceLastEmit += (float)timeElapsed;
|
||||
|
||||
m_timeOfLastFrame = get_time();
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetSprite(CSprite * sprite)
|
||||
{
|
||||
m_sprite = sprite;
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetOrigin(CVector3D origin)
|
||||
{
|
||||
m_origin = origin;
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetOrigin(float x, float y, float z)
|
||||
{
|
||||
m_origin.X = x;
|
||||
m_origin.Y = y;
|
||||
m_origin.Z = z;
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetOriginSpread(CVector3D spread)
|
||||
{
|
||||
m_originSpread = spread;
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetOriginSpread(float x, float y, float z)
|
||||
{
|
||||
m_originSpread.X = x;
|
||||
m_originSpread.Y = y;
|
||||
m_originSpread.Z = z;
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetGravity(CVector3D gravity)
|
||||
{
|
||||
m_gravity = gravity;
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetGravity(float x, float y, float z)
|
||||
{
|
||||
m_gravity.X = x;
|
||||
m_gravity.Y = y;
|
||||
m_gravity.Z = z;
|
||||
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetVelocity(CVector3D velocity)
|
||||
{
|
||||
m_velocity = velocity;
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetVelocity(float x, float y, float z)
|
||||
{
|
||||
m_velocity.X = x;
|
||||
m_velocity.Y = y;
|
||||
m_velocity.Z = z;
|
||||
}
|
||||
|
||||
|
||||
void CParticleEmitter::SetVelocitySpread(CVector3D spread)
|
||||
{
|
||||
m_velocitySpread = spread;
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetVelocitySpread(float x, float y, float z)
|
||||
{
|
||||
m_velocitySpread.X = x;
|
||||
m_velocitySpread.Y = y;
|
||||
m_velocitySpread.Z = z;
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetStartColour(float r, float g, float b, float a)
|
||||
{
|
||||
m_startColour[0] = r;
|
||||
m_startColour[1] = g;
|
||||
m_startColour[2] = b;
|
||||
m_startColour[3] = a;
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetEndColour(float r, float g, float b, float a)
|
||||
{
|
||||
m_endColour[0] = r;
|
||||
m_endColour[1] = g;
|
||||
m_endColour[2] = b;
|
||||
m_endColour[3] = a;
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetMaxLifetime(double maxLife)
|
||||
{
|
||||
m_maxLifetime = maxLife;
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetMinLifetime(double minLife)
|
||||
{
|
||||
m_minLifetime = minLife;
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetMaxParticles(int maxParticles)
|
||||
{
|
||||
m_maxParticles = maxParticles;
|
||||
}
|
||||
|
||||
void CParticleEmitter::SetMinParticles(int minParticles)
|
||||
{
|
||||
m_minParticles = minParticles;
|
||||
}
|
119
source/graphics/ParticleEmitter.h
Executable file
119
source/graphics/ParticleEmitter.h
Executable file
@ -0,0 +1,119 @@
|
||||
/*==================================================================
|
||||
|
|
||||
| Name: ParticleEmitter.h
|
||||
|
|
||||
|===================================================================
|
||||
|
|
||||
| Author: Ben Vinegar
|
||||
| Contact: benvinegar () hotmail ! com
|
||||
|
|
||||
|
|
||||
| Last Modified: 03/08/04
|
||||
|
|
||||
| Overview: Particle emitter class that emits particles from
|
||||
| an origin (or area) with a variety of set colours,
|
||||
| durations, forces and a single common sprite.
|
||||
|
|
||||
|
|
||||
| Usage: Instantiate one emitter per desired effect. Set the
|
||||
| various fields (preferably all, the defaults are rather
|
||||
| boring) and then call Frame() - you guessed it - every
|
||||
| frame.
|
||||
|
|
||||
| To do: TBA
|
||||
|
|
||||
| More Information: TBA
|
||||
|
|
||||
==================================================================*/
|
||||
|
||||
#ifndef PARTICLE_EMITTER_H
|
||||
#define PARTICLE_EMITTER_H
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Includes / Compiler directives
|
||||
//--------------------------------------------------------
|
||||
|
||||
#include "Particle.h"
|
||||
#include "Sprite.h"
|
||||
#include "Vector3D.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Declarations
|
||||
//--------------------------------------------------------
|
||||
|
||||
class CParticleEmitter
|
||||
{
|
||||
public:
|
||||
CParticleEmitter();
|
||||
~CParticleEmitter();
|
||||
|
||||
// must be performed before first frame/render/update call
|
||||
bool Init();
|
||||
|
||||
// renders and updates particles
|
||||
void Frame();
|
||||
|
||||
// renders without updating particles
|
||||
void Render();
|
||||
|
||||
void Update();
|
||||
|
||||
void SetSprite(CSprite * sprite);
|
||||
|
||||
void SetOrigin(CVector3D origin);
|
||||
void SetOrigin(float x, float y, float z);
|
||||
|
||||
void SetOriginSpread(CVector3D spread);
|
||||
void SetOriginSpread(float x, float y, float z);
|
||||
|
||||
void SetGravity(CVector3D gravity);
|
||||
void SetGravity(float x, float y, float z);
|
||||
|
||||
void SetVelocity(CVector3D direction);
|
||||
void SetVelocity(float x, float y, float z);
|
||||
|
||||
void SetVelocitySpread(CVector3D spread);
|
||||
void SetVelocitySpread(float x, float y, float z);
|
||||
|
||||
void SetStartColour(float r, float g, float b, float a);
|
||||
void SetEndColour(float r, float g, float b, float a);
|
||||
|
||||
// in milliseconds
|
||||
void SetMaxLifetime(double maxLife);
|
||||
|
||||
// in milliseconds
|
||||
void SetMinLifetime(double minLife);
|
||||
|
||||
void SetMaxParticles(int maxParticles);
|
||||
void SetMinParticles(int minParticles);
|
||||
|
||||
private:
|
||||
CSprite * m_sprite;
|
||||
|
||||
std::vector<CParticle *> m_particles;
|
||||
|
||||
CVector3D m_origin;
|
||||
CVector3D m_originSpread;
|
||||
|
||||
CVector3D m_velocity;
|
||||
CVector3D m_velocitySpread;
|
||||
|
||||
CVector3D m_gravity;
|
||||
|
||||
float m_startColour[4];
|
||||
float m_endColour[4];
|
||||
|
||||
int m_maxParticles;
|
||||
int m_minParticles;
|
||||
int m_numParticles;
|
||||
|
||||
double m_maxLifetime;
|
||||
double m_minLifetime;
|
||||
|
||||
double m_timeOfLastFrame;
|
||||
float m_timeSinceLastEmit;
|
||||
};
|
||||
|
||||
#endif // PARTICLE_EMITTER_H
|
60
source/graphics/Patch.cpp
Executable file
60
source/graphics/Patch.cpp
Executable file
@ -0,0 +1,60 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: ModelDef.cpp
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Patch.h"
|
||||
#include "Terrain.h"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CPatch constructor
|
||||
CPatch::CPatch() : m_Parent(0)
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CPatch destructor
|
||||
CPatch::~CPatch()
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Initialize: setup patch data
|
||||
void CPatch::Initialize(CTerrain* parent,u32 x,u32 z)
|
||||
{
|
||||
delete m_RenderData;
|
||||
m_RenderData=0;
|
||||
|
||||
m_Parent=parent;
|
||||
m_X=x;
|
||||
m_Z=z;
|
||||
|
||||
// set parent of each patch
|
||||
for (int j=0;j<16;j++) {
|
||||
for (int i=0;i<16;i++) {
|
||||
m_MiniPatches[j][i].m_Parent=this;
|
||||
}
|
||||
}
|
||||
|
||||
CalcBounds();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CalcBounds: calculating the bounds of this patch
|
||||
void CPatch::CalcBounds()
|
||||
{
|
||||
m_Bounds.SetEmpty();
|
||||
|
||||
for (int j=0;j<PATCH_SIZE+1;j++) {
|
||||
for (int i=0;i<PATCH_SIZE+1;i++) {
|
||||
CVector3D pos;
|
||||
m_Parent->CalcPosition(m_X*PATCH_SIZE+i,m_Z*PATCH_SIZE+j,pos);
|
||||
m_Bounds+=pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
42
source/graphics/Patch.h
Executable file
42
source/graphics/Patch.h
Executable file
@ -0,0 +1,42 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: Patch.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _PATCH_H
|
||||
#define _PATCH_H
|
||||
|
||||
#include "MiniPatch.h"
|
||||
#include "RenderableObject.h"
|
||||
|
||||
class CTerrain;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CPatch: a single terrain patch, 16 tiles square
|
||||
class CPatch : public CRenderableObject
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CPatch();
|
||||
// destructor
|
||||
~CPatch();
|
||||
|
||||
// initialize the patch
|
||||
void Initialize(CTerrain* parent,u32 x,u32 z);
|
||||
// calculate and store bounds of this patch
|
||||
void CalcBounds();
|
||||
|
||||
public:
|
||||
// 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
|
104
source/graphics/RenderableObject.h
Executable file
104
source/graphics/RenderableObject.h
Executable file
@ -0,0 +1,104 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: RenderableObject.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _RENDERABLEOBJECT_H
|
||||
#define _RENDERABLEOBJECT_H
|
||||
|
||||
#include <assert.h>
|
||||
#include "res/res.h"
|
||||
#include "Bound.h"
|
||||
#include "Matrix3D.h"
|
||||
|
||||
|
||||
// dirty flags - used as notification to the renderer that some bit of data
|
||||
// need updating
|
||||
#define RENDERDATA_UPDATE_VERTICES (1<<1)
|
||||
#define RENDERDATA_UPDATE_INDICES (1<<2)
|
||||
#define RENDERDATA_UPDATE_TRANSFORM (1<<3)
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CRenderData: base class of all the renderer's renderdata classes - the
|
||||
// derived class stores necessary information for rendering an object of a
|
||||
// particular type
|
||||
class CRenderData
|
||||
{
|
||||
public:
|
||||
CRenderData() : m_UpdateFlags(0) {}
|
||||
virtual ~CRenderData() {}
|
||||
|
||||
u32 m_UpdateFlags;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CRenderableObject: base class of all renderable objects - patches, models,
|
||||
// sprites, etc; stores position and bound information, and a pointer to
|
||||
// some renderdata necessary for the renderer to actually render it
|
||||
class CRenderableObject
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CRenderableObject() : m_RenderData(0) {
|
||||
m_Transform.SetIdentity();
|
||||
}
|
||||
// destructor
|
||||
virtual ~CRenderableObject() { delete m_RenderData; }
|
||||
|
||||
// set object transform
|
||||
virtual void SetTransform(const CMatrix3D& transform) {
|
||||
// store transform, calculate inverse
|
||||
m_Transform=transform;
|
||||
m_Transform.GetInverse(m_InvTransform);
|
||||
// normal recalculation likely required on transform change; flag it
|
||||
SetDirty(RENDERDATA_UPDATE_VERTICES);
|
||||
// rebuild world space bounds
|
||||
CalcBounds();
|
||||
}
|
||||
// get object to world space transform
|
||||
const CMatrix3D& GetTransform() const { return m_Transform; }
|
||||
// get world to object space transform
|
||||
const CMatrix3D& GetInvTransform() const { return m_InvTransform; }
|
||||
|
||||
// mark some part of the renderdata as dirty, and requiring
|
||||
// an update on next render
|
||||
void SetDirty(u32 dirtyflags) {
|
||||
if (m_RenderData) m_RenderData->m_UpdateFlags|=dirtyflags;
|
||||
}
|
||||
|
||||
// calculate (and store in m_Bounds) the world space bounds of this object
|
||||
// - must be implemented by all concrete subclasses
|
||||
virtual void CalcBounds() = 0;
|
||||
|
||||
// return world space bounds of this object
|
||||
const CBound& GetBounds() const { return m_Bounds; }
|
||||
|
||||
// set the object renderdata
|
||||
// TODO,RC 10/04/04 - need to delete existing renderdata here, or can we
|
||||
// assume the renderer won't set renderdata when an object already has it?
|
||||
// - just assert we've no renderdata at the minute
|
||||
void SetRenderData(CRenderData* renderdata) {
|
||||
assert(m_RenderData==0);
|
||||
m_RenderData=renderdata;
|
||||
}
|
||||
|
||||
// return object renderdata - can be null if renderer hasn't yet
|
||||
// created the renderdata
|
||||
CRenderData* GetRenderData() { return m_RenderData; }
|
||||
|
||||
protected:
|
||||
// object bounds
|
||||
CBound m_Bounds;
|
||||
// local->world space transform
|
||||
CMatrix3D m_Transform;
|
||||
// world->local space transform
|
||||
CMatrix3D m_InvTransform;
|
||||
// object renderdata
|
||||
CRenderData* m_RenderData;
|
||||
};
|
||||
|
||||
#endif
|
30
source/graphics/SkeletonAnim.h
Executable file
30
source/graphics/SkeletonAnim.h
Executable file
@ -0,0 +1,30 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: SkeletonAnim.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _SKELETONANIM_H
|
||||
#define _SKELETONANIM_H
|
||||
|
||||
#include "Bound.h"
|
||||
|
||||
class CSkeletonAnimDef;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CSkeletonAnim: an instance of a CSkeletonAnimDef, for application onto a model
|
||||
class CSkeletonAnim
|
||||
{
|
||||
public:
|
||||
// the raw animation frame data
|
||||
CSkeletonAnimDef* m_AnimDef;
|
||||
// speed at which this animation runs
|
||||
float m_Speed;
|
||||
// object space bounds of the model when this animation is applied to it
|
||||
CBound m_ObjectBounds;
|
||||
};
|
||||
|
||||
#endif
|
101
source/graphics/SkeletonAnimDef.cpp
Executable file
101
source/graphics/SkeletonAnimDef.cpp
Executable file
@ -0,0 +1,101 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: SkeletonAnimDef.cpp
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SkeletonAnimDef.h"
|
||||
#include "FilePacker.h"
|
||||
#include "FileUnpacker.h"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CSkeletonAnimDef constructor
|
||||
CSkeletonAnimDef::CSkeletonAnimDef() : m_Keys(0), m_NumKeys(0), m_NumFrames(0), m_FrameTime(0)
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CSkeletonAnimDef destructor
|
||||
CSkeletonAnimDef::~CSkeletonAnimDef()
|
||||
{
|
||||
delete[] m_Keys;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BuildBoneMatrices: build matrices for all bones at the given time (in MS) in this
|
||||
// animation
|
||||
void CSkeletonAnimDef::BuildBoneMatrices(float time,CMatrix3D* matrices) const
|
||||
{
|
||||
float fstartframe=time/m_FrameTime;
|
||||
u32 startframe=u32(time/m_FrameTime);
|
||||
float deltatime=fstartframe-startframe;
|
||||
|
||||
startframe%=m_NumFrames;
|
||||
|
||||
u32 endframe=startframe+1;
|
||||
endframe%=m_NumFrames;
|
||||
|
||||
u32 i;
|
||||
for (i=0;i<m_NumKeys;i++) {
|
||||
const Key& startkey=GetKey(startframe,i);
|
||||
const Key& endkey=GetKey(endframe,i);
|
||||
|
||||
CVector3D trans=startkey.m_Translation*(1-deltatime)+endkey.m_Translation*deltatime;
|
||||
CQuaternion rot;
|
||||
rot.Slerp(startkey.m_Rotation,endkey.m_Rotation,deltatime);
|
||||
|
||||
matrices[i].SetIdentity();
|
||||
matrices[i].Rotate(rot);
|
||||
matrices[i].Translate(trans);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Load: try to load the anim from given file; return a new anim if successful
|
||||
CSkeletonAnimDef* CSkeletonAnimDef::Load(const char* filename)
|
||||
{
|
||||
CFileUnpacker unpacker;
|
||||
unpacker.Read(filename,"PSSA");
|
||||
|
||||
// check version
|
||||
if (unpacker.GetVersion()<FILE_READ_VERSION) {
|
||||
throw CFileUnpacker::CFileVersionError();
|
||||
}
|
||||
|
||||
// unpack the data
|
||||
CSkeletonAnimDef* anim=new CSkeletonAnimDef;
|
||||
try {
|
||||
unpacker.UnpackString(anim->m_Name);
|
||||
unpacker.UnpackRaw(&anim->m_FrameTime,sizeof(anim->m_FrameTime));
|
||||
unpacker.UnpackRaw(&anim->m_NumKeys,sizeof(anim->m_NumKeys));
|
||||
unpacker.UnpackRaw(&anim->m_NumFrames,sizeof(anim->m_NumFrames));
|
||||
anim->m_Keys=new Key[anim->m_NumKeys*anim->m_NumFrames];
|
||||
unpacker.UnpackRaw(anim->m_Keys,anim->m_NumKeys*anim->m_NumFrames*sizeof(Key));
|
||||
} catch (...) {
|
||||
delete anim;
|
||||
throw CFileUnpacker::CFileEOFError();
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Save: try to save anim to file
|
||||
void CSkeletonAnimDef::Save(const char* filename,const CSkeletonAnimDef* anim)
|
||||
{
|
||||
CFilePacker packer;
|
||||
|
||||
// pack up all the data
|
||||
packer.PackString(CStr(anim->m_Name));
|
||||
packer.PackRaw(&anim->m_FrameTime,sizeof(anim->m_FrameTime));
|
||||
packer.PackRaw(&anim->m_NumKeys,sizeof(anim->m_NumKeys));
|
||||
packer.PackRaw(&anim->m_NumFrames,sizeof(anim->m_NumFrames));
|
||||
packer.PackRaw(anim->m_Keys,anim->m_NumKeys*anim->m_NumFrames*sizeof(Key));
|
||||
|
||||
// now write it
|
||||
packer.Write(filename,FILE_VERSION,"PSSA");
|
||||
}
|
||||
|
85
source/graphics/SkeletonAnimDef.h
Executable file
85
source/graphics/SkeletonAnimDef.h
Executable file
@ -0,0 +1,85 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: SkeletonAnimDef.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _SKELETONANIMDEF_H
|
||||
#define _SKELETONANIMDEF_H
|
||||
|
||||
#include "res/res.h"
|
||||
#include "CStr.h"
|
||||
#include "Vector3D.h"
|
||||
#include "Quaternion.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CBoneState: structure describing state of a bone at some point
|
||||
class CBoneState
|
||||
{
|
||||
public:
|
||||
// translation of bone relative to root
|
||||
CVector3D m_Translation;
|
||||
// rotation of bone relative to root
|
||||
CQuaternion m_Rotation;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CSkeletonAnimDef: raw description - eg bonestates - of an animation that plays upon
|
||||
// a skeleton
|
||||
class CSkeletonAnimDef
|
||||
{
|
||||
public:
|
||||
// current file version given to saved animations
|
||||
enum { FILE_VERSION = 1 };
|
||||
// supported file read version - files with a version less than this will be rejected
|
||||
enum { FILE_READ_VERSION = 1 };
|
||||
|
||||
|
||||
public:
|
||||
// Key: description of a single key in a skeleton animation
|
||||
typedef CBoneState Key;
|
||||
|
||||
public:
|
||||
// CSkeletonAnimDef constructor + destructor
|
||||
CSkeletonAnimDef();
|
||||
~CSkeletonAnimDef();
|
||||
|
||||
// return the number of keys in this animation
|
||||
u32 GetNumKeys() const { return m_NumKeys; }
|
||||
|
||||
// accessors: get a key for given bone at given time
|
||||
Key& GetKey(u32 frame,u32 bone) { return m_Keys[frame*m_NumKeys+bone]; }
|
||||
const Key& GetKey(u32 frame,u32 bone) const { return m_Keys[frame*m_NumKeys+bone]; }
|
||||
|
||||
// get duration of this anim, in ms
|
||||
float GetDuration() const { return m_NumFrames*m_FrameTime; }
|
||||
|
||||
// return length of each frame, in ms
|
||||
float GetFrameTime() const { return m_FrameTime; }
|
||||
// return number of frames in animation
|
||||
u32 GetNumFrames() const { return m_NumFrames; }
|
||||
|
||||
// build matrices for all bones at the given time (in MS) in this animation
|
||||
void BuildBoneMatrices(float time,CMatrix3D* matrices) const;
|
||||
|
||||
// anim I/O functions
|
||||
static CSkeletonAnimDef* Load(const char* filename);
|
||||
static void Save(const char* filename,const CSkeletonAnimDef* anim);
|
||||
|
||||
public:
|
||||
// name of the animation
|
||||
CStr m_Name;
|
||||
// frame time - time between successive frames, in ms
|
||||
float m_FrameTime;
|
||||
// number of keys in each frame - should match number of bones in the skeleton
|
||||
u32 m_NumKeys;
|
||||
// number of frames in the animation
|
||||
u32 m_NumFrames;
|
||||
// animation data - m_NumKeys*m_NumFrames total keys
|
||||
Key* m_Keys;
|
||||
};
|
||||
|
||||
#endif
|
67
source/graphics/SkeletonAnimManager.cpp
Executable file
67
source/graphics/SkeletonAnimManager.cpp
Executable file
@ -0,0 +1,67 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: SkeletonAnimManager.cpp
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "res/res.h"
|
||||
#include "Model.h"
|
||||
#include "SkeletonAnimManager.h"
|
||||
#include <algorithm>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CSkeletonAnimManager constructor
|
||||
CSkeletonAnimManager::CSkeletonAnimManager()
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CSkeletonAnimManager destructor
|
||||
CSkeletonAnimManager::~CSkeletonAnimManager()
|
||||
{
|
||||
typedef std::map<CStr,CSkeletonAnimDef*>::iterator Iter;
|
||||
for (Iter i=m_Animations.begin();i!=m_Animations.end();++i) {
|
||||
delete i->second;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GetAnimation: return a given animation by filename; return null if filename
|
||||
// doesn't refer to valid animation file
|
||||
CSkeletonAnimDef* CSkeletonAnimManager::GetAnimation(const char* filename)
|
||||
{
|
||||
// already loaded?
|
||||
CStr fname(filename);
|
||||
std::map<CStr,CSkeletonAnimDef*>::iterator iter=m_Animations.find(fname);
|
||||
if (iter!=m_Animations.end()) {
|
||||
// yes - return it
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
// already failed to load?
|
||||
std::set<CStr>::iterator setiter=m_BadAnimationFiles.find(fname);
|
||||
if (setiter!=m_BadAnimationFiles.end()) {
|
||||
// yes - return null
|
||||
return 0;
|
||||
}
|
||||
|
||||
// try and load it now
|
||||
CSkeletonAnimDef* def;
|
||||
try {
|
||||
def=CSkeletonAnimDef::Load(filename);
|
||||
} catch (...) {
|
||||
def=0;
|
||||
}
|
||||
|
||||
if (!def) {
|
||||
// add this file as bad
|
||||
m_BadAnimationFiles.insert(fname);
|
||||
return 0;
|
||||
} else {
|
||||
// add mapping for this file
|
||||
m_Animations[fname]=def;
|
||||
return def;
|
||||
}
|
||||
}
|
44
source/graphics/SkeletonAnimManager.h
Executable file
44
source/graphics/SkeletonAnimManager.h
Executable file
@ -0,0 +1,44 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: SkeletonAnimManager.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _SKELETONANIMMANAGER_H
|
||||
#define _SKELETONANIMMANAGER_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include "SkeletonAnimDef.h"
|
||||
#include "Singleton.h"
|
||||
|
||||
|
||||
// access to sole CSkeletonAnimManager object
|
||||
#define g_SkelAnimMan CSkeletonAnimManager::GetSingleton()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CSkeletonAnimManager : owner class of all skeleton anims - manages creation,
|
||||
// loading and destruction of animation data
|
||||
class CSkeletonAnimManager : public Singleton<CSkeletonAnimManager>
|
||||
{
|
||||
public:
|
||||
// constructor, destructor
|
||||
CSkeletonAnimManager();
|
||||
~CSkeletonAnimManager();
|
||||
|
||||
// return a given animation by filename; return null if filename doesn't
|
||||
// refer to valid animation file
|
||||
CSkeletonAnimDef* GetAnimation(const char* filename);
|
||||
|
||||
private:
|
||||
CSkeletonAnimDef* LoadAnimation(const char* filename);
|
||||
|
||||
// map of all known animations
|
||||
std::map<CStr,CSkeletonAnimDef*> m_Animations;
|
||||
// set of bad animation names - prevents multiple reloads of bad files
|
||||
std::set<CStr> m_BadAnimationFiles;
|
||||
};
|
||||
|
||||
#endif
|
215
source/graphics/Sprite.cpp
Executable file
215
source/graphics/Sprite.cpp
Executable file
@ -0,0 +1,215 @@
|
||||
/*==================================================================
|
||||
|
|
||||
| Name: Sprite.cpp
|
||||
|
|
||||
|===================================================================
|
||||
|
|
||||
| Author: Ben Vinegar
|
||||
| Contact: benvinegar () hotmail ! com
|
||||
|
|
||||
|
|
||||
| Last Modified: 03/08/04
|
||||
|
|
||||
| Overview: Billboarding sprite class - always faces the camera. It
|
||||
| does this by getting the current model view matrix state.
|
||||
|
|
||||
|
|
||||
| Usage: The functions speak for themselves. Instantiate, then be
|
||||
| sure to pass a loaded (using tex_load()) texture before
|
||||
| calling Render().
|
||||
|
|
||||
| To do: TBA
|
||||
|
|
||||
| More Information: TBA
|
||||
|
|
||||
==================================================================*/
|
||||
|
||||
#include "Sprite.h"
|
||||
#include "Renderer.h"
|
||||
#include "ogl.h"
|
||||
#include "res/tex.h"
|
||||
|
||||
CSprite::CSprite() :
|
||||
m_texture(NULL)
|
||||
{
|
||||
|
||||
// default scale 1:1
|
||||
m_scale.X = m_scale.Y = m_scale.Z = 1.0f;
|
||||
|
||||
// default position (0.0f, 0.0f, 0.0f)
|
||||
m_translation.X = m_translation.Y = m_translation.Z = 0.0f;
|
||||
|
||||
// default size 1.0 x 1.0
|
||||
SetSize(1.0f, 1.0f);
|
||||
|
||||
// default colour, white
|
||||
m_colour[0] = m_colour[1] = m_colour[2] = m_colour[3] = 1.0f;
|
||||
}
|
||||
|
||||
CSprite::~CSprite()
|
||||
{
|
||||
}
|
||||
|
||||
void CSprite::Render()
|
||||
{
|
||||
BeginBillboard();
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
glTranslatef(m_translation.X, m_translation.Y, m_translation.Z);
|
||||
glScalef(m_scale.X, m_scale.Y, m_scale.Z);
|
||||
|
||||
g_Renderer.BindTexture(0,tex_id(m_texture->GetHandle()));
|
||||
|
||||
glColor4fv(m_colour);
|
||||
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
// bottom left
|
||||
glTexCoord2f(0.0f, 0.0f);
|
||||
glVertex3fv((GLfloat *) &m_coords[0]);
|
||||
|
||||
// top left
|
||||
glTexCoord2f(0.0f, 1.0f);
|
||||
glVertex3fv((GLfloat *) &m_coords[1]);
|
||||
|
||||
// bottom right
|
||||
glTexCoord2f(1.0f, 0.0f);
|
||||
glVertex3fv((GLfloat *) &m_coords[2]);
|
||||
|
||||
// top left
|
||||
glTexCoord2f(1.0f, 1.0f);
|
||||
glVertex3fv((GLfloat *) &m_coords[3]);
|
||||
glEnd();
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
EndBillboard();
|
||||
}
|
||||
|
||||
int CSprite::SetTexture(CTexture *texture)
|
||||
{
|
||||
if (texture == NULL) return -1;
|
||||
|
||||
m_texture = texture;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CSprite::SetSize(float width, float height)
|
||||
{
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
|
||||
float xOffset = m_width / 2;
|
||||
float yOffset = m_height / 2;
|
||||
|
||||
// bottom left
|
||||
m_coords[0].X = - (xOffset);
|
||||
m_coords[0].Y = - (yOffset);
|
||||
m_coords[0].Z = 0.0f;
|
||||
|
||||
// top left
|
||||
m_coords[1].X = - (xOffset);
|
||||
m_coords[1].Y = yOffset;
|
||||
m_coords[1].Z = 0.0f;
|
||||
|
||||
// bottom right
|
||||
m_coords[2].X = xOffset;
|
||||
m_coords[2].Y = - (yOffset);
|
||||
m_coords[2].Z = 0.0f;
|
||||
|
||||
// top right
|
||||
m_coords[3].X = xOffset;
|
||||
m_coords[3].Y = yOffset;
|
||||
m_coords[3].Z = 0.0f;
|
||||
}
|
||||
|
||||
float CSprite::GetWidth()
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
|
||||
void CSprite::SetWidth(float width)
|
||||
{
|
||||
SetSize(width, m_height);
|
||||
}
|
||||
|
||||
float CSprite::GetHeight()
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
void CSprite::SetHeight(float height)
|
||||
{
|
||||
SetSize(m_width, height);
|
||||
}
|
||||
|
||||
CVector3D CSprite::GetTranslation()
|
||||
{
|
||||
return m_translation;
|
||||
}
|
||||
|
||||
void CSprite::SetTranslation(CVector3D trans)
|
||||
{
|
||||
m_translation = trans;
|
||||
}
|
||||
|
||||
void CSprite::SetTranslation(float x, float y, float z)
|
||||
{
|
||||
m_translation.X = x;
|
||||
m_translation.Y = y;
|
||||
m_translation.Z = z;
|
||||
}
|
||||
|
||||
CVector3D CSprite::GetScale()
|
||||
{
|
||||
return m_scale;
|
||||
}
|
||||
|
||||
void CSprite::SetScale(CVector3D scale)
|
||||
{
|
||||
m_scale = scale;
|
||||
}
|
||||
|
||||
void CSprite::SetScale(float x, float y, float z)
|
||||
{
|
||||
m_scale.X = x;
|
||||
m_scale.Y = y;
|
||||
m_scale.Z = z;
|
||||
}
|
||||
|
||||
void CSprite::SetColour(float * colour)
|
||||
{
|
||||
m_colour[0] = colour[0];
|
||||
m_colour[1] = colour[1];
|
||||
m_colour[2] = colour[2];
|
||||
m_colour[3] = colour[3];
|
||||
}
|
||||
|
||||
// should be called before any other gl calls
|
||||
void CSprite::BeginBillboard()
|
||||
{
|
||||
float newMatrix[16] = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f };
|
||||
float currentMatrix[16];
|
||||
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX, currentMatrix);
|
||||
newMatrix[0] = currentMatrix[0];
|
||||
newMatrix[1] = currentMatrix[4];
|
||||
newMatrix[2] = currentMatrix[8];
|
||||
newMatrix[4] = currentMatrix[1];
|
||||
newMatrix[5] = currentMatrix[5];
|
||||
newMatrix[6] = currentMatrix[9];
|
||||
newMatrix[8] = currentMatrix[2];
|
||||
newMatrix[9] = currentMatrix[6];
|
||||
newMatrix[10] = currentMatrix[10];
|
||||
|
||||
glPushMatrix();
|
||||
glMultMatrixf(newMatrix);
|
||||
}
|
||||
|
||||
void CSprite::EndBillboard()
|
||||
{
|
||||
glPopMatrix();
|
||||
}
|
86
source/graphics/Sprite.h
Executable file
86
source/graphics/Sprite.h
Executable file
@ -0,0 +1,86 @@
|
||||
/*==================================================================
|
||||
|
|
||||
| Name: Sprite.h
|
||||
|
|
||||
|===================================================================
|
||||
|
|
||||
| Author: Ben Vinegar
|
||||
| Contact: benvinegar () hotmail ! com
|
||||
|
|
||||
|
|
||||
| Last Modified: 03/08/04
|
||||
|
|
||||
| Overview: Billboarding sprite class - always faces the camera. It
|
||||
| does this by getting the current model view matrix state.
|
||||
|
|
||||
|
|
||||
| Usage: The functions speak for themselves. Instantiate, then be
|
||||
| sure to pass a loaded (using tex_load()) texture before
|
||||
| calling Render().
|
||||
|
|
||||
| To do: TBA
|
||||
|
|
||||
| More Information: TBA
|
||||
|
|
||||
==================================================================*/
|
||||
|
||||
#ifndef SPRITE_H
|
||||
#define SPRITE_H
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Includes / Compiler directives
|
||||
//--------------------------------------------------------
|
||||
|
||||
#include "Vector3D.h"
|
||||
#include "Texture.h"
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Declarations
|
||||
//--------------------------------------------------------
|
||||
|
||||
class CSprite
|
||||
{
|
||||
public:
|
||||
CSprite();
|
||||
~CSprite();
|
||||
|
||||
void Render();
|
||||
|
||||
int SetTexture(CTexture *texture);
|
||||
|
||||
void SetSize(float width, float height);
|
||||
|
||||
float GetWidth();
|
||||
void SetWidth(float width);
|
||||
|
||||
float GetHeight();
|
||||
void SetHeight(float height);
|
||||
|
||||
CVector3D GetTranslation();
|
||||
void SetTranslation(CVector3D pos);
|
||||
void SetTranslation(float x, float y, float z);
|
||||
|
||||
CVector3D GetScale();
|
||||
void SetScale(CVector3D scale);
|
||||
void SetScale(float x, float y, float z);
|
||||
|
||||
void SetColour(float * colour);
|
||||
void SetColour(float r, float g, float b, float a = 1.0f);
|
||||
private:
|
||||
void BeginBillboard();
|
||||
void EndBillboard();
|
||||
|
||||
CTexture *m_texture;
|
||||
|
||||
CVector3D m_coords[4];
|
||||
|
||||
float m_width;
|
||||
float m_height;
|
||||
|
||||
CVector3D m_translation;
|
||||
CVector3D m_scale;
|
||||
|
||||
float m_colour[4];
|
||||
};
|
||||
|
||||
#endif // SPRITE_H
|
292
source/graphics/Terrain.cpp
Executable file
292
source/graphics/Terrain.cpp
Executable file
@ -0,0 +1,292 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: Terrain.cpp
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "res/tex.h"
|
||||
#include "res/mem.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "Terrain.h"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CTerrain constructor
|
||||
CTerrain::CTerrain() : m_Heightmap(0), m_Patches(0), m_MapSize(0), m_MapSizePatches(0)
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CTerrain constructor
|
||||
CTerrain::~CTerrain()
|
||||
{
|
||||
ReleaseData();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ReleaseData: delete any data allocated by this terrain
|
||||
void CTerrain::ReleaseData()
|
||||
{
|
||||
delete[] m_Heightmap;
|
||||
delete[] m_Patches;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Initialise: initialise this terrain to the given size (in patches per side);
|
||||
// using given heightmap to setup elevation data
|
||||
bool CTerrain::Initialize(u32 size,const u16* data)
|
||||
{
|
||||
// clean up any previous terrain
|
||||
ReleaseData();
|
||||
|
||||
// store terrain size
|
||||
m_MapSize=(size*PATCH_SIZE)+1;
|
||||
m_MapSizePatches=size;
|
||||
|
||||
// allocate data for new terrain
|
||||
m_Heightmap=new u16[m_MapSize*m_MapSize];
|
||||
m_Patches=new CPatch[m_MapSizePatches*m_MapSizePatches];
|
||||
|
||||
// given a heightmap?
|
||||
if (data) {
|
||||
// yes; keep a copy of it
|
||||
memcpy(m_Heightmap,data,m_MapSize*m_MapSize*sizeof(u16));
|
||||
} else {
|
||||
// build a flat terrain
|
||||
memset(m_Heightmap,0,m_MapSize*m_MapSize*sizeof(u16));
|
||||
}
|
||||
|
||||
// setup patch parents, indices etc
|
||||
InitialisePatches();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CalcPosition: calculate the world space position of the vertex at (i,j)
|
||||
void CTerrain::CalcPosition(u32 i,u32 j,CVector3D& pos)
|
||||
{
|
||||
u16 height=m_Heightmap[j*m_MapSize + i];
|
||||
pos.X = float(i)*CELL_SIZE;
|
||||
pos.Y = float(height)*HEIGHT_SCALE;
|
||||
pos.Z = float(j)*CELL_SIZE;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CalcNormal: calculate the world space normal of the vertex at (i,j)
|
||||
void CTerrain::CalcNormal(u32 i,u32 j,CVector3D& normal)
|
||||
{
|
||||
CVector3D left, right, up, down;
|
||||
|
||||
left.Clear();
|
||||
right.Clear();
|
||||
up.Clear();
|
||||
down.Clear();
|
||||
|
||||
// get position of vertex where normal is being evaluated
|
||||
CVector3D basepos;
|
||||
CalcPosition(i,j,basepos);
|
||||
|
||||
CVector3D tmp;
|
||||
if (i>0) {
|
||||
CalcPosition(i-1,j,tmp);
|
||||
left=tmp-basepos;
|
||||
}
|
||||
|
||||
if (i<m_MapSize-1) {
|
||||
CalcPosition(i+1,j,tmp);
|
||||
right=tmp-basepos;
|
||||
}
|
||||
|
||||
if (j>0) {
|
||||
CalcPosition(i,j-1,tmp);
|
||||
up=tmp-basepos;
|
||||
}
|
||||
|
||||
if (j<m_MapSize-1) {
|
||||
CalcPosition(i,j+1,tmp);
|
||||
down=tmp-basepos;
|
||||
}
|
||||
|
||||
CVector3D n0 = up.Cross(left);
|
||||
CVector3D n1 = left.Cross(down);
|
||||
CVector3D n2 = down.Cross(right);
|
||||
CVector3D n3 = right.Cross(up);
|
||||
|
||||
normal = n0 + n1 + n2 + n3;
|
||||
float nlen=normal.GetLength();
|
||||
if (nlen>0.00001f) normal*=1.0f/nlen;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GetPatch: return the patch at (x,z) in patch space, or null if the patch is
|
||||
// out of bounds
|
||||
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];
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GetPatch: return the tile at (x,z) in tile space, or null if the tile is out
|
||||
// of bounds
|
||||
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];
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Resize: resize this terrain to the given size (in patches per side)
|
||||
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;j<copysize;j++) {
|
||||
memcpy(dst,src,copysize*sizeof(u16));
|
||||
dst+=copysize;
|
||||
src+=m_MapSize;
|
||||
if (newMapSize>m_MapSize) {
|
||||
// entend the last height to the end of the row
|
||||
for (u32 i=0;i<newMapSize-m_MapSize;i++) {
|
||||
*dst++=*(src-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (newMapSize>m_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;i<newMapSize-m_MapSize;i++) {
|
||||
memcpy(dst,src,newMapSize*sizeof(u16));
|
||||
dst+=newMapSize;
|
||||
}
|
||||
}
|
||||
|
||||
// now build new patches
|
||||
for (j=0;j<size;j++) {
|
||||
for (u32 i=0;i<size;i++) {
|
||||
// copy over texture data from existing tiles, if possible
|
||||
if (i<m_MapSizePatches && j<m_MapSizePatches) {
|
||||
memcpy(newPatches[j*size+i].m_MiniPatches,m_Patches[j*m_MapSizePatches+i].m_MiniPatches,sizeof(CMiniPatch)*16*16);
|
||||
}
|
||||
}
|
||||
|
||||
if (j<m_MapSizePatches && size>m_MapSizePatches) {
|
||||
// copy over the last tile from each column
|
||||
for (u32 n=0;n<size-m_MapSizePatches;n++) {
|
||||
for (int m=0;m<16;m++) {
|
||||
CMiniPatch& src=m_Patches[j*m_MapSizePatches+m_MapSizePatches-1].m_MiniPatches[m][15];
|
||||
for (int k=0;k<16;k++) {
|
||||
CMiniPatch& dst=newPatches[j*size+m_MapSizePatches+n].m_MiniPatches[m][k];
|
||||
dst.Tex1=src.Tex1;
|
||||
dst.Tex1Priority=src.Tex1Priority;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (size>m_MapSizePatches) {
|
||||
// copy over the last tile from each column
|
||||
CPatch* srcpatch=&newPatches[(m_MapSizePatches-1)*size];
|
||||
CPatch* dstpatch=srcpatch+size;
|
||||
for (u32 p=0;p<size-m_MapSizePatches;p++) {
|
||||
for (u32 n=0;n<size;n++) {
|
||||
for (int m=0;m<16;m++) {
|
||||
for (int k=0;k<16;k++) {
|
||||
CMiniPatch& src=srcpatch->m_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
|
||||
ReleaseData();
|
||||
|
||||
// store new data
|
||||
m_Heightmap=newHeightmap;
|
||||
m_Patches=newPatches;
|
||||
m_MapSize=newMapSize;
|
||||
m_MapSizePatches=size;
|
||||
|
||||
// initialise all the new patches
|
||||
InitialisePatches();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// InitialisePatches: initialise patch data
|
||||
void CTerrain::InitialisePatches()
|
||||
{
|
||||
for (u32 j=0;j<m_MapSizePatches;j++) {
|
||||
for (u32 i=0;i<m_MapSizePatches;i++) {
|
||||
CPatch* patch=GetPatch(i,j);
|
||||
patch->Initialize(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;j<m_MapSizePatches;j++) {
|
||||
for (u32 i=0;i<m_MapSizePatches;i++) {
|
||||
CPatch* patch=GetPatch(i,j);
|
||||
patch->CalcBounds();
|
||||
patch->SetDirty(RENDERDATA_UPDATE_VERTICES);
|
||||
}
|
||||
}
|
||||
}
|
82
source/graphics/Terrain.h
Executable file
82
source/graphics/Terrain.h
Executable file
@ -0,0 +1,82 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: Terrain.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef _TERRAIN_H
|
||||
#define _TERRAIN_H
|
||||
|
||||
#include "Patch.h"
|
||||
#include "Vector3D.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Terrain Constants:
|
||||
//
|
||||
// PATCH_SIZE: number of tiles in each patch
|
||||
const int PATCH_SIZE = 16;
|
||||
// CELL_SIZE: size of each tile in x and z
|
||||
const int CELL_SIZE = 4;
|
||||
// HEIGHT_SCALE: vertical scale of terrain - terrain has a coordinate range of
|
||||
// 0 to 65536*HEIGHT_SCALE
|
||||
const float HEIGHT_SCALE = 0.35f/256.0f;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CTerrain: main terrain class; contains the heightmap describing elevation
|
||||
// data, and the smaller subpatches that form the terrain
|
||||
class CTerrain
|
||||
{
|
||||
public:
|
||||
CTerrain();
|
||||
~CTerrain();
|
||||
|
||||
bool Initialize(u32 size,const u16* ptr);
|
||||
|
||||
// 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:
|
||||
// delete any data allocated by this terrain
|
||||
void ReleaseData();
|
||||
// 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;
|
||||
};
|
||||
|
||||
extern CTerrain g_Terrain;
|
||||
|
||||
#endif
|
35
source/graphics/Texture.h
Executable file
35
source/graphics/Texture.h
Executable file
@ -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/res.h"
|
||||
#include "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
|
24
source/graphics/TextureEntry.h
Executable file
24
source/graphics/TextureEntry.h
Executable file
@ -0,0 +1,24 @@
|
||||
#ifndef _TEXTUREENTRY_H
|
||||
#define _TEXTUREENTRY_H
|
||||
|
||||
#include "res/res.h"
|
||||
#include "CStr.h"
|
||||
|
||||
class CTextureEntry
|
||||
{
|
||||
public:
|
||||
CTextureEntry() : m_Bitmap(0), m_Handle(0), m_BaseColor(0), m_Type(0) {}
|
||||
|
||||
// filename
|
||||
CStr m_Name;
|
||||
// UI bitmap object
|
||||
void* m_Bitmap;
|
||||
// handle to GL texture data
|
||||
Handle m_Handle;
|
||||
// BGRA color of topmost mipmap level, for coloring minimap
|
||||
unsigned int m_BaseColor;
|
||||
// "type" of texture - index into TextureManager texturetypes array
|
||||
int m_Type;
|
||||
};
|
||||
|
||||
#endif
|
208
source/graphics/TextureManager.cpp
Executable file
208
source/graphics/TextureManager.cpp
Executable file
@ -0,0 +1,208 @@
|
||||
|
||||
#include "TextureManager.h"
|
||||
#include "lib.h"
|
||||
#include "ogl.h"
|
||||
#include "res/tex.h"
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
|
||||
const char* SupportedTextureFormats[] = { "png", "dds", "tga", "bmp" };
|
||||
|
||||
|
||||
|
||||
CTextureManager::CTextureManager()
|
||||
{
|
||||
m_TerrainTextures.reserve(32);
|
||||
}
|
||||
|
||||
CTextureManager::~CTextureManager()
|
||||
{
|
||||
for (size_t i=0;i<m_TerrainTextures.size();i++) {
|
||||
for (size_t j=0;j<m_TerrainTextures[i].m_Textures.size();j++) {
|
||||
delete m_TerrainTextures[i].m_Textures[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CTextureManager::AddTextureType(const char* name)
|
||||
{
|
||||
m_TerrainTextures.resize(m_TerrainTextures.size()+1);
|
||||
STextureType& ttype=m_TerrainTextures.back();
|
||||
ttype.m_Name=name;
|
||||
ttype.m_Index=m_TerrainTextures.size()-1;
|
||||
}
|
||||
|
||||
CTextureEntry* CTextureManager::FindTexture(const char* filename)
|
||||
{
|
||||
// check if file already loaded
|
||||
for (uint k=0;k<m_TerrainTextures.size();k++) {
|
||||
STextureType& ttype=m_TerrainTextures[k];
|
||||
for (uint i=0;i<ttype.m_Textures.size();i++) {
|
||||
if (strcmp((const char*) ttype.m_Textures[i]->m_Name,filename)==0) {
|
||||
return ttype.m_Textures[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CTextureEntry* CTextureManager::FindTexture(Handle handle)
|
||||
{
|
||||
for (uint k=0;k<m_TerrainTextures.size();k++) {
|
||||
STextureType& ttype=m_TerrainTextures[k];
|
||||
for (uint i=0;i<ttype.m_Textures.size();i++) {
|
||||
if (handle==ttype.m_Textures[i]->m_Handle) {
|
||||
return ttype.m_Textures[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CTextureEntry* CTextureManager::AddTexture(const char* filename,int type)
|
||||
{
|
||||
assert((uint)type<m_TerrainTextures.size());
|
||||
|
||||
CStr pathname("art/textures/terrain/types/");
|
||||
pathname+=m_TerrainTextures[type].m_Name;
|
||||
pathname+='/';
|
||||
pathname+=filename;
|
||||
|
||||
Handle h=tex_load((const char*) pathname);
|
||||
if (!h) {
|
||||
return 0;
|
||||
} else {
|
||||
int tw;
|
||||
int th;
|
||||
|
||||
tex_info(h, &tw, &th, NULL, NULL, NULL);
|
||||
|
||||
tw &= (tw-1);
|
||||
th &= (th-1);
|
||||
if (tw || th) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// create new texture entry
|
||||
CTextureEntry* texentry=new CTextureEntry;
|
||||
texentry->m_Name=filename;
|
||||
texentry->m_Handle=h;
|
||||
texentry->m_Type=type;
|
||||
|
||||
// upload texture for future GL use
|
||||
tex_upload(h,GL_LINEAR_MIPMAP_LINEAR);
|
||||
|
||||
// setup texture to repeat
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
// get root color for coloring minimap by querying root level of the texture
|
||||
// (this should decompress any compressed textures for us),
|
||||
// then scaling it down to a 1x1 size
|
||||
// - an alternative approach of just grabbing the top level of the mipmap tree fails
|
||||
// (or gives an incorrect colour) in some cases:
|
||||
// - suspect bug on Radeon cards when SGIS_generate_mipmap is used
|
||||
// - any textures without mipmaps
|
||||
// we'll just take the basic approach here:
|
||||
int width,height;
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_WIDTH,&width);
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_HEIGHT,&height);
|
||||
|
||||
unsigned char* buf=new unsigned char[width*height*4];
|
||||
glGetTexImage(GL_TEXTURE_2D,0,GL_BGRA_EXT,GL_UNSIGNED_BYTE,buf);
|
||||
gluScaleImage(GL_BGRA_EXT,width,height,GL_UNSIGNED_BYTE,buf,
|
||||
1,1,GL_UNSIGNED_BYTE,&texentry->m_BaseColor);
|
||||
delete[] buf;
|
||||
|
||||
// add entry to list ..
|
||||
m_TerrainTextures[type].m_Textures.push_back(texentry);
|
||||
|
||||
// .. and return it
|
||||
return texentry;
|
||||
}
|
||||
|
||||
void CTextureManager::DeleteTexture(CTextureEntry* entry)
|
||||
{
|
||||
// find entry in list
|
||||
std::vector<CTextureEntry*>& textures=m_TerrainTextures[entry->m_Type].m_Textures;
|
||||
|
||||
typedef std::vector<CTextureEntry*>::iterator Iter;
|
||||
Iter i=std::find(textures.begin(),textures.end(),entry);
|
||||
if (i!=textures.end()) {
|
||||
textures.erase(i);
|
||||
}
|
||||
delete entry;
|
||||
}
|
||||
|
||||
void CTextureManager::LoadTerrainTextures(int terraintype,const char* fileext)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
struct _finddata_t file;
|
||||
long handle;
|
||||
|
||||
// build pathname
|
||||
CStr pathname("mods\\official\\art\\textures\\terrain\\types\\");
|
||||
pathname+=m_TerrainTextures[terraintype].m_Name;
|
||||
pathname+="\\";
|
||||
|
||||
CStr findname(pathname);
|
||||
findname+="*.";
|
||||
findname+=fileext;
|
||||
|
||||
// Find first matching file in directory for this terrain type
|
||||
if ((handle=_findfirst((const char*) findname,&file))!=-1) {
|
||||
|
||||
AddTexture(file.name,terraintype);
|
||||
|
||||
// Find the rest of the matching files
|
||||
while( _findnext(handle,&file)==0) {
|
||||
AddTexture((const char*) file.name,terraintype);
|
||||
}
|
||||
|
||||
_findclose(handle);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CTextureManager::BuildTerrainTypes()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
struct _finddata_t file;
|
||||
long handle;
|
||||
|
||||
// Find first matching directory in terrain\textures
|
||||
if ((handle=_findfirst("mods\\official\\art\\textures\\terrain\\types\\*",&file))!=-1) {
|
||||
|
||||
if ((file.attrib & _A_SUBDIR) && file.name[0]!='.') {
|
||||
AddTextureType(file.name);
|
||||
}
|
||||
|
||||
// Find the rest of the matching files
|
||||
while( _findnext(handle,&file)==0) {
|
||||
if ((file.attrib & _A_SUBDIR) && file.name[0]!='.') {
|
||||
AddTextureType(file.name);
|
||||
}
|
||||
}
|
||||
|
||||
_findclose(handle);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CTextureManager::LoadTerrainTextures()
|
||||
{
|
||||
// find all the terrain types by directory name
|
||||
BuildTerrainTypes();
|
||||
|
||||
// now iterate through terrain types loading all textures of that type
|
||||
for (uint i=0;i<m_TerrainTextures.size();i++) {
|
||||
for (uint j=0;j<sizeof(SupportedTextureFormats)/sizeof(const char*);j++) {
|
||||
LoadTerrainTextures(i,SupportedTextureFormats[j]);
|
||||
}
|
||||
}
|
||||
}
|
51
source/graphics/TextureManager.h
Executable file
51
source/graphics/TextureManager.h
Executable file
@ -0,0 +1,51 @@
|
||||
#ifndef _TEXTUREMANAGER_H
|
||||
#define _TEXTUREMANAGER_H
|
||||
|
||||
#include <vector>
|
||||
#include "CStr.h"
|
||||
#include "Singleton.h"
|
||||
#include "TextureEntry.h"
|
||||
|
||||
// access to sole CTextureManager object
|
||||
#define g_TexMan CTextureManager ::GetSingleton()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CTextureManager : manager class for all terrain texture objects
|
||||
class CTextureManager : public Singleton<CTextureManager>
|
||||
{
|
||||
public:
|
||||
struct STextureType
|
||||
{
|
||||
// name of this texture type (derived from directory name)
|
||||
CStr m_Name;
|
||||
// index in parent array
|
||||
int m_Index;
|
||||
// list of textures of this type (found from the texture directory)
|
||||
std::vector<CTextureEntry*> m_Textures;
|
||||
};
|
||||
|
||||
public:
|
||||
// constructor, destructor
|
||||
CTextureManager();
|
||||
~CTextureManager();
|
||||
|
||||
void LoadTerrainTextures();
|
||||
|
||||
|
||||
void AddTextureType(const char* name);
|
||||
|
||||
CTextureEntry* FindTexture(const char* filename);
|
||||
CTextureEntry* FindTexture(Handle handle);
|
||||
CTextureEntry* AddTexture(const char* filename,int type);
|
||||
void DeleteTexture(CTextureEntry* entry);
|
||||
|
||||
std::vector<STextureType> m_TerrainTextures;
|
||||
|
||||
private:
|
||||
void LoadTerrainTextures(int terraintype,const char* fileext);
|
||||
void BuildTerrainTypes();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
36
source/graphics/Unit.h
Executable file
36
source/graphics/Unit.h
Executable file
@ -0,0 +1,36 @@
|
||||
#ifndef _UNIT_H
|
||||
#define _UNIT_H
|
||||
|
||||
#include <assert.h>
|
||||
#include "Model.h"
|
||||
|
||||
class CObjectEntry;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CUnit: simple "actor" definition - defines a sole object within the world
|
||||
class CUnit
|
||||
{
|
||||
public:
|
||||
// sole constructor - unit invalid without a model and object
|
||||
CUnit(CObjectEntry* object,CModel* model) : m_Object(object), m_Model(model) {
|
||||
assert(object && model);
|
||||
}
|
||||
// destructor
|
||||
~CUnit() {
|
||||
delete m_Model;
|
||||
}
|
||||
|
||||
|
||||
// get unit's template object
|
||||
CObjectEntry* GetObject() { return m_Object; }
|
||||
// get unit's model data
|
||||
CModel* GetModel() { return m_Model; }
|
||||
|
||||
private:
|
||||
// object from which unit was created
|
||||
CObjectEntry* m_Object;
|
||||
// object model representation
|
||||
CModel* m_Model;
|
||||
};
|
||||
|
||||
#endif
|
77
source/graphics/UnitManager.cpp
Executable file
77
source/graphics/UnitManager.cpp
Executable file
@ -0,0 +1,77 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: UnitManager.cpp
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "res/res.h"
|
||||
#include "Model.h"
|
||||
#include "UnitManager.h"
|
||||
#include <algorithm>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CUnitManager constructor
|
||||
CUnitManager::CUnitManager()
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CUnitManager destructor
|
||||
CUnitManager::~CUnitManager()
|
||||
{
|
||||
DeleteAll();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AddUnit: add given unit to world
|
||||
void CUnitManager::AddUnit(CUnit* unit)
|
||||
{
|
||||
m_Units.push_back(unit);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RemoveUnit: remove given unit from world, but don't delete it
|
||||
void CUnitManager::RemoveUnit(CUnit* unit)
|
||||
{
|
||||
// find entry in list
|
||||
typedef std::vector<CUnit*>::iterator Iter;
|
||||
Iter i=std::find(m_Units.begin(),m_Units.end(),unit);
|
||||
if (i!=m_Units.end()) {
|
||||
m_Units.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// DeleteAll: remove and delete all units
|
||||
void CUnitManager::DeleteAll()
|
||||
{
|
||||
for (uint i=0;i<m_Units.size();i++) {
|
||||
delete m_Units[i];
|
||||
}
|
||||
m_Units.clear();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PickUnit: iterate through units testing given ray against bounds of each
|
||||
// unit; return the closest unit, or null if everything missed
|
||||
CUnit* CUnitManager::PickUnit(const CVector3D& origin,const CVector3D& dir) const
|
||||
{
|
||||
// closest object found so far
|
||||
CUnit* hit=0;
|
||||
// distance to closest object found so far
|
||||
float dist=1.0e30f;
|
||||
for (uint i=0;i<m_Units.size();i++) {
|
||||
CUnit* unit=m_Units[i];
|
||||
float tmin,tmax;
|
||||
if (unit->GetModel()->GetBounds().RayIntersect(origin,dir,tmin,tmax)) {
|
||||
if (!hit || tmin<dist) {
|
||||
hit=unit;
|
||||
dist=tmin;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
49
source/graphics/UnitManager.h
Executable file
49
source/graphics/UnitManager.h
Executable file
@ -0,0 +1,49 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: UnitManager.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _UNITMANAGER_H
|
||||
#define _UNITMANAGER_H
|
||||
|
||||
#include <vector>
|
||||
#include "Unit.h"
|
||||
#include "Singleton.h"
|
||||
|
||||
class CVector3D;
|
||||
|
||||
// access to sole CUnitManager object
|
||||
#define g_UnitMan CUnitManager::GetSingleton()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CUnitManager: simple container class holding all units within the world
|
||||
class CUnitManager : public Singleton<CUnitManager>
|
||||
{
|
||||
public:
|
||||
// constructor, destructor
|
||||
CUnitManager();
|
||||
~CUnitManager();
|
||||
|
||||
// add given unit to world
|
||||
void AddUnit(CUnit* unit);
|
||||
// remove given unit from world, but don't delete it
|
||||
void RemoveUnit(CUnit* unit);
|
||||
// remove and delete all units
|
||||
void DeleteAll();
|
||||
|
||||
// return the units
|
||||
const std::vector<CUnit*>& GetUnits() const { return m_Units; }
|
||||
|
||||
// iterate through units testing given ray against bounds of each unit;
|
||||
// return the closest unit, or null if everything missed
|
||||
CUnit* PickUnit(const CVector3D& origin,const CVector3D& dir) const;
|
||||
|
||||
private:
|
||||
// list of all known units
|
||||
std::vector<CUnit*> m_Units;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user