diff --git a/source/graphics/Camera.cpp b/source/graphics/Camera.cpp new file mode 100755 index 0000000000..058dfa5761 --- /dev/null +++ b/source/graphics/Camera.cpp @@ -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]); + } +} diff --git a/source/graphics/Camera.h b/source/graphics/Camera.h new file mode 100755 index 0000000000..301834c1c8 --- /dev/null +++ b/source/graphics/Camera.h @@ -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 diff --git a/source/graphics/Color.h b/source/graphics/Color.h new file mode 100755 index 0000000000..05078c6b16 --- /dev/null +++ b/source/graphics/Color.h @@ -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 diff --git a/source/graphics/Frustum.cpp b/source/graphics/Frustum.cpp new file mode 100755 index 0000000000..81bb50e9c7 --- /dev/null +++ b/source/graphics/Frustum.cpp @@ -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 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 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; +} + diff --git a/source/graphics/Frustum.h b/source/graphics/Frustum.h new file mode 100755 index 0000000000..35e337ef27 --- /dev/null +++ b/source/graphics/Frustum.h @@ -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 diff --git a/source/graphics/HFTracer.cpp b/source/graphics/HFTracer.cpp new file mode 100755 index 0000000000..9cf00a9657 --- /dev/null +++ b/source/graphics/HFTracer.cpp @@ -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)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 && d0) { + 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=0 && cz=0); + + // fell off end of heightmap with no intersection; return a miss + return false; +} diff --git a/source/graphics/HFTracer.h b/source/graphics/HFTracer.h new file mode 100755 index 0000000000..97f0a02850 --- /dev/null +++ b/source/graphics/HFTracer.h @@ -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 \ No newline at end of file diff --git a/source/graphics/LightEnv.h b/source/graphics/LightEnv.h new file mode 100755 index 0000000000..3a17efea14 --- /dev/null +++ b/source/graphics/LightEnv.h @@ -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 diff --git a/source/graphics/MapIO.h b/source/graphics/MapIO.h new file mode 100755 index 0000000000..57d6e2e6cc --- /dev/null +++ b/source/graphics/MapIO.h @@ -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 + + diff --git a/source/graphics/MapReader.cpp b/source/graphics/MapReader.cpp new file mode 100755 index 0000000000..f8b7504026 --- /dev/null +++ b/source/graphics/MapReader.cpp @@ -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 +#include + + +// 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()=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;im_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;jm_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;im_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; + } +} diff --git a/source/graphics/MapReader.h b/source/graphics/MapReader.h new file mode 100755 index 0000000000..1b2302c7a7 --- /dev/null +++ b/source/graphics/MapReader.h @@ -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 m_Heightmap; + // list of terrain textures used by map + std::vector m_TerrainTextures; + // tile descriptions for each tile + std::vector m_Tiles; + // list of object types used by map + std::vector m_ObjectTypes; + // descriptions for each objects + std::vector m_Objects; + // lightenv stored in file + CLightEnv m_LightEnv; +}; + +#endif \ No newline at end of file diff --git a/source/graphics/MapWriter.cpp b/source/graphics/MapWriter.cpp new file mode 100755 index 0000000000..33e0aa9134 --- /dev/null +++ b/source/graphics/MapWriter.cpp @@ -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 +#include + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// 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& handles) +{ + for (uint i=0;i& objects) +{ + for (uint i=0;i& textures, + std::vector& tiles) +{ + // the list of all handles in use + std::vector 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;jm_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;im_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& objectTypes,std::vector& objects) +{ + // the list of all object entries in use + std::vector objectsInUse; + + // resize object array to required size + const std::vector& units=g_UnitMan.GetUnits(); + objects.resize(units.size()); + SObjectDesc* objptr=&objects[0]; + + // now iterate through all the units + for (u32 j=0;jGetObject(),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;im_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 objectTypes; + // descriptions of each object + std::vector 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 terrainTextures; + // descriptions of each tile + std::vector 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 +#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& textures,std::vector& tileIndices); + + // EnumObjects: build lists of object types used by map, and object descriptions for + // each object in the world + void EnumObjects(std::vector& objectTypes,std::vector& objects); +}; + +#endif \ No newline at end of file diff --git a/source/graphics/MiniPatch.cpp b/source/graphics/MiniPatch.cpp new file mode 100755 index 0000000000..333538599b --- /dev/null +++ b/source/graphics/MiniPatch.cpp @@ -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; +} + diff --git a/source/graphics/MiniPatch.h b/source/graphics/MiniPatch.h new file mode 100755 index 0000000000..36a3eb7fa3 --- /dev/null +++ b/source/graphics/MiniPatch.h @@ -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 diff --git a/source/graphics/Model.cpp b/source/graphics/Model.cpp new file mode 100755 index 0000000000..be49f75b8b --- /dev/null +++ b/source/graphics/Model.cpp @@ -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;iGetNumBones(); + 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;iGetNumVertices(); + SModelVertex* verts=m_pModelDef->GetVertices(); + + for (int i=0;iGetNumVertices(); + SModelVertex* verts=m_pModelDef->GetVertices(); + + // iterate through every frame of the animation + for (uint j=0;jGetNumFrames();j++) { + // extend bounds by vertex positions at the frame + for (int i=0;iGetFrameTime(); + 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;iUpdate(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;iGetNumBones();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;im_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::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;iAddProp(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;im_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); + } +} diff --git a/source/graphics/Model.h b/source/graphics/Model.h new file mode 100755 index 0000000000..70def4ade1 --- /dev/null +++ b/source/graphics/Model.h @@ -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& 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 m_Props; +}; + +#endif diff --git a/source/graphics/ModelDef.cpp b/source/graphics/ModelDef.cpp new file mode 100755 index 0000000000..75298d2585 --- /dev/null +++ b/source/graphics/ModelDef.cpp @@ -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;im_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;im_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;im_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"); +} + diff --git a/source/graphics/ModelDef.h b/source/graphics/ModelDef.h new file mode 100755 index 0000000000..738326f37a --- /dev/null +++ b/source/graphics/ModelDef.h @@ -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 diff --git a/source/graphics/ObjectEntry.cpp b/source/graphics/ObjectEntry.cpp new file mode 100755 index 0000000000..f55ffd99e9 --- /dev/null +++ b/source/graphics/ObjectEntry.cpp @@ -0,0 +1,321 @@ +#include "ObjectEntry.h" +#include "ObjectManager.h" +#include "Model.h" +#include "ModelDef.h" + +#include "UnitManager.h" + +// xerces XML stuff +#include +#include +#include +#include +#include + +// Gee's custom error handler +#include + +#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;iGetModelDef() : 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;pFindPropPoint((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& units=g_UnitMan.GetUnits(); + for (uint i=0;iGetModel(); + if (unitmodel->GetModelDef()==oldmodel) { + unitmodel->InitModel(m_Model->GetModelDef()); + + const std::vector& newprops=m_Model->GetProps(); + for (uint j=0;jAddProp(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; iitem(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; jgetLength(); ++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; jgetLength(); ++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,"\n\n"); + fprintf(fp,"\n\n"); + + // write the object itself + fprintf(fp,"\n"); + fprintf(fp,"\n"); + fprintf(fp,"\t%s\n",(const char*) m_Name); + fprintf(fp,"\t%s\n",(const char*) m_ModelName); + fprintf(fp,"\t%s\n",(const char*) m_TextureName); + if (m_Animations.size()>0) { + fprintf(fp,"\t\n"); + for (uint i=0;i \n",(const char*) m_Animations[i].m_AnimName,(const char*) m_Animations[i].m_FileName); + } + fprintf(fp,"\t\n"); + } + fprintf(fp,"\n"); + fclose(fp); + + return true; +} diff --git a/source/graphics/ObjectEntry.h b/source/graphics/ObjectEntry.h new file mode 100755 index 0000000000..289ffe7026 --- /dev/null +++ b/source/graphics/ObjectEntry.h @@ -0,0 +1,65 @@ +#ifndef _OBJECTENTRY_H +#define _OBJECTENTRY_H + +class CModel; +class CSkeletonAnim; + +#include +#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 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 m_Props; + // corresponding model + CModel* m_Model; + // type of object; index into object managers types array + int m_Type; +}; + + +#endif diff --git a/source/graphics/ObjectManager.cpp b/source/graphics/ObjectManager.cpp new file mode 100755 index 0000000000..6766fe142e --- /dev/null +++ b/source/graphics/ObjectManager.cpp @@ -0,0 +1,151 @@ +#include "ObjectManager.h" +#include +#include + + +CObjectManager::CObjectManager() : m_SelectedObject(0) +{ + m_ObjectTypes.reserve(32); +} + +CObjectManager::~CObjectManager() +{ + m_SelectedObject=0; + for (size_t i=0;i& objects=m_ObjectTypes[k].m_Objects; + + for (uint i=0;im_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& objects=m_ObjectTypes[entry->m_Type].m_Objects; + + typedef std::vector::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& objects=m_ObjectTypes[i].m_Objects; + + for (uint j=0;jm_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); + } +} diff --git a/source/graphics/ObjectManager.h b/source/graphics/ObjectManager.h new file mode 100755 index 0000000000..1022a6f04c --- /dev/null +++ b/source/graphics/ObjectManager.h @@ -0,0 +1,52 @@ +#ifndef _OBJECTMANAGER_H +#define _OBJECTMANAGER_H + +#include +#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 +{ +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 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 m_ObjectTypes; + +private: + void BuildObjectTypes(); + void LoadObjects(int type); + + CObjectEntry* m_SelectedObject; +}; + + +#endif \ No newline at end of file diff --git a/source/graphics/Particle.cpp b/source/graphics/Particle.cpp new file mode 100755 index 0000000000..df06b5c35b --- /dev/null +++ b/source/graphics/Particle.cpp @@ -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 + +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; +} diff --git a/source/graphics/Particle.h b/source/graphics/Particle.h new file mode 100755 index 0000000000..27ee205dd4 --- /dev/null +++ b/source/graphics/Particle.h @@ -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 \ No newline at end of file diff --git a/source/graphics/ParticleEmitter.cpp b/source/graphics/ParticleEmitter.cpp new file mode 100755 index 0000000000..a62e121b6e --- /dev/null +++ b/source/graphics/ParticleEmitter.cpp @@ -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 + +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::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::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; +} diff --git a/source/graphics/ParticleEmitter.h b/source/graphics/ParticleEmitter.h new file mode 100755 index 0000000000..a529d53e48 --- /dev/null +++ b/source/graphics/ParticleEmitter.h @@ -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 + + +//-------------------------------------------------------- +// 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 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 diff --git a/source/graphics/Patch.cpp b/source/graphics/Patch.cpp new file mode 100755 index 0000000000..90a752a750 --- /dev/null +++ b/source/graphics/Patch.cpp @@ -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;jCalcPosition(m_X*PATCH_SIZE+i,m_Z*PATCH_SIZE+j,pos); + m_Bounds+=pos; + } + } +} + diff --git a/source/graphics/Patch.h b/source/graphics/Patch.h new file mode 100755 index 0000000000..d6e735bfdf --- /dev/null +++ b/source/graphics/Patch.h @@ -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 diff --git a/source/graphics/RenderableObject.h b/source/graphics/RenderableObject.h new file mode 100755 index 0000000000..d2d8690914 --- /dev/null +++ b/source/graphics/RenderableObject.h @@ -0,0 +1,104 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Name: RenderableObject.h +// Author: Rich Cross +// Contact: rich@wildfiregames.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _RENDERABLEOBJECT_H +#define _RENDERABLEOBJECT_H + +#include +#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 diff --git a/source/graphics/SkeletonAnim.h b/source/graphics/SkeletonAnim.h new file mode 100755 index 0000000000..340aa5ab88 --- /dev/null +++ b/source/graphics/SkeletonAnim.h @@ -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 \ No newline at end of file diff --git a/source/graphics/SkeletonAnimDef.cpp b/source/graphics/SkeletonAnimDef.cpp new file mode 100755 index 0000000000..0ae86429b3 --- /dev/null +++ b/source/graphics/SkeletonAnimDef.cpp @@ -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;im_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"); +} + diff --git a/source/graphics/SkeletonAnimDef.h b/source/graphics/SkeletonAnimDef.h new file mode 100755 index 0000000000..4bb408e466 --- /dev/null +++ b/source/graphics/SkeletonAnimDef.h @@ -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 \ No newline at end of file diff --git a/source/graphics/SkeletonAnimManager.cpp b/source/graphics/SkeletonAnimManager.cpp new file mode 100755 index 0000000000..2eee2583f3 --- /dev/null +++ b/source/graphics/SkeletonAnimManager.cpp @@ -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 + +/////////////////////////////////////////////////////////////////////////////// +// CSkeletonAnimManager constructor +CSkeletonAnimManager::CSkeletonAnimManager() +{ +} + +/////////////////////////////////////////////////////////////////////////////// +// CSkeletonAnimManager destructor +CSkeletonAnimManager::~CSkeletonAnimManager() +{ + typedef std::map::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::iterator iter=m_Animations.find(fname); + if (iter!=m_Animations.end()) { + // yes - return it + return iter->second; + } + + // already failed to load? + std::set::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; + } +} diff --git a/source/graphics/SkeletonAnimManager.h b/source/graphics/SkeletonAnimManager.h new file mode 100755 index 0000000000..2c155028c9 --- /dev/null +++ b/source/graphics/SkeletonAnimManager.h @@ -0,0 +1,44 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Name: SkeletonAnimManager.h +// Author: Rich Cross +// Contact: rich@wildfiregames.com +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _SKELETONANIMMANAGER_H +#define _SKELETONANIMMANAGER_H + +#include +#include +#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 +{ +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 m_Animations; + // set of bad animation names - prevents multiple reloads of bad files + std::set m_BadAnimationFiles; +}; + +#endif \ No newline at end of file diff --git a/source/graphics/Sprite.cpp b/source/graphics/Sprite.cpp new file mode 100755 index 0000000000..d0b5efd61e --- /dev/null +++ b/source/graphics/Sprite.cpp @@ -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(); +} diff --git a/source/graphics/Sprite.h b/source/graphics/Sprite.h new file mode 100755 index 0000000000..cfdc44919d --- /dev/null +++ b/source/graphics/Sprite.h @@ -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 \ No newline at end of file diff --git a/source/graphics/Terrain.cpp b/source/graphics/Terrain.cpp new file mode 100755 index 0000000000..a73061162e --- /dev/null +++ b/source/graphics/Terrain.cpp @@ -0,0 +1,292 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Name: Terrain.cpp +// Author: Rich Cross +// Contact: rich@wildfiregames.com +// +/////////////////////////////////////////////////////////////////////////////// + +#include "res/tex.h" +#include "res/mem.h" + +#include +#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 (i0) { + CalcPosition(i,j-1,tmp); + up=tmp-basepos; + } + + if (j0.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;jm_MapSize) { + // entend the last height to the end of the row + for (u32 i=0;im_MapSize) { + // copy over heights of the last row to any remaining rows + src=newHeightmap+((m_MapSize-1)*newMapSize); + dst=src+newMapSize; + for (u32 i=0;im_MapSizePatches) { + // copy over the last tile from each column + for (u32 n=0;nm_MapSizePatches) { + // copy over the last tile from each column + CPatch* srcpatch=&newPatches[(m_MapSizePatches-1)*size]; + CPatch* dstpatch=srcpatch+size; + for (u32 p=0;pm_MiniPatches[15][k]; + CMiniPatch& dst=dstpatch->m_MiniPatches[m][k]; + dst.Tex1=src.Tex1; + dst.Tex1Priority=src.Tex1Priority; + } + } + srcpatch++; + dstpatch++; + } + } + } + + + // release all the original data + 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;jInitialize(this,i,j); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// SetHeightMap: set up a new heightmap from 16-bit source data; +// assumes heightmap matches current terrain size +void CTerrain::SetHeightMap(u16* heightmap) +{ + // keep a copy of the given heightmap + memcpy(m_Heightmap,heightmap,m_MapSize*m_MapSize*sizeof(u16)); + + // recalculate patch bounds, invalidate vertices + for (u32 j=0;jCalcBounds(); + patch->SetDirty(RENDERDATA_UPDATE_VERTICES); + } + } +} diff --git a/source/graphics/Terrain.h b/source/graphics/Terrain.h new file mode 100755 index 0000000000..65ceb72cf9 --- /dev/null +++ b/source/graphics/Terrain.h @@ -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 diff --git a/source/graphics/Texture.h b/source/graphics/Texture.h new file mode 100755 index 0000000000..e48a73e279 --- /dev/null +++ b/source/graphics/Texture.h @@ -0,0 +1,35 @@ +//----------------------------------------------------------- +// +// Name: Texture.h +// Last Update: 25/11/03 +// Author: Rich Cross +// Contact: rich@0ad.wildfiregames.com +// +// Description: Basic texture class +// +//----------------------------------------------------------- + +#ifndef _TEXTURE_H +#define _TEXTURE_H + +#include "res/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 diff --git a/source/graphics/TextureEntry.h b/source/graphics/TextureEntry.h new file mode 100755 index 0000000000..e827eecdc6 --- /dev/null +++ b/source/graphics/TextureEntry.h @@ -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 diff --git a/source/graphics/TextureManager.cpp b/source/graphics/TextureManager.cpp new file mode 100755 index 0000000000..4ab8f15d3a --- /dev/null +++ b/source/graphics/TextureManager.cpp @@ -0,0 +1,208 @@ + +#include "TextureManager.h" +#include "lib.h" +#include "ogl.h" +#include "res/tex.h" +#ifdef _WIN32 +#include +#endif +#include + +const char* SupportedTextureFormats[] = { "png", "dds", "tga", "bmp" }; + + + +CTextureManager::CTextureManager() +{ + m_TerrainTextures.reserve(32); +} + +CTextureManager::~CTextureManager() +{ + for (size_t i=0;im_Name,filename)==0) { + return ttype.m_Textures[i]; + } + } + } + + return 0; +} + +CTextureEntry* CTextureManager::FindTexture(Handle handle) +{ + for (uint k=0;km_Handle) { + return ttype.m_Textures[i]; + } + } + } + + return 0; +} + +CTextureEntry* CTextureManager::AddTexture(const char* filename,int type) +{ + assert((uint)typem_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& textures=m_TerrainTextures[entry->m_Type].m_Textures; + + typedef std::vector::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 +#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 +{ +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 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 m_TerrainTextures; + +private: + void LoadTerrainTextures(int terraintype,const char* fileext); + void BuildTerrainTypes(); + +}; + + +#endif diff --git a/source/graphics/Unit.h b/source/graphics/Unit.h new file mode 100755 index 0000000000..ef5af04f56 --- /dev/null +++ b/source/graphics/Unit.h @@ -0,0 +1,36 @@ +#ifndef _UNIT_H +#define _UNIT_H + +#include +#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 diff --git a/source/graphics/UnitManager.cpp b/source/graphics/UnitManager.cpp new file mode 100755 index 0000000000..3861aa17fa --- /dev/null +++ b/source/graphics/UnitManager.cpp @@ -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 + +/////////////////////////////////////////////////////////////////////////////// +// 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::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;iGetModel()->GetBounds().RayIntersect(origin,dir,tmin,tmax)) { + if (!hit || tmin +#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 +{ +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& 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 m_Units; +}; + +#endif \ No newline at end of file