1
0
forked from 0ad/0ad

*** empty log message ***

This was SVN commit r232.
This commit is contained in:
notpete 2004-05-15 17:57:41 +00:00
parent 02cd011c19
commit 99b785b75e
73 changed files with 8019 additions and 7072 deletions

View File

@ -14,6 +14,11 @@
#include "sysdep/ia32.h" #include "sysdep/ia32.h"
#endif #endif
#include "ps/Config.h" #include "ps/Config.h"
#include "MapReader.h"
#include "Terrain.h"
#include "Renderer.h"
#include "Model.h"
#include "UnitManager.h"
#ifndef NO_GUI #ifndef NO_GUI
#include "gui/GUI.h" #include "gui/GUI.h"
@ -26,11 +31,20 @@ bool keys[SDLK_LAST];
#include <cmath> #include <cmath>
// flag to disable extended GL extensions until fix found - specifically, crashes
// using VBOs on laptop Radeon cards
static bool g_NoGLVBO=false;
// mapfile to load or null for no map (and to use default terrain)
static const char* g_MapFile=0;
static Handle font; static Handle font;
static Handle tex; static Handle tex;
extern CCamera g_Camera;
extern void terr_init(); extern void terr_init();
extern void terr_update(); extern void terr_update(float time);
extern bool terr_handler(const SDL_Event& ev); extern bool terr_handler(const SDL_Event& ev);
@ -86,6 +100,17 @@ static void display_startup_error(const wchar_t* msg)
exit(1); exit(1);
} }
// error before GUI is initialized: display message, and quit
// TODO: localization
static void display_startup_error(const char* msg)
{
const char* caption = "0ad startup problem";
write_sys_info();
display_msg(caption, msg);
exit(1);
}
static int set_vmode(int w, int h, int bpp) static int set_vmode(int w, int h, int bpp)
{ {
@ -143,14 +168,80 @@ static bool handler(const SDL_Event& ev)
} }
//////////////////////////////////////////////////////////////////////////////////////////////////
// RenderTerrain: iterate through all terrain patches and submit all patches in viewing frustum to
// the renderer
void RenderTerrain()
{
CFrustum frustum=g_Camera.GetFustum();
u32 patchesPerSide=g_Terrain.GetPatchesPerSide();
for (uint j=0; j<patchesPerSide; j++) {
for (uint i=0; i<patchesPerSide; i++) {
CPatch* patch=g_Terrain.GetPatch(i,j);
if (frustum.IsBoxVisible (CVector3D(0,0,0),patch->GetBounds())) {
g_Renderer.Submit(patch);
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// RenderModels: iterate through model list and submit all models in viewing frustum to the
// Renderer
void RenderModels()
{
CFrustum frustum=g_Camera.GetFustum();
const std::vector<CUnit*>& units=g_UnitMan.GetUnits();
uint i;
for (i=0;i<units.size();++i) {
if (frustum.IsBoxVisible(CVector3D(0,0,0),units[i]->m_Model->GetBounds())) {
g_Renderer.Submit(units[i]->m_Model);
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////
// RenderNoCull: render absolutely everything to a blank frame to force renderer
// to load required assets
void RenderNoCull()
{
g_Renderer.BeginFrame();
g_Renderer.SetCamera(g_Camera);
uint i,j;
const std::vector<CUnit*>& units=g_UnitMan.GetUnits();
for (i=0;i<units.size();++i) {
g_Renderer.Submit(units[i]->m_Model);
}
u32 patchesPerSide=g_Terrain.GetPatchesPerSide();
for (j=0; j<patchesPerSide; j++) {
for (i=0; i<patchesPerSide; i++) {
CPatch* patch=g_Terrain.GetPatch(i,j);
g_Renderer.Submit(patch);
}
}
g_Renderer.FlushFrame();
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
g_Renderer.EndFrame();
}
static void render() static void render()
{ {
// TODO: not needed with 100% draw coverage // start new frame
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); g_Renderer.BeginFrame();
g_Renderer.SetCamera(g_Camera);
terr_update(); // switch on wireframe for terrain if we want it
g_Renderer.SetTerrainRenderMode(SOLID);
glColor3f(1.0f, 1.0f, 1.0f); RenderTerrain();
RenderModels();
g_Renderer.FlushFrame();
glColor3f(1.0f, 1.0f, 1.0f);
// overlay mode // overlay mode
glPushAttrib(GL_ENABLE_BIT); glPushAttrib(GL_ENABLE_BIT);
@ -213,6 +304,8 @@ const float x = 600.0f, y = 512.0f;
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glPopMatrix(); glPopMatrix();
glPopAttrib(); glPopAttrib();
g_Renderer.EndFrame();
} }
@ -220,10 +313,42 @@ static void do_tick()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////
// UpdateWorld: update time dependent data in the world to account for changes over
// the given time (in s)
void UpdateWorld(float time)
{
const std::vector<CUnit*>& units=g_UnitMan.GetUnits();
for (uint i=0;i<units.size();++i) {
units[i]->m_Model->Update(time);
}
}
void ParseArgs(int argc, char* argv[])
{
for (int i=1;i<argc;i++) {
if (argv[i][0]=='-') {
switch (argv[i][1]) {
case 'm':
if (argv[i][2]=='=') {
g_MapFile=argv[i]+3;
}
break;
case 'n':
if (strncmp(argv[i]+1,"novbo",5)==0) {
g_NoGLVBO=true;
}
break;
}
}
}
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
ParseArgs(argc,argv);
chdir("\\games\\bf\\ScreenShots"); chdir("\\games\\bf\\ScreenShots");
int a,b; int a,b;
@ -321,12 +446,8 @@ int c = b-a;
write_sys_info(); write_sys_info();
if(!oglExtAvail("GL_ARB_multitexture") || !oglExtAvail("GL_ARB_texture_env_combine")) if(!oglExtAvail("GL_ARB_multitexture") || !oglExtAvail("GL_ARB_texture_env_combine"))
display_startup_error(L"required ARB_multitexture or ARB_texture_env_combine extension not available"); display_startup_error(L"required ARB_multitexture or ARB_texture_env_combine extension not available");
glEnable (GL_CULL_FACE);
glEnable (GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
new CConfig; new CConfig;
@ -346,19 +467,36 @@ glEnable (GL_DEPTH_TEST);
// tex_upload(tex); // tex_upload(tex);
font = font_load("verdana.fnt"); font = font_load("verdana.fnt");
// set renderer options from command line options - NOVBO must be set before opening the renderer
g_Renderer.SetOption(CRenderer::OPT_NOVBO,g_NoGLVBO);
extern int dir_add_watch(const char* const dir, bool watch_subdirs); // terr_init actually opens the renderer and loads a bunch of resources as well as setting up
dir_add_watch("mods\\official", false); // the terrain
terr_init();
terr_init();
// load a map if we were given one
if (g_MapFile) {
CStr mapfilename("mods/official/maps/scenarios/");
mapfilename+=g_MapFile;
try {
CMapReader reader;
reader.LoadMap(mapfilename);
} catch (...) {
char errmsg[256];
sprintf(errmsg, "Failed to load map %s\n", mapfilename.c_str());
display_startup_error(errmsg);
}
}
#ifndef NO_GUI #ifndef NO_GUI
in_add_handler(gui_handler); in_add_handler(gui_handler);
#endif #endif
in_add_handler(handler); in_add_handler(handler);
in_add_handler(terr_handler); in_add_handler(terr_handler);
// render everything to a blank frame to force renderer to load everything
RenderNoCull();
// fixed timestep main loop // fixed timestep main loop
const double TICK_TIME = 30e-3; // [s] const double TICK_TIME = 30e-3; // [s]
@ -370,6 +508,7 @@ in_add_handler(terr_handler);
g_Config.Update(); g_Config.Update();
// TODO: limiter in case simulation can't keep up? // TODO: limiter in case simulation can't keep up?
#if 0
double time1 = get_time(); double time1 = get_time();
while((time1-time0) > TICK_TIME) while((time1-time0) > TICK_TIME)
{ {
@ -378,15 +517,26 @@ in_add_handler(terr_handler);
do_tick(); do_tick();
time0 += TICK_TIME; time0 += TICK_TIME;
} }
UpdateWorld(float(time1-time0));
terr_update(float(time1-time0));
render(); render();
SDL_GL_SwapBuffers(); SDL_GL_SwapBuffers();
calc_fps(); calc_fps();
extern int allow_reload(); #else
allow_reload();
double time1 = get_time();
in_get_events();
UpdateWorld(float(time1-time0));
terr_update(float(time1-time0));
render();
SDL_GL_SwapBuffers();
calc_fps();
time0=time1;
#endif
} }
#ifndef NO_GUI #ifndef NO_GUI

23
source/ps/Overlay.cpp Executable file
View File

@ -0,0 +1,23 @@
/*
COverlay
by Rich Cross
rich@0ad.wildfiregames.com
*/
#include "Overlay.h"
COverlay::COverlay()
: m_Rect(CRect(0,0,0,0)), m_Z(0), m_Color(CColor(0,0,0,0)), m_Texture(""), m_HasBorder(false), m_BorderColor(CColor(0,0,0,0))
{
}
COverlay::COverlay(const CRect& rect,int z,const CColor& color,const char* texturename,
bool hasBorder,const CColor& bordercolor)
: m_Rect(rect), m_Z(z), m_Color(color), m_Texture(texturename), m_HasBorder(hasBorder), m_BorderColor(bordercolor)
{
}
COverlay::~COverlay()
{
}

142
source/ps/Overlay.h Executable file
View File

@ -0,0 +1,142 @@
/*
COverlay
by Rich Cross, rich@0ad.wildfiregames.com
--Overview--
Class representing 2D screen overlays; includes functionality for overlay
position, color, texture and borders.
*/
#ifndef COVERLAY_H
#define COVERLAY_H
struct CColor
{
CColor() {}
CColor(float cr,float cg,float cb,float ca) : r(cr), g(cg), b(cb), a(ca) {}
float r, g, b, a;
};
// yuck - MFC already defines a CRect class...
#define CRect PS_CRect
struct CRect
{
CRect() {}
CRect(int _l, int _t, int _r, int _b) :
left(_l),
top(_t),
right(_r),
bottom(_b) {}
int bottom, top, left, right;
bool operator ==(const CRect &rect) const
{
return (bottom==rect.bottom) &&
(top==rect.top) &&
(left==rect.left) &&
(right==rect.right);
}
bool operator !=(const CRect &rect) const
{
return !(*this==rect);
}
};
//--------------------------------------------------------
// Includes / Compiler directives
//--------------------------------------------------------
#include "terrain/Texture.h"
//--------------------------------------------------------
// Macros
//--------------------------------------------------------
//--------------------------------------------------------
// Types
//--------------------------------------------------------
//--------------------------------------------------------
// Error declarations
//--------------------------------------------------------
//--------------------------------------------------------
// Declarations
//--------------------------------------------------------
/**
* @author Rich Cross
*
* Overlay class definition.
*/
class COverlay
{
public:
/**
* Default constructor; creates an overlay that won't actually be renderable
*/
COverlay();
/**
* Constructor with setup for more common parameters
*/
COverlay(const CRect& rect,int z,const CColor& color,const char* texturename="",bool hasBorder=false,
const CColor& bordercolor=CColor(0,0,0,0));
/**
* Destructor
*/
~COverlay();
/**
* Get coordinates
*/
const CRect& GetRect() const { return m_Rect; }
/**
* Get depth
*/
int GetZ() const { return m_Z; }
/**
* Get texture (not const as Renderer need to modify texture to store handle)
*/
CTexture& GetTexture() { return m_Texture; }
/**
* Get color
*/
const CColor& GetColor() const { return m_Color; }
/**
* Get border flag
*/
bool HasBorder() const { return m_HasBorder; }
/**
* Get border color
*/
const CColor& GetBorderColor() const { return m_BorderColor; }
private:
/// screen space coordinates of overlay
CRect m_Rect;
/// depth of overlay, for correctly overlapping overlays; higher z implies in-front-of behaviour
int m_Z;
/// texture to use in rendering overlay; can be a null texture
CTexture m_Texture;
/// overlay color
CColor m_Color;
// flag indicating whether to render overlay using a border
bool m_HasBorder;
/// border color
CColor m_BorderColor;
};
#endif

32
source/ps/OverlayText.cpp Executable file
View File

@ -0,0 +1,32 @@
/*
COverlayText
by Rich Cross
rich@0ad.wildfiregames.com
*/
#include "OverlayText.h"
#include "NPFont.h"
#include "NPFontManager.h"
COverlayText::COverlayText()
: m_X(0), m_Y(0), m_Z(0), m_Color(CColor(0,0,0,0)), m_Font(0), m_String("")
{
}
COverlayText::COverlayText(float x,float y,int z,const char* fontname,const char* string,const CColor& color)
: m_X(x), m_Y(y), m_Z(z), m_String(string), m_Color(color)
{
m_Font=NPFontManager::instance().add(fontname);
}
COverlayText::~COverlayText()
{
}
bool COverlayText::GetOutputStringSize(int& sx,int& sy)
{
if (!m_Font) return false;
m_Font->GetOutputStringSize((const char*) m_String,sx,sy);
return true;
}

108
source/ps/OverlayText.h Executable file
View File

@ -0,0 +1,108 @@
/*
COverlayText
by Rich Cross, rich@0ad.wildfiregames.com
--Overview--
Class representing 2D screen text overlay
*/
#ifndef COVERLAYTEXT_H
#define COVERLAYTEXT_H
//--------------------------------------------------------
// Includes / Compiler directives
//--------------------------------------------------------
#include "terrain/Texture.h"
#include "Overlay.h" // just for CColor at the mo
//--------------------------------------------------------
// Macros
//--------------------------------------------------------
//--------------------------------------------------------
// Types
//--------------------------------------------------------
//--------------------------------------------------------
// Error declarations
//--------------------------------------------------------
//--------------------------------------------------------
// Declarations
//--------------------------------------------------------
class NPFont;
/**
* @author Rich Cross
*
* OverlayText class definition.
*/
class COverlayText
{
public:
/**
* Default constructor; creates an overlay text object that won't actually be renderable
*/
COverlayText();
/**
* Constructor with setup for more common parameters
*/
COverlayText(float x,float y,int z,const char* fontname,const char* string,const CColor& color);
/**
* Destructor
*/
~COverlayText();
/**
* Get position
*/
void GetPosition(float& x,float& y) {
x=m_X;
y=m_Y;
}
/**
* Get depth
*/
int GetZ() const { return m_Z; }
/**
* Get font (not const as Renderer need to modify texture to store handle)
*/
NPFont* GetFont() { return m_Font; }
/**
* Get string to render
*/
const CStr& GetString() const { return m_String; }
/**
* Get color
*/
const CColor& GetColor() const { return m_Color; }
/**
* Get size of this string when rendered; return false if font is invalid and string size cannot
* actually by determined, or true on success
*/
bool GetOutputStringSize(int& sx,int& sy);
private:
/// coordinates to start rendering string
float m_X,m_Y;
/// depth of overlay text, for correctly overlapping overlays; higher z implies in-front-of behaviour
int m_Z;
/// text color
CColor m_Color;
/// pointer to the font to use in rendering out text; not owned by the overlay, never attempt to delete
NPFont* m_Font;
/// actual text string
CStr m_String;
};
#endif

View File

@ -1,308 +0,0 @@
#ifndef _AABBTREE_H
#define _AABBTREE_H
#include <vector>
#include <algorithm>
#include "Bound.h"
template <class T>
class CAABBTree
{
private:
struct Leaf;
struct Branch;
struct InsertionData;
struct Node {
Node() : m_Parent(0) {}
virtual ~Node() {}
virtual bool RayIntersect(CVector3D& origin,CVector3D& dir,float& dist,T* selection) = 0;
virtual void FindInsertionPoint(Leaf* _leaf,InsertionData& _inserter) = 0;
virtual void AddLeaf(Leaf* _leaf) = 0;
virtual void AddLeafAsChild(Leaf* _leaf) {};
void AddLeafAsSibling(Leaf* _leaf);
CBound m_Bounds;
Branch* m_Parent;
};
struct Leaf : public Node {
T m_Element;
void AddLeaf(Leaf* _leaf);
bool RayIntersect(CVector3D& origin,CVector3D& dir,float& dist,T* selection);
void FindInsertionPoint(Leaf* _leaf,InsertionData& _inserter);
};
struct Branch : public Node {
~Branch() {
for (int i=0;i<m_Children.size();i++) {
delete m_Children[i];
}
}
void AddChild(Node* _node);
void RemoveChild(Node* _node);
void AddLeaf(Leaf* _leaf);
void AddLeafAsChild(Leaf* leaf);
bool RayIntersect(CVector3D& origin,CVector3D& dir,float& dist,T* selection);
void FindInsertionPoint(Leaf* _leaf,InsertionData& _inserter);
std::vector<Node*> m_Children;
};
struct InsertionData
{
enum Method { ADDINVALID, ADDASSIBLING, ADDASCHILD };
InsertionData() : cost((float) 1.0e38), inheritedCost(0), method(ADDINVALID), insertionPt(0) {}
void setInsertion(Node* pt,float c,enum Method m) {
insertionPt=pt;
cost=c;
method=m;
}
float cost;
float inheritedCost;
enum Method method;
Node* insertionPt;
};
// root of AABBTree
Node* m_Root;
public:
CAABBTree();
~CAABBTree();
void AddElement(const T& element);
bool RayIntersect(CVector3D& origin,CVector3D& dir,float& dist,T* selection);
};
template <class T>
CAABBTree<T>::CAABBTree() : m_Root(0)
{
}
template <class T>
CAABBTree<T>::~CAABBTree()
{
delete m_Root;
}
template <class T>
void CAABBTree<T>::AddElement(const T& element)
{
Leaf* leaf=new Leaf;
leaf->m_Element=element;
leaf->m_Element->GetBounds(leaf->m_Bounds);
if (m_Root) {
m_Root->AddLeaf(leaf);
// set root to topmost node
while (m_Root->m_Parent) {
m_Root=m_Root->m_Parent;
}
} else {
m_Root=leaf;
}
}
template <class T>
bool CAABBTree<T>::RayIntersect(CVector3D& origin,CVector3D& dir,float& dist,T* selection)
{
if (m_Root) {
return m_Root->RayIntersect(origin,dir,dist,selection);
} else {
return false;
}
}
template <class T>
void CAABBTree<T>::Node::AddLeafAsSibling(CAABBTree<T>::Leaf* leaf)
{
CBound& leafBound=leaf->m_Bounds;
if (m_Parent) {
// recursively extend the bounding volumes of the parent nodes to allow the leaf
// to fit within them
Branch* p=m_Parent;
while (p) {
p->m_Bounds+=leafBound;
p=p->m_Parent;
}
}
// create a new parent, whose children are the current node (this) and
// the leaf being added
Branch* newParent=new Branch;
newParent->m_Parent=m_Parent;
newParent->m_Bounds=m_Bounds;
newParent->m_Bounds+=leafBound;
if (m_Parent) {
// remove the current node from it's original parent ..
m_Parent->RemoveChild(this);
// .. and add new parent as a child of the original parent
m_Parent->AddChild(newParent);
}
// create new parent/child relationships
newParent->AddChild(leaf);
leaf->m_Parent=newParent;
newParent->AddChild(this);
this->m_Parent=newParent;
}
template <class T>
bool CAABBTree<T>::Branch::RayIntersect(CVector3D& origin,CVector3D& dir,float& dist,T* selection)
{
// assume nothing hit
bool result=false;
// do bounds check first
float tmin,tmax;
if (m_Bounds.RayIntersect(origin,dir,tmin,tmax) && tmin<=dist) {
// test all children of this branch
for (int i=0;i<m_Children.size();i++) {
bool hit=m_Children[i]->RayIntersect(origin,dir,dist,selection);
if (hit) {
// hit a triangle; can quit out ..
result=true;
}
}
}
return result;
}
template <class T>
bool CAABBTree<T>::Leaf::RayIntersect(CVector3D& origin,CVector3D& dir,float& dist,T* selection)
{
if (m_Element->RayIntersect(origin,dir,dist)) {
*selection=m_Element;
return true;
} else {
return false;
}
}
//**********************************************************************************************
// FindInsertionPoint : check if the estimated cost of adding given leaf to this leaf
// is less than the current best cost; if so, update insertion data accordingly
//**********************************************************************************************
template <class T>
void CAABBTree<T>::Leaf::FindInsertionPoint(CAABBTree<T>::Leaf* leaf,CAABBTree<T>::InsertionData& inserter)
{
CBound thisbound=m_Bounds;
thisbound+=leaf->m_Bounds;
float m1=2*thisbound.GetVolume();
if (m1<inserter.cost)
inserter.setInsertion(this,m1,InsertionData::ADDASSIBLING);
}
template <class T>
void CAABBTree<T>::Branch::AddLeaf(CAABBTree<T>::Leaf* leaf)
{
// first find the node to attach the leaf to, and the method with which to attach it
InsertionData inserter;
FindInsertionPoint(leaf,inserter);
// now add the leaf to the descendent found above, using the required method
if (inserter.method==InsertionData::ADDASCHILD) {
inserter.insertionPt->AddLeafAsChild(leaf);
} else {
inserter.insertionPt->AddLeafAsSibling(leaf);
}
}
template <class T>
void CAABBTree<T>::Leaf::AddLeaf(CAABBTree<T>::Leaf* leaf)
{
AddLeafAsSibling(leaf);
}
template <class T>
void CAABBTree<T>::Branch::AddChild(CAABBTree<T>::Node* node)
{
m_Children.push_back(node);
}
template <class T>
void CAABBTree<T>::Branch::RemoveChild(CAABBTree<T>::Node* node)
{
m_Children.erase(std::find(m_Children.begin(),m_Children.end(),node));
}
template <class T>
void CAABBTree<T>::Branch::FindInsertionPoint(CAABBTree<T>::Leaf* leaf,CAABBTree<T>::InsertionData& inserter)
{
// first count the children
int childCt=m_Children.size();
// get volume of union between this node and leaf
CBound& leafBounds=leaf->m_Bounds;
CBound uBounds=m_Bounds;
uBounds+=leafBounds;
float unionVol=uBounds.GetVolume();
// get volume of this node
float thisVol=m_Bounds.GetVolume();
// estimate cost of adding the leaf as a sibling of this node
float m1=2*unionVol;
if (m1<inserter.cost) {
// best cost so far; use this insertion point
inserter.setInsertion(this,m1,InsertionData::ADDASSIBLING);
}
// estimate cost of adding the leaf as a child of this node
float m2=(unionVol-thisVol)*childCt+thisVol;
if (m2<inserter.cost) {
// best cost so far; use this insertion point
inserter.setInsertion(this,m2,InsertionData::ADDASCHILD);
}
// calculate cost children inherit from parent
float inheritanceCost=inserter.inheritedCost+(unionVol-thisVol)*childCt;
if (inheritanceCost>inserter.cost) {
// child inheritance cost is greater than lowest cost insertion found so
// far, so no improvement can be found by searching children; terminate now
return;
}
// now traverse through children to try and find a better insertion point
for (int i=0;i<m_Children.size();i++) {
inserter.inheritedCost=inheritanceCost;
m_Children[i]->FindInsertionPoint(leaf,inserter);
}
}
template <class T>
void CAABBTree<T>::Branch::AddLeafAsChild(CAABBTree<T>::Leaf* leaf)
{
Node* p=this;
// stretch bounds of all ancestors to include the bounds of the leaf
while (p) {
p->m_Bounds+=leaf->m_Bounds;
p=p->m_Parent;
}
// add leaf as child
AddChild(leaf);
leaf->m_Parent=this;
}
#endif

View File

@ -1,272 +1,303 @@
#include "AlphaMapCalculator.h" ///////////////////////////////////////////////////////////////////////////////
#include <string.h> //
#include <stdio.h> // Name: AlphaMapCalculator.cpp
// Author: Rich Cross
namespace CAlphaMapCalculator { // Contact: rich@wildfiregames.com
//
struct Blend4 { ///////////////////////////////////////////////////////////////////////////////
Blend4(BlendShape4 shape,int alphamap) : m_Shape(shape), m_AlphaMap(alphamap) {}
#include "AlphaMapCalculator.h"
BlendShape4 m_Shape; #include <string.h>
int m_AlphaMap; #include <stdio.h>
};
///////////////////////////////////////////////////////////////////////////////
struct Blend8 { // CAlphaMapCalculator: functionality for calculating which alpha blend map
Blend8(BlendShape8 shape,int alphamap) : m_Shape(shape), m_AlphaMap(alphamap) {} // fits a given shape
namespace CAlphaMapCalculator {
BlendShape8 m_Shape;
int m_AlphaMap; ///////////////////////////////////////////////////////////////////////////////
}; // Blend4: structure mapping a blend shape for N,E,S,W to a particular map
struct Blend4 {
Blend4 Blends1Neighbour[] = Blend4(BlendShape4 shape,int alphamap) : m_Shape(shape), m_AlphaMap(alphamap) {}
{
Blend4(BlendShape4(1,0,0,0), 12) // u shape blend BlendShape4 m_Shape;
}; int m_AlphaMap;
};
Blend4 Blends2Neighbour[] = ///////////////////////////////////////////////////////////////////////////////
{ // Blend8: structure mapping a blend shape for N,NE,E,SE,S,SW,W,NW to a
Blend4(BlendShape4(0,1,1,0), 7), // l shaped corner blend // particular map
Blend4(BlendShape4(1,0,1,0), 10) // two edges blend struct Blend8 {
}; Blend8(BlendShape8 shape,int alphamap) : m_Shape(shape), m_AlphaMap(alphamap) {}
Blend8 Blends2Neighbour8[] = BlendShape8 m_Shape;
{ int m_AlphaMap;
Blend8(BlendShape8(1,1,0,0,0,0,0,0), 12), // u shaped blend };
Blend8(BlendShape8(1,0,0,0,0,1,0,0), 12), // u shaped blend
Blend8(BlendShape8(0,1,0,1,0,0,0,0), 0) , ///////////////////////////////////////////////////////////////////////////////
Blend8(BlendShape8(0,1,0,0,0,1,0,0), 0) // Data tables for mapping between shapes and blend maps
}; ///////////////////////////////////////////////////////////////////////////////
Blend4 Blends3Neighbour[] = const Blend4 Blends1Neighbour[] =
{ {
Blend4(BlendShape4(1,1,1,0), 4) // l shaped corner blend Blend4(BlendShape4(1,0,0,0), 12)
}; };
Blend8 Blends3Neighbour8[] =
{ const Blend4 Blends2Neighbour[] =
Blend8(BlendShape8(1,1,0,0,1,0,0,0), 10), {
Blend8(BlendShape8(1,1,0,0,0,0,0,1), 12), Blend4(BlendShape4(0,1,1,0), 7),
Blend8(BlendShape8(1,1,1,0,0,0,0,0), 1), Blend4(BlendShape4(1,0,1,0), 10)
Blend8(BlendShape8(0,1,1,0,1,0,0,0), 7), };
Blend8(BlendShape8(0,0,1,0,1,0,1,0), 4),
Blend8(BlendShape8(1,1,0,0,0,1,0,0), 12), const Blend8 Blends2Neighbour8[] =
Blend8(BlendShape8(1,1,0,1,0,0,0,0), 12), {
Blend8(BlendShape8(0,0,1,0,1,0,0,1), 7), Blend8(BlendShape8(1,1,0,0,0,0,0,0), 12),
Blend8(BlendShape8(1,0,0,1,0,1,0,0), 12), Blend8(BlendShape8(1,0,0,0,0,1,0,0), 12),
Blend8(BlendShape8(0,1,0,1,0,1,0,0), 0) Blend8(BlendShape8(0,1,0,1,0,0,0,0), 0) ,
}; Blend8(BlendShape8(0,1,0,0,0,1,0,0), 0)
};
Blend8 Blends4Neighbour8[] =
{ const Blend4 Blends3Neighbour[] =
Blend8(BlendShape8(1,1,0,0,1,0,0,1), 10), {
Blend8(BlendShape8(1,1,0,1,1,0,0,0), 10), Blend4(BlendShape4(1,1,1,0), 4)
Blend8(BlendShape8(1,1,0,0,1,1,0,0), 10), };
Blend8(BlendShape8(1,1,0,1,0,0,0,1), 12),
Blend8(BlendShape8(0,1,1,0,1,1,0,0), 7), const Blend8 Blends3Neighbour8[] =
Blend8(BlendShape8(1,1,1,1,0,0,0,0), 1), {
Blend8(BlendShape8(1,1,1,0,1,0,0,0), 3), Blend8(BlendShape8(1,1,0,0,1,0,0,0), 10),
Blend8(BlendShape8(0,0,1,0,1,1,0,1), 7), Blend8(BlendShape8(1,1,0,0,0,0,0,1), 12),
Blend8(BlendShape8(1,0,1,0,1,1,0,0), 4), Blend8(BlendShape8(1,1,1,0,0,0,0,0), 1),
Blend8(BlendShape8(1,1,1,0,0,1,0,0), 1), Blend8(BlendShape8(0,1,1,0,1,0,0,0), 7),
Blend8(BlendShape8(1,1,0,1,0,1,0,0), 12), Blend8(BlendShape8(0,0,1,0,1,0,1,0), 4),
Blend8(BlendShape8(0,1,0,1,0,1,0,1), 0) Blend8(BlendShape8(1,1,0,0,0,1,0,0), 12),
}; Blend8(BlendShape8(1,1,0,1,0,0,0,0), 12),
Blend8(BlendShape8(0,0,1,0,1,0,0,1), 7),
Blend8 Blends5Neighbour8[] = Blend8(BlendShape8(1,0,0,1,0,1,0,0), 12),
{ Blend8(BlendShape8(0,1,0,1,0,1,0,0), 0)
Blend8(BlendShape8(1,1,1,1,1,0,0,0), 2), };
Blend8(BlendShape8(1,1,1,1,0,0,0,1), 1),
Blend8(BlendShape8(1,1,1,0,1,0,0,1), 3), const Blend8 Blends4Neighbour8[] =
Blend8(BlendShape8(1,1,1,0,1,0,1,0), 11), {
Blend8(BlendShape8(1,1,1,0,0,1,0,1), 1), Blend8(BlendShape8(1,1,0,0,1,0,0,1), 10),
Blend8(BlendShape8(1,1,0,1,1,1,0,0), 10), Blend8(BlendShape8(1,1,0,1,1,0,0,0), 10),
Blend8(BlendShape8(1,1,1,0,1,1,0,0), 3), Blend8(BlendShape8(1,1,0,0,1,1,0,0), 10),
Blend8(BlendShape8(1,0,1,0,1,1,0,1), 4), Blend8(BlendShape8(1,1,0,1,0,0,0,1), 12),
Blend8(BlendShape8(1,1,0,1,0,1,0,1), 12), Blend8(BlendShape8(0,1,1,0,1,1,0,0), 7),
Blend8(BlendShape8(0,1,1,0,1,1,0,1), 7) Blend8(BlendShape8(1,1,1,1,0,0,0,0), 1),
}; Blend8(BlendShape8(1,1,1,0,1,0,0,0), 3),
Blend8(BlendShape8(0,0,1,0,1,1,0,1), 7),
Blend8 Blends6Neighbour8[] = Blend8(BlendShape8(1,0,1,0,1,1,0,0), 4),
{ Blend8(BlendShape8(1,1,1,0,0,1,0,0), 1),
Blend8(BlendShape8(1,1,1,1,1,1,0,0), 2), Blend8(BlendShape8(1,1,0,1,0,1,0,0), 12),
Blend8(BlendShape8(1,1,1,1,1,0,1,0), 8), Blend8(BlendShape8(0,1,0,1,0,1,0,1), 0)
Blend8(BlendShape8(1,1,1,1,0,1,0,1), 1), };
Blend8(BlendShape8(1,1,1,0,1,1,1,0), 6),
Blend8(BlendShape8(1,1,1,0,1,1,0,1), 3), const Blend8 Blends5Neighbour8[] =
Blend8(BlendShape8(1,1,0,1,1,1,0,1), 10) {
}; Blend8(BlendShape8(1,1,1,1,1,0,0,0), 2),
Blend8(BlendShape8(1,1,1,1,0,0,0,1), 1),
Blend8 Blends7Neighbour8[] = Blend8(BlendShape8(1,1,1,0,1,0,0,1), 3),
{ Blend8(BlendShape8(1,1,1,0,1,0,1,0), 11),
Blend8(BlendShape8(1,1,1,1,1,1,0,1), 2), Blend8(BlendShape8(1,1,1,0,0,1,0,1), 1),
Blend8(BlendShape8(1,1,1,1,1,1,1,0), 9) Blend8(BlendShape8(1,1,0,1,1,1,0,0), 10),
}; Blend8(BlendShape8(1,1,1,0,1,1,0,0), 3),
Blend8(BlendShape8(1,0,1,0,1,1,0,1), 4),
Blend8(BlendShape8(1,1,0,1,0,1,0,1), 12),
Blend8(BlendShape8(0,1,1,0,1,1,0,1), 7)
template<class T> };
bool MatchBlendShapeRotated(const T& templateshape,const T& shape,unsigned int& flipflags)
{ const Blend8 Blends6Neighbour8[] =
// try to match shapes by testing the template shape in normal, and flipped u and v configurations {
// test unrotated shape Blend8(BlendShape8(1,1,1,1,1,1,0,0), 2),
if (shape==templateshape) { Blend8(BlendShape8(1,1,1,1,1,0,1,0), 8),
return true; Blend8(BlendShape8(1,1,1,1,0,1,0,1), 1),
} Blend8(BlendShape8(1,1,1,0,1,1,1,0), 6),
Blend8(BlendShape8(1,1,1,0,1,1,0,1), 3),
T tstShape; Blend8(BlendShape8(1,1,0,1,1,1,0,1), 10)
templateshape.FlipU(tstShape); };
if (shape==tstShape) {
flipflags|=0x02; const Blend8 Blends7Neighbour8[] =
return true; {
} Blend8(BlendShape8(1,1,1,1,1,1,0,1), 2),
Blend8(BlendShape8(1,1,1,1,1,1,1,0), 9)
templateshape.FlipV(tstShape); };
if (shape==tstShape) {
flipflags|=0x01; ///////////////////////////////////////////////////////////////////////////////
return true;
}
return false; ///////////////////////////////////////////////////////////////////////////////
} // MatchBlendShapeFlipped: test if the given shape can be made to fit the
// template in either unflipped state, or by flipping the shape in U or V
template<class T> template<class T>
int MatchBlendShape(const T& templateshape,const T& shape,unsigned int& flipflags) bool MatchBlendShapeFlipped(const T& templateshape,const T& shape,unsigned int& flags)
{ {
// try matching unrotated shape first // test unrotated shape
if (MatchBlendShapeRotated(templateshape,shape,flipflags)) { if (shape==templateshape) {
return true; return true;
} }
// now try iterating through rotations of 90,180,270 degrees // test against shape flipped in U
T tstShape; T tstShape;
templateshape.Rotate90(tstShape); templateshape.FlipU(tstShape);
if (MatchBlendShapeRotated(tstShape,shape,flipflags)) { if (shape==tstShape) {
flipflags|=flipflags ? 0x10 : 0x04; flags|=BLENDMAP_FLIPU;
return true; return true;
} }
templateshape.Rotate180(tstShape); // test against shape flipped in V
if (MatchBlendShapeRotated(tstShape,shape,flipflags)) { templateshape.FlipV(tstShape);
flipflags|=0x08; if (shape==tstShape) {
return true; flags|=BLENDMAP_FLIPV;
} return true;
}
templateshape.Rotate270(tstShape);
if (MatchBlendShapeRotated(tstShape,shape,flipflags)) { // no joy; no match by flipping
flipflags|=flipflags ? 0x04 : 0x10; return false;
return true; }
}
///////////////////////////////////////////////////////////////////////////////
/* // MatchBlendShape: try and find a matching blendmap, and the required flip/
FlipBlendU(templateshape,tstShape); // rotation flags, to fit the given shape to the template
if (shape==tstShape) { template<class T>
flipflags|=0x01; int MatchBlendShape(const T& templateshape,const T& shape,unsigned int& flags)
return true; {
} // try matching unrotated shape first using just flipping
if (MatchBlendShapeFlipped(templateshape,shape,flags)) {
FlipBlendV(templateshape,tstShape); return true;
if (shape==tstShape) { }
flipflags|=0x02;
return true; // now try iterating through rotations of 90,180,270 degrees
} T tstShape;
*/ templateshape.Rotate90(tstShape);
return false; if (MatchBlendShapeFlipped(tstShape,shape,flags)) {
} // update flags - note if we've flipped in u or v, we need to rotate in
// the opposite direction
template<class S,class T> flags|=flags ? BLENDMAP_ROTATE270 : BLENDMAP_ROTATE90;
int LookupBlend(int tableSize,const S* table,const T& shape,unsigned int& flipflags) return true;
{ }
// iterate through known blend shapes
for (int b=0;b<tableSize;b++) { templateshape.Rotate180(tstShape);
const S& blend=table[b]; if (MatchBlendShapeFlipped(tstShape,shape,flags)) {
if (MatchBlendShape(blend.m_Shape,shape,flipflags)) { flags|=BLENDMAP_ROTATE180;
return blend.m_AlphaMap; return true;
} }
}
templateshape.Rotate270(tstShape);
// eh? shouldn't get here if we've correctly considered all possible cases; keep the compiler happy, and, while if (MatchBlendShapeFlipped(tstShape,shape,flags)) {
// we're still debugging possible shapes, return bad blend to highlight suspect alphamap logic // update flags - note if we've flipped in u or v, we need to rotate in
return 13; // the opposite direction
} flags|=flags ? BLENDMAP_ROTATE90 : BLENDMAP_ROTATE270;
return true;
}
int Calculate(BlendShape8 shape,unsigned int& flipflags)
{ return false;
// assume we're not going to require flipping }
flipflags=0;
///////////////////////////////////////////////////////////////////////////////
// count number of neighbours // LookupBlend: find and return the blendmap fitting the given shape by
int count=0; // iterating through the given data table and testing each shape in flipped and
for (int i=0;i<8;i++) { // rotated forms until a match is found
if (shape[i]) count++; template<class S,class T>
} int LookupBlend(int tableSize,const S* table,const T& shape,unsigned int& flags)
{
if (count==0) { // iterate through known blend shapes
// no neighbours, just the centre tile has the given texture; use blend circle for (int b=0;b<tableSize;b++) {
return 0; const S& blend=table[b];
} else if (count==8) { if (MatchBlendShape(blend.m_Shape,shape,flags)) {
// all neighbours have same texture; return code to signal no alphamap required return blend.m_AlphaMap;
return -1; }
} else { }
if (count<=4) {
// check if we can consider this a BlendShape4 - ie are any of the diagonals (NE,SE,SW,NW) set? // eh? shouldn't get here if we've correctly considered all possible cases;
if (!shape[1] && !shape[3] && !shape[5] && !shape[7]) { // keep the compiler happy, and, while we're still debugging possible shapes,
// ok, build a BlendShape4 and use that // return bad blend to highlight suspect alphamap logic
BlendShape4 shape4; return 13;
shape4[0]=shape[0]; }
shape4[1]=shape[2];
shape4[2]=shape[4];
shape4[3]=shape[6]; ///////////////////////////////////////////////////////////////////////////////
// Calculate: return the index of the blend map that fits the given shape,
switch (count) { // and the set of flip/rotation flags to get the shape correctly oriented
case 1: int Calculate(BlendShape8 shape,unsigned int& flags)
return LookupBlend(sizeof(Blends1Neighbour)/sizeof(Blend4),Blends1Neighbour,shape4,flipflags); {
// assume we're not going to require flipping or rotating
case 2: flags=0;
return LookupBlend(sizeof(Blends2Neighbour)/sizeof(Blend4),Blends2Neighbour,shape4,flipflags);
// count number of neighbours
case 3: int count=0;
return LookupBlend(sizeof(Blends3Neighbour)/sizeof(Blend4),Blends3Neighbour,shape4,flipflags); for (int i=0;i<8;i++) {
if (shape[i]) count++;
case 4: }
// N,S,E,W have same texture, NE,SE,SW,NW don't; use a blend 4 corners
return 5; if (count==0) {
} // no neighbours, just the centre tile has the given texture; use blend circle
} return 0;
} } else if (count==8) {
// all neighbours have same texture; return code to signal no alphamap required
return -1;
// we've got this far, so now we've got to consider the remaining choices, all containing diagonal elements } else {
switch (count) { if (count<=4) {
case 1: // check if we can consider this a BlendShape4 - ie are any of the diagonals (NE,SE,SW,NW) set?
// trivial case - just return a circle blend if (!shape[1] && !shape[3] && !shape[5] && !shape[7]) {
return 0; // ok, build a BlendShape4 and use that
BlendShape4 shape4;
case 2: shape4[0]=shape[0];
return LookupBlend(sizeof(Blends2Neighbour8)/sizeof(Blend8),Blends2Neighbour8,shape,flipflags); shape4[1]=shape[2];
shape4[2]=shape[4];
case 3: shape4[3]=shape[6];
return LookupBlend(sizeof(Blends3Neighbour8)/sizeof(Blend8),Blends3Neighbour8,shape,flipflags);
switch (count) {
case 4: case 1:
return LookupBlend(sizeof(Blends4Neighbour8)/sizeof(Blend8),Blends4Neighbour8,shape,flipflags); return LookupBlend(sizeof(Blends1Neighbour)/sizeof(Blend4),Blends1Neighbour,shape4,flags);
case 5: case 2:
return LookupBlend(sizeof(Blends5Neighbour8)/sizeof(Blend8),Blends5Neighbour8,shape,flipflags); return LookupBlend(sizeof(Blends2Neighbour)/sizeof(Blend4),Blends2Neighbour,shape4,flags);
case 6: case 3:
return LookupBlend(sizeof(Blends6Neighbour8)/sizeof(Blend8),Blends6Neighbour8,shape,flipflags); return LookupBlend(sizeof(Blends3Neighbour)/sizeof(Blend4),Blends3Neighbour,shape4,flags);
case 7: case 4:
return LookupBlend(sizeof(Blends7Neighbour8)/sizeof(Blend8),Blends7Neighbour8,shape,flipflags); // N,S,E,W have same texture, NE,SE,SW,NW don't; use a blend 4 corners
} return 5;
}
} }
}
// Shouldn't get here if we've correctly considered all possible cases; keep the compiler happy, and, while
// we're still debugging possible shapes, return bad blend to highlight suspect alphamap logic
return 13; // we've got this far, so now we've got to consider the remaining choices, all containing
} // diagonal elements
switch (count) {
} // end of namespace case 1:
// trivial case - just return a circle blend
return 0;
case 2:
return LookupBlend(sizeof(Blends2Neighbour8)/sizeof(Blend8),Blends2Neighbour8,shape,flags);
case 3:
return LookupBlend(sizeof(Blends3Neighbour8)/sizeof(Blend8),Blends3Neighbour8,shape,flags);
case 4:
return LookupBlend(sizeof(Blends4Neighbour8)/sizeof(Blend8),Blends4Neighbour8,shape,flags);
case 5:
return LookupBlend(sizeof(Blends5Neighbour8)/sizeof(Blend8),Blends5Neighbour8,shape,flags);
case 6:
return LookupBlend(sizeof(Blends6Neighbour8)/sizeof(Blend8),Blends6Neighbour8,shape,flags);
case 7:
return LookupBlend(sizeof(Blends7Neighbour8)/sizeof(Blend8),Blends7Neighbour8,shape,flags);
}
}
// Shouldn't get here if we've correctly considered all possible cases;
// keep the compiler happy, and, while we're still debugging possible shapes,
// return bad blend to highlight suspect alphamap logic
return 13;
}
} // end of namespace

View File

@ -1,11 +1,31 @@
#ifndef _ALPHAMAPCALCULATOR_H ///////////////////////////////////////////////////////////////////////////////
#define _ALPHAMAPCALCULATOR_H //
// Name: AlphaMapCalculator.h
#include <string.h> // Author: Rich Cross
#include "BlendShapes.h" // Contact: rich@wildfiregames.com
//
namespace CAlphaMapCalculator { ///////////////////////////////////////////////////////////////////////////////
int Calculate(BlendShape8 shape,unsigned int& flipflags);
} #ifndef _ALPHAMAPCALCULATOR_H
#define _ALPHAMAPCALCULATOR_H
#endif
#include <string.h>
#include "BlendShapes.h"
// defines for blendmap flipping/rotating
#define BLENDMAP_FLIPV 0x01
#define BLENDMAP_FLIPU 0x02
#define BLENDMAP_ROTATE90 0x04
#define BLENDMAP_ROTATE180 0x08
#define BLENDMAP_ROTATE270 0x10
///////////////////////////////////////////////////////////////////////////////
// CAlphaMapCalculator: functionality for calculating which alpha blend map
// fits a given shape
namespace CAlphaMapCalculator {
// Calculate: return the index of the blend map that fits the given shape,
// and the set of flip/rotation flags to get the shape correctly oriented
int Calculate(BlendShape8 shape,unsigned int& flags);
}
#endif

View File

@ -1,134 +1,142 @@
#ifndef _BLENDSHAPES_H ///////////////////////////////////////////////////////////////////////////////
#define _BLENDSHAPES_H //
// Name: BlendShapes.h
struct BlendShape4 // Author: Rich Cross
{ // Contact: rich@wildfiregames.com
public: //
BlendShape4() {} ///////////////////////////////////////////////////////////////////////////////
BlendShape4(int a,int b,int c,int d) {
m_Data[0]=a; m_Data[1]=b; m_Data[2]=c; m_Data[3]=d; #ifndef _BLENDSHAPES_H
} #define _BLENDSHAPES_H
int& operator[](int index) { return m_Data[index]; } struct BlendShape4
const int& operator[](int index) const { return m_Data[index]; } {
public:
bool operator==(const BlendShape4& lhs) const { BlendShape4() {}
return memcmp(m_Data,lhs.m_Data,sizeof(BlendShape4))==0; BlendShape4(int a,int b,int c,int d) {
} m_Data[0]=a; m_Data[1]=b; m_Data[2]=c; m_Data[3]=d;
}
void Rotate90(BlendShape4& dst) const {
dst[0]=m_Data[3]; int& operator[](int index) { return m_Data[index]; }
dst[1]=m_Data[0]; const int& operator[](int index) const { return m_Data[index]; }
dst[2]=m_Data[1];
dst[3]=m_Data[2]; bool operator==(const BlendShape4& lhs) const {
} return memcmp(m_Data,lhs.m_Data,sizeof(BlendShape4))==0;
}
void Rotate180(BlendShape4& dst) const {
dst[0]=m_Data[2]; void Rotate90(BlendShape4& dst) const {
dst[1]=m_Data[3]; dst[0]=m_Data[3];
dst[2]=m_Data[0]; dst[1]=m_Data[0];
dst[3]=m_Data[1]; dst[2]=m_Data[1];
} dst[3]=m_Data[2];
}
void Rotate270(BlendShape4& dst) const {
dst[0]=m_Data[1]; void Rotate180(BlendShape4& dst) const {
dst[1]=m_Data[2]; dst[0]=m_Data[2];
dst[2]=m_Data[3]; dst[1]=m_Data[3];
dst[3]=m_Data[0]; dst[2]=m_Data[0];
} dst[3]=m_Data[1];
}
void FlipU(BlendShape4& dst) const {
dst[0]=m_Data[0]; void Rotate270(BlendShape4& dst) const {
dst[1]=m_Data[3]; dst[0]=m_Data[1];
dst[2]=m_Data[2]; dst[1]=m_Data[2];
dst[3]=m_Data[1]; dst[2]=m_Data[3];
} dst[3]=m_Data[0];
}
void FlipV(BlendShape4& dst) const {
dst[0]=m_Data[2]; void FlipU(BlendShape4& dst) const {
dst[1]=m_Data[1]; dst[0]=m_Data[2];
dst[2]=m_Data[0]; dst[1]=m_Data[1];
dst[3]=m_Data[3]; dst[2]=m_Data[0];
} dst[3]=m_Data[3];
}
private:
int m_Data[4]; void FlipV(BlendShape4& dst) const {
}; dst[0]=m_Data[0];
dst[1]=m_Data[3];
dst[2]=m_Data[2];
struct BlendShape8 dst[3]=m_Data[1];
{ }
public:
BlendShape8() {} private:
BlendShape8(int a,int b,int c,int d,int e,int f,int g,int h) { int m_Data[4];
m_Data[0]=a; m_Data[1]=b; m_Data[2]=c; m_Data[3]=d; };
m_Data[4]=e; m_Data[5]=f; m_Data[6]=g; m_Data[7]=h;
}
struct BlendShape8
int& operator[](int index) { return m_Data[index]; } {
const int& operator[](int index) const { return m_Data[index]; } public:
BlendShape8() {}
bool operator==(const BlendShape8& lhs) const { BlendShape8(int a,int b,int c,int d,int e,int f,int g,int h) {
return memcmp(m_Data,lhs.m_Data,sizeof(BlendShape8))==0; m_Data[0]=a; m_Data[1]=b; m_Data[2]=c; m_Data[3]=d;
} m_Data[4]=e; m_Data[5]=f; m_Data[6]=g; m_Data[7]=h;
}
void Rotate90(BlendShape8& dst) const {
dst[0]=m_Data[6]; int& operator[](int index) { return m_Data[index]; }
dst[1]=m_Data[7]; const int& operator[](int index) const { return m_Data[index]; }
dst[2]=m_Data[0];
dst[3]=m_Data[1]; bool operator==(const BlendShape8& lhs) const {
dst[4]=m_Data[2]; return memcmp(m_Data,lhs.m_Data,sizeof(BlendShape8))==0;
dst[5]=m_Data[3]; }
dst[6]=m_Data[4];
dst[7]=m_Data[5]; void Rotate90(BlendShape8& dst) const {
} dst[0]=m_Data[6];
dst[1]=m_Data[7];
void Rotate180(BlendShape8& dst) const { dst[2]=m_Data[0];
dst[0]=m_Data[4]; dst[3]=m_Data[1];
dst[1]=m_Data[5]; dst[4]=m_Data[2];
dst[2]=m_Data[6]; dst[5]=m_Data[3];
dst[3]=m_Data[7]; dst[6]=m_Data[4];
dst[4]=m_Data[0]; dst[7]=m_Data[5];
dst[5]=m_Data[1]; }
dst[6]=m_Data[2];
dst[7]=m_Data[3]; void Rotate180(BlendShape8& dst) const {
} dst[0]=m_Data[4];
dst[1]=m_Data[5];
void Rotate270(BlendShape8& dst) const { dst[2]=m_Data[6];
dst[0]=m_Data[2]; dst[3]=m_Data[7];
dst[1]=m_Data[3]; dst[4]=m_Data[0];
dst[2]=m_Data[4]; dst[5]=m_Data[1];
dst[3]=m_Data[5]; dst[6]=m_Data[2];
dst[4]=m_Data[6]; dst[7]=m_Data[3];
dst[5]=m_Data[7]; }
dst[6]=m_Data[0];
dst[7]=m_Data[1]; void Rotate270(BlendShape8& dst) const {
} dst[0]=m_Data[2];
dst[1]=m_Data[3];
void FlipU(BlendShape8& dst) const { dst[2]=m_Data[4];
dst[0]=m_Data[0]; dst[3]=m_Data[5];
dst[1]=m_Data[7]; dst[4]=m_Data[6];
dst[2]=m_Data[6]; dst[5]=m_Data[7];
dst[3]=m_Data[5]; dst[6]=m_Data[0];
dst[4]=m_Data[4]; dst[7]=m_Data[1];
dst[5]=m_Data[3]; }
dst[6]=m_Data[2];
dst[7]=m_Data[1]; void FlipU(BlendShape8& dst) const {
} dst[0]=m_Data[4];
dst[1]=m_Data[3];
void FlipV(BlendShape8& dst) const { dst[2]=m_Data[2];
dst[0]=m_Data[4]; dst[3]=m_Data[1];
dst[1]=m_Data[3]; dst[4]=m_Data[0];
dst[2]=m_Data[2]; dst[5]=m_Data[7];
dst[3]=m_Data[1]; dst[6]=m_Data[6];
dst[4]=m_Data[0]; dst[7]=m_Data[5];
dst[5]=m_Data[7]; }
dst[6]=m_Data[6];
dst[7]=m_Data[5]; void FlipV(BlendShape8& dst) const {
} dst[0]=m_Data[0];
dst[1]=m_Data[7];
private: dst[2]=m_Data[6];
int m_Data[8]; dst[3]=m_Data[5];
}; dst[4]=m_Data[4];
dst[5]=m_Data[3];
#endif dst[6]=m_Data[2];
dst[7]=m_Data[1];
}
private:
int m_Data[8];
};
#endif

View File

@ -1,165 +1,162 @@
//----------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////////
// //
// Name: Bound.h // Name: Bound.cpp
// Last Update: 25/11/03 // Author: Rich Cross
// Author: Rich Cross // Contact: rich@wildfiregames.com
// Contact: rich@0ad.wildfiregames.com //
// ///////////////////////////////////////////////////////////////////////////////
// Description: Basic axis aligned bounding box class
//
//----------------------------------------------------------- // necessary includes
#include <assert.h>
// necessary includes #include <float.h>
#include <assert.h> #include "Bound.h"
#include <float.h>
#include "Bound.h" ///////////////////////////////////////////////////////////////////////////////
// operator+=: extend this bound to include given bound
//----------------------------------------------------------- CBound& CBound::operator+=(const CBound& b)
// operator+=: extend this bound to include given bound {
//----------------------------------------------------------- for (int i=0;i<3;++i) {
CBound& CBound::operator+=(const CBound& b) if (b[0][i]<m_Data[0][i])
{ m_Data[0][i]=b[0][i];
for (int i=0;i<3;++i) { if (b[1][i]>m_Data[1][i])
if (b[0][i]<m_Data[0][i]) m_Data[1][i]=b[1][i];
m_Data[0][i]=b[0][i]; }
if (b[1][i]>m_Data[1][i])
m_Data[1][i]=b[1][i]; return *this;
} }
return *this; ///////////////////////////////////////////////////////////////////////////////
} // operator+=: extend this bound to include given point
CBound& CBound::operator+=(const CVector3D& pt)
//----------------------------------------------------------- {
// operator+=: extend this bound to include given point for (int i=0;i<3;++i) {
//----------------------------------------------------------- if (pt[i]<m_Data[0][i])
CBound& CBound::operator+=(const CVector3D& pt) m_Data[0][i]=pt[i];
{ else if (pt[i]>m_Data[1][i])
for (int i=0;i<3;++i) { m_Data[1][i]=pt[i];
if (pt[i]<m_Data[0][i]) }
m_Data[0][i]=pt[i];
else if (pt[i]>m_Data[1][i]) return *this;
m_Data[1][i]=pt[i]; }
}
///////////////////////////////////////////////////////////////////////////////
return *this; // RayIntersect: intersect ray with this bound; return true
} // if ray hits (and store entry and exit times), or false
// otherwise
//----------------------------------------------------------- // note: incoming ray direction must be normalised
// RayIntersect: intersect ray with this bound; return true bool CBound::RayIntersect(const CVector3D& origin,const CVector3D& dir,
// if ray hits (and store entry and exit times), or false float& tmin,float& tmax) const
// otherwise {
// note: incoming ray direction must be normalised float t1,t2;
//----------------------------------------------------------- float tnear,tfar;
bool CBound::RayIntersect(const CVector3D& origin,const CVector3D& dir,
float& tmin,float& tmax) const if (dir[0]==0) {
{ if (origin[0]<m_Data[0][0] || origin[0]>m_Data[1][0])
float t1,t2; return false;
float tnear,tfar; else {
tnear=(float) FLT_MIN;
if (dir[0]==0) { tfar=(float) FLT_MAX;
if (origin[0]<m_Data[0][0] || origin[0]>m_Data[1][0]) }
return false; } else {
else { t1=(m_Data[0][0]-origin[0])/dir[0];
tnear=(float) FLT_MIN; t2=(m_Data[1][0]-origin[0])/dir[0];
tfar=(float) FLT_MAX;
} if (dir[0]<0) {
} else { tnear = t2;
t1=(m_Data[0][0]-origin[0])/dir[0]; tfar = t1;
t2=(m_Data[1][0]-origin[0])/dir[0]; } else {
tnear = t1;
if (dir[0]<0) { tfar = t2;
tnear = t2; }
tfar = t1;
} else { if (tfar<0)
tnear = t1; return false;
tfar = t2; }
}
if (dir[1]==0 && (origin[1]<m_Data[0][1] || origin[1]>m_Data[1][1]))
if (tfar<0) return false;
return false; else {
} t1=(m_Data[0][1]-origin[1])/dir[1];
t2=(m_Data[1][1]-origin[1])/dir[1];
if (dir[1]==0 && (origin[1]<m_Data[0][1] || origin[1]>m_Data[1][1]))
return false; if (dir[1]<0) {
else { if (t2>tnear)
t1=(m_Data[0][1]-origin[1])/dir[1]; tnear = t2;
t2=(m_Data[1][1]-origin[1])/dir[1]; if (t1<tfar)
tfar = t1;
if (dir[1]<0) { } else {
if (t2>tnear) if (t1>tnear)
tnear = t2; tnear = t1;
if (t1<tfar) if (t2<tfar)
tfar = t1; tfar = t2;
} else { }
if (t1>tnear)
tnear = t1; if (tnear>tfar || tfar<0)
if (t2<tfar) return false;
tfar = t2; }
}
if (dir[2]==0 && (origin[2]<m_Data[0][2] || origin[2]>m_Data[1][2]))
if (tnear>tfar || tfar<0) return false;
return false; else {
} t1=(m_Data[0][2]-origin[2])/dir[2];
t2=(m_Data[1][2]-origin[2])/dir[2];
if (dir[2]==0 && (origin[2]<m_Data[0][2] || origin[2]>m_Data[1][2]))
return false; if (dir[2]<0) {
else { if (t2>tnear)
t1=(m_Data[0][2]-origin[2])/dir[2]; tnear = t2;
t2=(m_Data[1][2]-origin[2])/dir[2]; if (t1<tfar)
tfar = t1;
if (dir[2]<0) { } else {
if (t2>tnear) if (t1>tnear)
tnear = t2; tnear = t1;
if (t1<tfar) if (t2<tfar)
tfar = t1; tfar = t2;
} else { }
if (t1>tnear)
tnear = t1; if (tnear>tfar || tfar<0)
if (t2<tfar) return false;
tfar = t2; }
}
tmin=tnear;
if (tnear>tfar || tfar<0) tmax=tfar;
return false;
} return true;
}
tmin=tnear;
tmax=tfar; ///////////////////////////////////////////////////////////////////////////////
// SetEmpty: initialise this bound as empty
return true; void CBound::SetEmpty()
} {
m_Data[0]=CVector3D(FLT_MAX,FLT_MAX,FLT_MAX);
//----------------------------------------------------------- m_Data[1]=CVector3D(FLT_MIN,FLT_MIN,FLT_MIN);
// SetEmpty: initialise this bound as empty }
//-----------------------------------------------------------
void CBound::SetEmpty() ///////////////////////////////////////////////////////////////////////////////
{ // Transform: transform this bound by given matrix; return transformed bound
m_Data[0]=CVector3D(FLT_MAX,FLT_MAX,FLT_MAX); // in 'result' parameter - slightly modified version of code in Graphic Gems
m_Data[1]=CVector3D(FLT_MIN,FLT_MIN,FLT_MIN); // (can't remember which one it was, though)
} void CBound::Transform(const CMatrix3D& m,CBound& result) const
{
assert(this!=&result);
void CBound::Transform(const CMatrix3D& m,CBound& result) const
{ for (int i=0;i<3;++i) {
assert(this!=&result); // handle translation
result[0][i]=result[1][i]=m(3,i);
for (int i=0;i<3;++i) {
// handle translation // Now find the extreme points by considering the product of the
result[0][i]=result[1][i]=m(3,i); // min and max with each component of matrix
for(int j=0;j<3;j++) {
// Now find the extreme points by considering the product of the float a=m(i,j)*m_Data[0][j];
// min and max with each component of matrix float b=m(i,j)*m_Data[1][j];
for(int j=0;j<3;j++) {
float a=m(i,j)*m_Data[0][j]; if (a<b) {
float b=m(i,j)*m_Data[1][j]; result[0][i]+=a;
result[1][i]+=b;
if (a<b) { } else {
result[0][i]+=a; result[0][i]+=b;
result[1][i]+=b; result[1][i]+=a;
} else { }
result[0][i]+=b; }
result[1][i]+=a; }
} }
}
}
}

View File

@ -1,51 +1,50 @@
//----------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////////
// //
// Name: Bound.h // Name: Bound.h
// Last Update: 25/11/03 // Author: Rich Cross
// Author: Rich Cross // Contact: rich@wildfiregames.com
// Contact: rich@0ad.wildfiregames.com //
// ///////////////////////////////////////////////////////////////////////////////
// Description: Basic axis aligned bounding box class
// #ifndef _BOUND_H
//----------------------------------------------------------- #define _BOUND_H
#ifndef _BOUND_H // necessary includes
#define _BOUND_H #include "Vector3D.h"
#include "Matrix3D.h"
// necessary includes
#include "Vector3D.h" ///////////////////////////////////////////////////////////////////////////////
#include "Matrix3D.h" // CBound: basic axis aligned bounding box class
class CBound
class CBound {
{ public:
public: CBound() {}
CBound() {} CBound(const CVector3D& min,const CVector3D& max) {
CBound(const CVector3D& min,const CVector3D& max) { m_Data[0]=min; m_Data[1]=max;
m_Data[0]=min; m_Data[1]=max; }
}
void Transform(const CMatrix3D& m,CBound& result) const;
void Transform(const CMatrix3D& m,CBound& result) const;
CVector3D& operator[](int index) { return m_Data[index]; }
CVector3D& operator[](int index) { return m_Data[index]; } const CVector3D& operator[](int index) const { return m_Data[index]; }
const CVector3D& operator[](int index) const { return m_Data[index]; }
void SetEmpty();
void SetEmpty();
CBound& operator+=(const CBound& b);
CBound& operator+=(const CBound& b); CBound& operator+=(const CVector3D& pt);
CBound& operator+=(const CVector3D& pt);
bool RayIntersect(const CVector3D& origin,const CVector3D& dir,float& tmin,float& tmax) const;
bool RayIntersect(const CVector3D& origin,const CVector3D& dir,float& tmin,float& tmax) const;
float GetVolume() const {
float GetVolume() const { CVector3D v=m_Data[1]-m_Data[0];
CVector3D v=m_Data[1]-m_Data[0]; return v.X*v.Y*v.Z;
return v.X*v.Y*v.Z; }
}
private:
private: CVector3D m_Data[2];
CVector3D m_Data[2]; };
}; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif
#endif

View File

@ -1,109 +1,108 @@
//*********************************************************** //***********************************************************
// //
// Name: Camera.Cpp // Name: Camera.Cpp
// Last Update: 24/2/02 // Last Update: 24/2/02
// Author: Poya Manouchehri // Author: Poya Manouchehri
// //
// Description: CCamera holds a view and a projection matrix. // Description: CCamera holds a view and a projection matrix.
// It also has a frustum which can be used to // It also has a frustum which can be used to
// cull objects for rendering. // cull objects for rendering.
// //
//*********************************************************** //***********************************************************
#include "Camera.h" #include "Camera.h"
#include "Prometheus.h"
CCamera::CCamera ()
CCamera::CCamera () {
{ // set viewport to something anything should handle, but should be initialised
// set viewport to something anything should handle, but should be initialised // to window size before use
// to window size before use m_ViewPort.m_X = 0;
m_ViewPort.m_X = 0; m_ViewPort.m_Y = 0;
m_ViewPort.m_Y = 0; m_ViewPort.m_Width = 800;
m_ViewPort.m_Width = 800; m_ViewPort.m_Height = 600;
m_ViewPort.m_Height = 600; }
}
CCamera::~CCamera ()
CCamera::~CCamera () {
{ }
}
void CCamera::SetProjection (float nearp, float farp, float fov)
void CCamera::SetProjection (float nearp, float farp, float fov) {
{ float h, w, Q;
float h, w, Q;
m_NearPlane = nearp;
m_NearPlane = nearp; m_FarPlane = farp;
m_FarPlane = farp; m_FOV = fov;
m_FOV = fov;
float Aspect = (float)m_ViewPort.m_Width/(float)m_ViewPort.m_Height;
float Aspect = (float)m_ViewPort.m_Width/(float)m_ViewPort.m_Height;
w = 1/tanf (fov*0.5f*Aspect);
w = 1/tanf (fov*0.5f*Aspect); h = 1/tanf (fov*0.5f);
h = 1/tanf (fov*0.5f); Q = m_FarPlane / (m_FarPlane - m_NearPlane);
Q = m_FarPlane / (m_FarPlane - m_NearPlane);
m_ProjMat.SetZero ();
m_ProjMat.SetZero (); m_ProjMat._11 = w;
m_ProjMat._11 = w; m_ProjMat._22 = h;
m_ProjMat._22 = h; m_ProjMat._33 = Q;
m_ProjMat._33 = Q; m_ProjMat._34 = -Q*m_NearPlane;
m_ProjMat._34 = -Q*m_NearPlane; m_ProjMat._43 = 1.0f;
m_ProjMat._43 = 1.0f; }
}
//Updates the frustum planes. Should be called
//Updates the frustum planes. Should be called //everytime the view or projection matrices are
//everytime the view or projection matrices are //altered.
//altered. void CCamera::UpdateFrustum ()
void CCamera::UpdateFrustum () {
{ CMatrix3D MatFinal;
CMatrix3D MatFinal; CMatrix3D MatView;
CMatrix3D MatView;
m_Orientation.GetInverse(MatView);
m_Orientation.Invert(MatView);
MatFinal = m_ProjMat * MatView;
MatFinal = m_ProjMat * MatView;
//get the RIGHT plane
//get the RIGHT plane m_ViewFrustum.SetNumPlanes (6);
m_ViewFrustum.SetNumPlanes (6);
m_ViewFrustum.m_aPlanes[0].m_Norm.X = MatFinal._41-MatFinal._11;
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.Y = MatFinal._42-MatFinal._12; m_ViewFrustum.m_aPlanes[0].m_Norm.Z = MatFinal._43-MatFinal._13;
m_ViewFrustum.m_aPlanes[0].m_Norm.Z = MatFinal._43-MatFinal._13; m_ViewFrustum.m_aPlanes[0].m_Dist = MatFinal._44-MatFinal._14;
m_ViewFrustum.m_aPlanes[0].m_Dist = MatFinal._44-MatFinal._14;
//get the LEFT plane
//get the LEFT plane m_ViewFrustum.m_aPlanes[1].m_Norm.X = MatFinal._41+MatFinal._11;
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.Y = MatFinal._42+MatFinal._12; m_ViewFrustum.m_aPlanes[1].m_Norm.Z = MatFinal._43+MatFinal._13;
m_ViewFrustum.m_aPlanes[1].m_Norm.Z = MatFinal._43+MatFinal._13; m_ViewFrustum.m_aPlanes[1].m_Dist = MatFinal._44+MatFinal._14;
m_ViewFrustum.m_aPlanes[1].m_Dist = MatFinal._44+MatFinal._14;
//get the BOTTOM plane
//get the BOTTOM plane m_ViewFrustum.m_aPlanes[2].m_Norm.X = MatFinal._41+MatFinal._21;
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.Y = MatFinal._42+MatFinal._22; m_ViewFrustum.m_aPlanes[2].m_Norm.Z = MatFinal._43+MatFinal._23;
m_ViewFrustum.m_aPlanes[2].m_Norm.Z = MatFinal._43+MatFinal._23; m_ViewFrustum.m_aPlanes[2].m_Dist = MatFinal._44+MatFinal._24;
m_ViewFrustum.m_aPlanes[2].m_Dist = MatFinal._44+MatFinal._24;
//get the TOP plane
//get the TOP plane m_ViewFrustum.m_aPlanes[3].m_Norm.X = MatFinal._41-MatFinal._21;
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.Y = MatFinal._42-MatFinal._22; m_ViewFrustum.m_aPlanes[3].m_Norm.Z = MatFinal._43-MatFinal._23;
m_ViewFrustum.m_aPlanes[3].m_Norm.Z = MatFinal._43-MatFinal._23; m_ViewFrustum.m_aPlanes[3].m_Dist = MatFinal._44-MatFinal._24;
m_ViewFrustum.m_aPlanes[3].m_Dist = MatFinal._44-MatFinal._24;
//get the FAR plane
//get the FAR plane m_ViewFrustum.m_aPlanes[4].m_Norm.X = MatFinal._41-MatFinal._31;
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.Y = MatFinal._42-MatFinal._32; m_ViewFrustum.m_aPlanes[4].m_Norm.Z = MatFinal._43-MatFinal._33;
m_ViewFrustum.m_aPlanes[4].m_Norm.Z = MatFinal._43-MatFinal._33; m_ViewFrustum.m_aPlanes[4].m_Dist = MatFinal._44-MatFinal._34;
m_ViewFrustum.m_aPlanes[4].m_Dist = MatFinal._44-MatFinal._34;
//get the NEAR plane
//get the NEAR plane m_ViewFrustum.m_aPlanes[5].m_Norm.X = MatFinal._41+MatFinal._31;
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.Y = MatFinal._42+MatFinal._32; m_ViewFrustum.m_aPlanes[5].m_Norm.Z = MatFinal._43+MatFinal._33;
m_ViewFrustum.m_aPlanes[5].m_Norm.Z = MatFinal._43+MatFinal._33; m_ViewFrustum.m_aPlanes[5].m_Dist = MatFinal._44+MatFinal._34;
m_ViewFrustum.m_aPlanes[5].m_Dist = MatFinal._44+MatFinal._34; }
}
void CCamera::SetViewPort (SViewPort *viewport)
void CCamera::SetViewPort (SViewPort *viewport) {
{ m_ViewPort.m_X = viewport->m_X;
m_ViewPort.m_X = viewport->m_X; m_ViewPort.m_Y = viewport->m_Y;
m_ViewPort.m_Y = viewport->m_Y; m_ViewPort.m_Width = viewport->m_Width;
m_ViewPort.m_Width = viewport->m_Width; m_ViewPort.m_Height = viewport->m_Height;
m_ViewPort.m_Height = viewport->m_Height; }
}

View File

@ -1,72 +1,72 @@
//*********************************************************** //***********************************************************
// //
// Name: Camera.h // Name: Camera.H
// Last Update: 24/2/02 // Last Update: 24/2/02
// Author: Poya Manouchehri // Author: Poya Manouchehri
// //
// Description: CCamera holds a view and a projection matrix. // Description: CCamera holds a view and a projection matrix.
// It also has a frustum which can be used to // It also has a frustum which can be used to
// cull objects for rendering. // cull objects for rendering.
// //
//*********************************************************** //***********************************************************
#ifndef CAMERA_H #ifndef CAMERA_H
#define CAMERA_H #define CAMERA_H
#include "Frustum.h" #include "Frustum.h"
#include "Matrix3D.h" #include "Matrix3D.h"
//view port //view port
struct SViewPort struct SViewPort
{ {
unsigned int m_X; unsigned int m_X;
unsigned int m_Y; unsigned int m_Y;
unsigned int m_Width; unsigned int m_Width;
unsigned int m_Height; unsigned int m_Height;
}; };
class CCamera class CCamera
{ {
public: public:
CCamera (); CCamera ();
~CCamera (); ~CCamera ();
//Methods for projection //Methods for projection
void SetProjection (CMatrix3D *proj) { m_ProjMat = *proj; } void SetProjection (CMatrix3D *proj) { m_ProjMat = *proj; }
void SetProjection (float nearp, float farp, float fov); void SetProjection (float nearp, float farp, float fov);
CMatrix3D GetProjection () { return m_ProjMat; } CMatrix3D GetProjection () { return m_ProjMat; }
//Updates the frustum planes. Should be called //Updates the frustum planes. Should be called
//everytime the view or projection matrices are //everytime the view or projection matrices are
//altered. //altered.
void UpdateFrustum (); void UpdateFrustum ();
CFrustum GetFustum () { return m_ViewFrustum; } CFrustum GetFustum () { return m_ViewFrustum; }
void SetViewPort (SViewPort *viewport); void SetViewPort (SViewPort *viewport);
SViewPort GetViewPort () { return m_ViewPort; } SViewPort GetViewPort () { return m_ViewPort; }
//getters //getters
float GetNearPlane () { return m_NearPlane; } float GetNearPlane () { return m_NearPlane; }
float GetFarPlane () { return m_FarPlane; } float GetFarPlane () { return m_FarPlane; }
float GetFOV () { return m_FOV; } float GetFOV () { return m_FOV; }
public: public:
//This is the orientation matrix. The inverse of this //This is the orientation matrix. The inverse of this
//is the view matrix //is the view matrix
CMatrix3D m_Orientation; CMatrix3D m_Orientation;
private: private:
//keep the projection matrix private //keep the projection matrix private
//so we can't fiddle with it. //so we can't fiddle with it.
CMatrix3D m_ProjMat; CMatrix3D m_ProjMat;
float m_NearPlane; float m_NearPlane;
float m_FarPlane; float m_FarPlane;
float m_FOV; float m_FOV;
SViewPort m_ViewPort; SViewPort m_ViewPort;
CFrustum m_ViewFrustum; CFrustum m_ViewFrustum;
}; };
#endif #endif

View File

@ -1,22 +1,30 @@
//----------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////////
// //
// Name: Color.h // Name: Color.h
// Last Update: 25/11/03 // Author: Rich Cross
// Author: Rich Cross // Contact: rich@wildfiregames.com
// Contact: rich@0ad.wildfiregames.com //
// ///////////////////////////////////////////////////////////////////////////////
// Description: Definitions for 3 and 4 component floating
// point colors #ifndef _COLOR_H
// #define _COLOR_H
//-----------------------------------------------------------
#include "Vector3D.h"
#ifndef _COLOR_H #include "Vector4D.h"
#define _COLOR_H
// simple defines for 3 and 4 component floating point colors - just map to
#include "Vector3D.h" // corresponding vector types
#include "Vector4D.h" typedef CVector3D RGBColor;
typedef CVector4D RGBAColor;
typedef CVector3D RGBColor;
typedef CVector4D RGBAColor; // SColor4ub: structure for packed RGBA colors
struct SColor4ub
#endif {
u8 R;
u8 G;
u8 B;
u8 A;
};
#endif

76
source/terrain/FilePacker.cpp Executable file
View File

@ -0,0 +1,76 @@
///////////////////////////////////////////////////////////////////////////////
//
// Name: FilePacker.cpp
// Author: Rich Cross
// Contact: rich@wildfiregames.com
//
///////////////////////////////////////////////////////////////////////////////
#include "FilePacker.h"
#include <stdio.h>
////////////////////////////////////////////////////////////////////////////////////////
// CFilePacker constructor
CFilePacker::CFilePacker()
{
}
////////////////////////////////////////////////////////////////////////////////////////
// Write: write out any packed data to file, using given version and magic bits
void CFilePacker::Write(const char* filename,u32 version,const char magicstr[4])
{
FILE* fp=fopen(filename,"wb");
if (!fp) {
throw CFileOpenError();
}
// write magic bits
if (fwrite(magicstr,sizeof(char)*4,1,fp)!=1) {
fclose(fp);
throw CFileWriteError();
}
// write version
if (fwrite(&version,sizeof(version),1,fp)!=1) {
fclose(fp);
throw CFileWriteError();
}
// get size of data
u32 datasize=m_Data.size();
if (fwrite(&datasize,sizeof(datasize),1,fp)!=1) {
fclose(fp);
throw CFileWriteError();
}
// write out one big chunk of data
if (fwrite(&m_Data[0],datasize,1,fp)!=1) {
fclose(fp);
throw CFileWriteError();
}
// all done
fclose(fp);
}
////////////////////////////////////////////////////////////////////////////////////////
// PackRaw: pack given number of bytes onto the end of the data stream
void CFilePacker::PackRaw(const void* rawdata,u32 rawdatalen)
{
u32 start=m_Data.size();
m_Data.resize(m_Data.size()+rawdatalen);
memcpy(&m_Data[start],rawdata,rawdatalen);
}
////////////////////////////////////////////////////////////////////////////////////////
// PackString: pack a string onto the end of the data stream
void CFilePacker::PackString(const CStr& str)
{
u32 len=str.Length();
PackRaw(&len,sizeof(len));
PackRaw((const char*) str,len);
}

43
source/terrain/FilePacker.h Executable file
View File

@ -0,0 +1,43 @@
///////////////////////////////////////////////////////////////////////////////
//
// Name: FilePacker.h
// Author: Rich Cross
// Contact: rich@wildfiregames.com
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _FILEPACKER_H
#define _FILEPACKER_H
#include <vector>
#include "res/res.h"
#include "CStr.h"
////////////////////////////////////////////////////////////////////////////////////////
// CFilePacker: class to assist in writing of binary files
class CFilePacker
{
public:
// CFilePacker exceptions
class CError { };
class CFileOpenError : public CError { };
class CFileWriteError : public CError { };
public:
// constructor
CFilePacker();
// Write: write out any packed data to file, using given version and magic bits
void Write(const char* filename,u32 version,const char magicstr[4]);
// PackRaw: pack given number of bytes onto the end of the data stream
void PackRaw(const void* rawdata,u32 rawdatalen);
// PackString: pack a string onto the end of the data stream
void PackString(const CStr& str);
private:
// the output data stream built during pack operations
std::vector<u8> m_Data;
};
#endif

101
source/terrain/FileUnpacker.cpp Executable file
View File

@ -0,0 +1,101 @@
///////////////////////////////////////////////////////////////////////////////
//
// Name: FileUnpacker.cpp
// Author: Rich Cross
// Contact: rich@wildfiregames.com
//
///////////////////////////////////////////////////////////////////////////////
#include "FileUnpacker.h"
#include <stdio.h>
////////////////////////////////////////////////////////////////////////////////////////
// CFileUnpacker constructor
CFileUnpacker::CFileUnpacker() : m_UnpackPos(0), m_Version(0)
{
}
////////////////////////////////////////////////////////////////////////////////////////
// Read: open and read in given file, check magic bits against those given; throw
// variety of exceptions for missing files etc
void CFileUnpacker::Read(const char* filename,const char magicstr[4])
{
FILE* fp=fopen(filename,"rb");
if (!fp) {
throw CFileOpenError();
}
// read magic bits
char magic[4];
if (fread(magic,sizeof(char)*4,1,fp)!=1) {
fclose(fp);
throw CFileReadError();
}
// check we've got the right kind of file
if (strncmp(magic,magicstr,4)!=0) {
// nope ..
fclose(fp);
throw CFileTypeError();
}
// get version
if (fread(&m_Version,sizeof(m_Version),1,fp)!=1) {
fclose(fp);
throw CFileReadError();
}
// get size of anim data
u32 datasize;
if (fread(&datasize,sizeof(datasize),1,fp)!=1) {
fclose(fp);
throw CFileReadError();
}
// allocate memory and read in a big chunk of data
m_Data.resize(datasize);
if (fread(&m_Data[0],datasize,1,fp)!=1) {
fclose(fp);
throw CFileReadError();
}
// all done
fclose(fp);
}
////////////////////////////////////////////////////////////////////////////////////////
// UnpackRaw: unpack given number of bytes from the input stream into the given array
// - throws CFileEOFError if the end of the data stream is reached before the given
// number of bytes have been read
void CFileUnpacker::UnpackRaw(void* rawdata,u32 rawdatalen)
{
// got enough data to unpack?
if (m_UnpackPos+rawdatalen<=m_Data.size()) {
// yes .. copy over
memcpy(rawdata,&m_Data[m_UnpackPos],rawdatalen);
// advance pointer
m_UnpackPos+=rawdatalen;
} else {
// nope - throw exception
throw CFileEOFError();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// UnpackString: unpack a string from the raw data stream
void CFileUnpacker::UnpackString(CStr& result)
{
// get string length
u32 length;
UnpackRaw(&length,sizeof(length));
// read string into temporary buffer
std::vector<char> tmp;
tmp.resize(length+1);
UnpackRaw(&tmp[0],length);
tmp[length]='\0';
// assign to output
result=&tmp[0];
}

56
source/terrain/FileUnpacker.h Executable file
View File

@ -0,0 +1,56 @@
///////////////////////////////////////////////////////////////////////////////
//
// Name: FileUnpacker.h
// Author: Rich Cross
// Contact: rich@wildfiregames.com
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _FILEUNPACKER_H
#define _FILEUNPACKER_H
#include <vector>
#include "res/res.h"
#include "CStr.h"
////////////////////////////////////////////////////////////////////////////////
// CFileUnpacker: class to assist in reading of binary files
class CFileUnpacker
{
public:
// exceptions thrown by class
class CError { };
class CFileTypeError : public CError { };
class CFileVersionError : public CError { };
class CFileOpenError : public CError { };
class CFileReadError : public CError { };
class CFileEOFError : public CError { };
public:
// constructor
CFileUnpacker();
// Read: open and read in given file, check magic bits against those given; throw
// variety of exceptions for missing files etc
void Read(const char* filename,const char magicstr[4]);
// GetVersion: return stored file version
u32 GetVersion() const { return m_Version; }
// UnpackRaw: unpack given number of bytes from the input stream into the given array
// - throws CFileEOFError if the end of the data stream is reached before the given
// number of bytes have been read
void UnpackRaw(void* rawdata,u32 rawdatalen);
// UnpackString: unpack a string from the raw data stream
void UnpackString(CStr& result);
private:
// the input data stream read from file and used during unpack operations
std::vector<u8> m_Data;
// current unpack position in stream
u32 m_UnpackPos;
// version of the file currently being read
u32 m_Version;
};
#endif

View File

@ -1,156 +0,0 @@
// HBV.h
//
// (c) Rich Cross, 2000
#ifndef __HBV_H
#define __HBV_H
#include <algorithm>
#include <vector>
#include "HBVNode.h"
#include "Aggregate.h"
class Point3;
class Vector3;
template <class T>
class HBV
{
public:
HBV();
~HBV();
Geometry* clone() const;
void open();
void add(const T& element);
void addMany(const std::vector<T>& v);
void close();
bool vectorIntersect(const Point3& origin,const Vector3& dir,float& dist) const;
void getBounds(BoundingBox& result) const;
void getNormal(const Point3& pt,Vector3& result) const;
void getUV(const Point3& pt,float& u,float& v) const;
const T& getIntersectedElement() const;
private:
mutable T _cachedElement;
HBVNode<T>* _root;
std::vector<T>* _elementList;
};
#include "common.h"
#include "HBVLeaf.h"
template <class T>
HBV<T>::HBV() : _root(0), _elementList(0), _cachedElement(0)
{
}
template <class T>
HBV<T>::~HBV()
{
assert(_elementList==0);
delete _root;
}
template <class T>
Geometry* HBV<T>::clone() const
{
assert(0);
return 0;
}
template <class T>
void HBV<T>::open()
{
_elementList=new std::vector<T>();
}
template <class T>
void HBV<T>::add(const T& element)
{
assert(_elementList!=0);
_elementList->push_back(element);
}
template <class T>
void HBV<T>::addMany(const std::vector<T>& v)
{
assert(_elementList!=0);
for (int i=0;i<v.size();i++)
_elementList->push_back(v.at(i));
}
template <class T>
void HBV<T>::close()
{
std::random_shuffle(_elementList->begin(),_elementList->end());
for (int i=0;i<_elementList->size();i++) {
T element=_elementList->at(i);
HBVLeaf<T> *leaf=new HBVLeaf<T>(element);
if (_root) {
_root->addLeaf(leaf);
while (_root->getParent())
_root=_root->getParent();
}
else
_root=leaf;
}
_elementList->clear();
delete _elementList;
_elementList=0;
}
template <class T>
bool HBV<T>::vectorIntersect(const Point3& origin,const Vector3& dir,float& dist) const
{
T element;
_cachedElement=0;
int result=_root->vectorIntersect(origin,dir,dist,element);
if (result) {
_cachedElement=element;
return true;
}
return false;
}
template <class T>
void HBV<T>::getBounds(BoundingBox& result) const
{
result=_root->getBounds();
}
template <class T>
void HBV<T>::getNormal(const Point3& pt,Vector3& result) const
{
assert(_cachedElement!=0);
_cachedElement->getNormal(pt,result);
}
template <class T>
void HBV<T>::getUV(const Point3& pt,float& u,float& v) const
{
assert(_cachedElement!=0);
_cachedElement->getUV(pt,u,v);
}
template <class T>
const T& HBV<T>::getIntersectedElement() const
{
assert(_cachedElement!=0);
return _cachedElement;
}
#endif

View File

@ -1,44 +1,47 @@
//---------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////////
// //
// Name: LightEnv.h // Name: LightEnv.h
// Last Update: 25/11/03 // Author: Rich Cross
// Author: Rich Cross // Contact: rich@wildfiregames.com
// Contact: rich@0ad.wildfiregames.com //
// // Description: class describing current lighting environment -
// Description: class describing current lighting environment - // at the minute, this is only sunlight and ambient light
// at the minute, this is only sunlight and ambient light // parameters; will be extended to handle dynamic lights at some
// parameters; will be extended to handle dynamic lights at some // later date
// later date //
//---------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////////
#ifndef __LIGHTENV_H #ifndef __LIGHTENV_H
#define __LIGHTENV_H #define __LIGHTENV_H
#include "Color.h" #include "Color.h"
#include "Vector3D.h" #include "Vector3D.h"
class CLightEnv ///////////////////////////////////////////////////////////////////////////////
{ // CLightEnv: description of a lighting environment - contains all the
public: // necessary parameters for representation of the lighting within a scenario
RGBColor m_SunColor; class CLightEnv
float m_Elevation; {
float m_Rotation; public:
RGBColor m_TerrainAmbientColor; RGBColor m_SunColor;
RGBColor m_UnitsAmbientColor; float m_Elevation;
float m_Rotation;
// get sun direction from a rotation and elevation; defined such that: RGBColor m_TerrainAmbientColor;
// 0 rotation = (0,0,1) RGBColor m_UnitsAmbientColor;
// PI/2 rotation = (-1,0,0)
// 0 elevation = (0,0,0) // get sun direction from a rotation and elevation; defined such that:
// PI/2 elevation = (0,-1,0) // 0 rotation = (0,0,1)
void GetSunDirection(CVector3D& lightdir) const { // PI/2 rotation = (-1,0,0)
lightdir.Y=-float(sin(m_Elevation)); // 0 elevation = (0,0,0)
float scale=1+lightdir.Y; // PI/2 elevation = (0,-1,0)
lightdir.X=scale*float(sin(m_Rotation)); void GetSunDirection(CVector3D& lightdir) const {
lightdir.Z=scale*float(cos(m_Rotation)); lightdir.Y=-float(sin(m_Elevation));
lightdir.Normalize(); float scale=1+lightdir.Y;
} lightdir.X=scale*float(sin(m_Rotation));
}; lightdir.Z=scale*float(cos(m_Rotation));
lightdir.Normalize();
#endif }
};
#endif

35
source/terrain/MapIO.h Executable file
View File

@ -0,0 +1,35 @@
#ifndef _MAPIO_H
#define _MAPIO_H
class CMapIO
{
public:
// current file version given to saved maps
enum { FILE_VERSION = 2 };
// supported file read version - file with version less than this will be reject
enum { FILE_READ_VERSION = 1 };
#pragma pack(push, 1)
// description of a tile for I/O purposes
struct STileDesc {
// index into the texture array of first texture on tile
u16 m_Tex1Index;
// index into the texture array of second texture; (0xffff) if none
u16 m_Tex2Index;
// priority
u32 m_Priority;
};
// description of an object for I/O purposes
struct SObjectDesc {
// index into the object array
u16 m_ObjectIndex;
// transformation matrix
float m_Transform[16];
};
#pragma pack(pop)
};
#endif

171
source/terrain/MapReader.cpp Executable file
View File

@ -0,0 +1,171 @@
// 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 "terrain/Model.h"
#include "terrain/Terrain.h"
#include "terrain/TextureManager.h"
extern CTerrain g_Terrain;
extern CLightEnv g_LightEnv;
#include <set>
#include <stdio.h>
// CMapReader constructor: nothing to do at the minute
CMapReader::CMapReader()
{
}
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful
void CMapReader::LoadMap(const char* filename)
{
CFileUnpacker unpacker;
unpacker.Read(filename,"PSMP");
// check version
if (unpacker.GetVersion()<FILE_READ_VERSION) {
throw CFileUnpacker::CFileVersionError();
}
// unpack the data
UnpackMap(unpacker);
// finally, apply data to the world
ApplyData(unpacker);
}
// UnpackMap: unpack the given data from the raw data stream into local variables
void CMapReader::UnpackMap(CFileUnpacker& unpacker)
{
// now unpack everything into local data
UnpackTerrain(unpacker);
UnpackObjects(unpacker);
if (unpacker.GetVersion()>=2) {
UnpackLightEnv(unpacker);
}
}
// UnpackLightEnv: unpack lighting parameters from input stream
void CMapReader::UnpackLightEnv(CFileUnpacker& unpacker)
{
unpacker.UnpackRaw(&m_LightEnv.m_SunColor,sizeof(m_LightEnv.m_SunColor));
unpacker.UnpackRaw(&m_LightEnv.m_Elevation,sizeof(m_LightEnv.m_Elevation));
unpacker.UnpackRaw(&m_LightEnv.m_Rotation,sizeof(m_LightEnv.m_Rotation));
unpacker.UnpackRaw(&m_LightEnv.m_TerrainAmbientColor,sizeof(m_LightEnv.m_TerrainAmbientColor));
unpacker.UnpackRaw(&m_LightEnv.m_UnitsAmbientColor,sizeof(m_LightEnv.m_UnitsAmbientColor));
}
// UnpackObjects: unpack world objects from input stream
void CMapReader::UnpackObjects(CFileUnpacker& unpacker)
{
// unpack object types
u32 numObjTypes;
unpacker.UnpackRaw(&numObjTypes,sizeof(numObjTypes));
m_ObjectTypes.resize(numObjTypes);
for (uint i=0;i<numObjTypes;i++) {
CStr objname;
unpacker.UnpackString(objname);
CObjectEntry* object=g_ObjMan.FindObject((const char*) objname);
m_ObjectTypes[i]=object;
}
// unpack object data
u32 numObjects;
unpacker.UnpackRaw(&numObjects,sizeof(numObjects));
m_Objects.resize(numObjects);
unpacker.UnpackRaw(&m_Objects[0],sizeof(SObjectDesc)*numObjects);
}
// UnpackTerrain: unpack the terrain from the end of the input data stream
// - data: map size, heightmap, list of textures used by map, texture tile assignments
void CMapReader::UnpackTerrain(CFileUnpacker& unpacker)
{
// unpack map size
unpacker.UnpackRaw(&m_MapSize,sizeof(m_MapSize));
// unpack heightmap
u32 verticesPerSide=m_MapSize*PATCH_SIZE+1;
m_Heightmap.resize(SQR(verticesPerSide));
unpacker.UnpackRaw(&m_Heightmap[0],SQR(verticesPerSide)*sizeof(u16));
// unpack texture names; find handle for each texture
u32 numTextures;
unpacker.UnpackRaw(&numTextures,sizeof(numTextures));
m_TerrainTextures.reserve(numTextures);
for (uint i=0;i<numTextures;i++) {
CStr texturename;
unpacker.UnpackString(texturename);
Handle handle;
CTextureEntry* texentry=g_TexMan.FindTexture(texturename);
if (!texentry) {
// ack; mismatch between texture datasets?
handle=0;
} else {
handle=texentry->m_Handle;
}
m_TerrainTextures.push_back(handle);
}
// unpack tile data
u32 tilesPerSide=m_MapSize*PATCH_SIZE;
m_Tiles.resize(SQR(tilesPerSide));
unpacker.UnpackRaw(&m_Tiles[0],sizeof(STileDesc)*m_Tiles.size());
}
// ApplyData: take all the input data, and rebuild the scene from it
void CMapReader::ApplyData(CFileUnpacker& unpacker)
{
// initialise the terrain
g_Terrain.Initialize(m_MapSize,&m_Heightmap[0]);
// setup the textures on the minipatches
STileDesc* tileptr=&m_Tiles[0];
for (u32 j=0;j<m_MapSize;j++) {
for (u32 i=0;i<m_MapSize;i++) {
for (u32 m=0;m<PATCH_SIZE;m++) {
for (u32 k=0;k<PATCH_SIZE;k++) {
CMiniPatch& mp=g_Terrain.GetPatch(i,j)->m_MiniPatches[m][k];
mp.Tex1=m_TerrainTextures[tileptr->m_Tex1Index];
mp.Tex1Priority=tileptr->m_Priority;
tileptr++;
}
}
}
}
// empty out existing units
g_UnitMan.DeleteAll();
// add new objects
for (u32 i=0;i<m_Objects.size();i++) {
CObjectEntry* objentry=m_ObjectTypes[m_Objects[i].m_ObjectIndex];
if (objentry && objentry->m_Model) {
// create new unit
CUnit* unit=new CUnit;
unit->m_Object=objentry;
unit->m_Model=objentry->m_Model ? objentry->m_Model->Clone() : 0;
CMatrix3D transform;
memcpy(&transform._11,m_Objects[i].m_Transform,sizeof(float)*16);
unit->m_Model->SetTransform(transform);
// add this unit to list of units stored in unit manager
g_UnitMan.AddUnit(unit);
}
}
if (unpacker.GetVersion()>=2) {
// copy over the lighting parameters
g_LightEnv=m_LightEnv;
}
}

48
source/terrain/MapReader.h Executable file
View File

@ -0,0 +1,48 @@
#ifndef _MAPREADER_H
#define _MAPREADER_H
#include "MapIO.h"
#include "CStr.h"
#include "terrain/LightEnv.h"
#include "terrain/FileUnpacker.h"
class CObjectEntry;
class CMapReader : public CMapIO
{
public:
// constructor
CMapReader();
// LoadMap: try to load the map from given file; reinitialise the scene to new data if successful
void LoadMap(const char* filename);
private:
// UnpackMap: unpack the given data from the raw data stream into local variables
void UnpackMap(CFileUnpacker& unpacker);
// UnpackTerrain: unpack the terrain from the input stream
void UnpackTerrain(CFileUnpacker& unpacker);
// UnpackObjects: unpack world objects from the input stream
void UnpackObjects(CFileUnpacker& unpacker);
// UnpackObjects: unpack lighting parameters from the input stream
void UnpackLightEnv(CFileUnpacker& unpacker);
// ApplyData: take all the input data, and rebuild the scene from it
void ApplyData(CFileUnpacker& unpacker);
// size of map
u32 m_MapSize;
// heightmap for map
std::vector<u16> m_Heightmap;
// list of terrain textures used by map
std::vector<Handle> m_TerrainTextures;
// tile descriptions for each tile
std::vector<STileDesc> m_Tiles;
// list of object types used by map
std::vector<CObjectEntry*> m_ObjectTypes;
// descriptions for each objects
std::vector<SObjectDesc> m_Objects;
// lightenv stored in file
CLightEnv m_LightEnv;
};
#endif

226
source/terrain/MapWriter.cpp Executable file
View File

@ -0,0 +1,226 @@
// switch off warnings before including stl files
#pragma warning(disable : 4786) // identifier truncated to 255 chars
#include "Types.h"
#include "MapWriter.h"
#include "UnitManager.h"
#include "ObjectManager.h"
#include "terrain/Model.h"
#include "terrain/Terrain.h"
#include "terrain/LightEnv.h"
#include "terrain/TextureManager.h"
extern CTerrain g_Terrain;
extern CLightEnv g_LightEnv;
#include <set>
#include <stdio.h>
///////////////////////////////////////////////////////////////////////////////////////////////////
// CMapWriter constructor: nothing to do at the minute
CMapWriter::CMapWriter()
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// SaveMap: try to save the current map to the given file
void CMapWriter::SaveMap(const char* filename)
{
CFilePacker packer;
// build necessary data
PackMap(packer);
// write it out
packer.Write(filename,FILE_VERSION,"PSMP");
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// GetHandleIndex: return the index of the given handle in the given list; or 0xffff if
// handle isn't in list
static u16 GetHandleIndex(const Handle handle,const std::vector<Handle>& handles)
{
for (uint i=0;i<handles.size();i++) {
if (handles[i]==handle) {
return i;
}
}
return 0xffff;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// GetObjectIndex: return the index of the given object in the given list; or 0xffff if
// object isn't in list
static u16 GetObjectIndex(const CObjectEntry* object,const std::vector<CObjectEntry*>& objects)
{
for (uint i=0;i<objects.size();i++) {
if (objects[i]==object) {
return i;
}
}
return 0xffff;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// EnumTerrainTextures: build lists of textures used by map, and tile descriptions for
// each tile on the terrain
void CMapWriter::EnumTerrainTextures(std::vector<CStr>& textures,
std::vector<STileDesc>& tiles)
{
// the list of all handles in use
std::vector<Handle> handles;
// resize tile array to required size
tiles.resize(SQR(g_Terrain.GetVerticesPerSide()-1));
STileDesc* tileptr=&tiles[0];
// now iterate through all the tiles
u32 mapsize=g_Terrain.GetPatchesPerSide();
for (u32 j=0;j<mapsize;j++) {
for (u32 i=0;i<mapsize;i++) {
for (u32 m=0;m<PATCH_SIZE;m++) {
for (u32 k=0;k<PATCH_SIZE;k++) {
CMiniPatch& mp=g_Terrain.GetPatch(i,j)->m_MiniPatches[m][k];
u16 index=u16(GetHandleIndex(mp.Tex1,handles));
if (index==0xffff) {
index=handles.size();
handles.push_back(mp.Tex1);
}
tileptr->m_Tex1Index=index;
tileptr->m_Tex2Index=0xffff;
tileptr->m_Priority=mp.Tex1Priority;
tileptr++;
}
}
}
}
// now find the texture names for each handle
for (uint i=0;i<handles.size();i++) {
CStr texturename;
CTextureEntry* texentry=g_TexMan.FindTexture(handles[i]);
if (!texentry) {
// uh-oh, this shouldn't happen; set texturename to empty string
texturename="";
} else {
texturename=texentry->m_Name;
}
textures.push_back(texturename);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// EnumObjects: build lists of object types used by map, and object descriptions for
// each object in the world
void CMapWriter::EnumObjects(std::vector<CStr>& objectTypes,std::vector<SObjectDesc>& objects)
{
// the list of all object entries in use
std::vector<CObjectEntry*> objectsInUse;
// resize object array to required size
const std::vector<CUnit*>& units=g_UnitMan.GetUnits();
objects.resize(units.size());
SObjectDesc* objptr=&objects[0];
// now iterate through all the units
for (u32 j=0;j<units.size();j++) {
CUnit* unit=units[j];
u16 index=u16(GetObjectIndex(unit->m_Object,objectsInUse));
if (index==0xffff) {
index=objectsInUse.size();
objectsInUse.push_back(unit->m_Object);
}
objptr->m_ObjectIndex=index;
memcpy(objptr->m_Transform,&unit->m_Model->GetTransform()._11,sizeof(float)*16);
objptr++;
}
// now build outgoing objectTypes array
for (uint i=0;i<objectsInUse.size();i++) {
objectTypes.push_back(objectsInUse[i]->m_Name);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// PackMap: pack the current world into a raw data stream
void CMapWriter::PackMap(CFilePacker& packer)
{
// now pack everything up
PackTerrain(packer);
PackObjects(packer);
PackLightEnv(packer);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// PackLightEnv: pack lighting parameters onto the end of the output data stream
void CMapWriter::PackLightEnv(CFilePacker& packer)
{
packer.PackRaw(&g_LightEnv.m_SunColor,sizeof(g_LightEnv.m_SunColor));
packer.PackRaw(&g_LightEnv.m_Elevation,sizeof(g_LightEnv.m_Elevation));
packer.PackRaw(&g_LightEnv.m_Rotation,sizeof(g_LightEnv.m_Rotation));
packer.PackRaw(&g_LightEnv.m_TerrainAmbientColor,sizeof(g_LightEnv.m_TerrainAmbientColor));
packer.PackRaw(&g_LightEnv.m_UnitsAmbientColor,sizeof(g_LightEnv.m_UnitsAmbientColor));
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// PackObjects: pack world objects onto the end of the output data stream
// - data: list of objects types used by map, list of object descriptions
void CMapWriter::PackObjects(CFilePacker& packer)
{
// the list of object types used by map
std::vector<CStr> objectTypes;
// descriptions of each object
std::vector<SObjectDesc> objects;
// build lists by scanning through the world
EnumObjects(objectTypes,objects);
// pack object types
u32 numObjTypes=objectTypes.size();
packer.PackRaw(&numObjTypes,sizeof(numObjTypes));
for (uint i=0;i<numObjTypes;i++) {
packer.PackString(objectTypes[i]);
}
// pack object data
u32 numObjects=objects.size();
packer.PackRaw(&numObjects,sizeof(numObjects));
packer.PackRaw(&objects[0],sizeof(SObjectDesc)*numObjects);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// PackTerrain: pack the terrain onto the end of the output data stream
// - data: map size, heightmap, list of textures used by map, texture tile assignments
void CMapWriter::PackTerrain(CFilePacker& packer)
{
// pack map size
u32 mapsize=g_Terrain.GetPatchesPerSide();
packer.PackRaw(&mapsize,sizeof(mapsize));
// pack heightmap
packer.PackRaw(g_Terrain.GetHeightMap(),sizeof(u16)*SQR(g_Terrain.GetVerticesPerSide()));
// the list of textures used by map
std::vector<CStr> terrainTextures;
// descriptions of each tile
std::vector<STileDesc> tiles;
// build lists by scanning through the terrain
EnumTerrainTextures(terrainTextures,tiles);
// pack texture names
u32 numTextures=terrainTextures.size();
packer.PackRaw(&numTextures,sizeof(numTextures));
for (uint i=0;i<numTextures;i++) {
packer.PackString(terrainTextures[i]);
}
// pack tile data
packer.PackRaw(&tiles[0],sizeof(STileDesc)*tiles.size());
}

36
source/terrain/MapWriter.h Executable file
View File

@ -0,0 +1,36 @@
#ifndef _MAPWRITER_H
#define _MAPWRITER_H
#include <vector>
#include "MapIO.h"
#include "CStr.h"
#include "terrain/FilePacker.h"
class CMapWriter : public CMapIO
{
public:
// constructor
CMapWriter();
// SaveMap: try to save the current map to the given file
void SaveMap(const char* filename);
private:
// PackMap: pack the current world into a raw data stream
void PackMap(CFilePacker& packer);
// PackTerrain: pack the terrain onto the end of the data stream
void PackTerrain(CFilePacker& packer);
// PackObjects: pack world objects onto the end of the output data stream
void PackObjects(CFilePacker& packer);
// PackLightEnv: pack lighting parameters onto the end of the output data stream
void PackLightEnv(CFilePacker& packer);
// EnumTerrainTextures: build lists of textures used by map, and indices into this list
// for each tile on the terrain
void EnumTerrainTextures(std::vector<CStr>& textures,std::vector<STileDesc>& tileIndices);
// EnumObjects: build lists of object types used by map, and object descriptions for
// each object in the world
void EnumObjects(std::vector<CStr>& objectTypes,std::vector<SObjectDesc>& objects);
};
#endif

View File

@ -1,27 +1,29 @@
//*********************************************************** //***********************************************************
// //
// Name: MathUtil.H // Name: MathUtil.H
// Last Update: 28/1/02 // Last Update: 28/1/02
// Author: Poya Manouchehri // Author: Poya Manouchehri
// //
// Description: This file contains some maths related // Description: This file contains some maths related
// utility macros and fucntions. // utility macros and fucntions.
// //
//*********************************************************** //***********************************************************
#ifndef MATHUTIL_H #ifndef MATHUTIL_H
#define MATHUTIL_H #define MATHUTIL_H
#ifndef PI #ifndef PI
#define PI 3.14159265358979323846f #define PI 3.14159265358979323846f
#endif #endif
#define DEGTORAD(a) ((a) * (PI/180.0f)) #define DEGTORAD(a) ((a) * (PI/180.0f))
#define RADTODEG(a) ((a) * (180.0f/PI)) #define RADTODEG(a) ((a) * (180.0f/PI))
#define SQR(x) ((x) * (x)) #define SQR(x) ((x) * (x))
#define MAX3(a,b,c) ( MAX (MAX(a,b), c) ) //#define MAX(a,b) ((a < b) ? (b) : (a))
#define ABS(a) ((a > 0) ? (a) : (-a)) //#define MIN(a,b) ((a < b) ? (a) : (b))
#define MAX3(a,b,c) ( MAX (MAX(a,b), c) )
//extern unsigned int F2DW (float f); #define ABS(a) ((a > 0) ? (a) : (-a))
#endif //extern unsigned int F2DW (float f);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,108 +1,120 @@
//*********************************************************** #ifndef __MATRIX3D_H
// #define __MATRIX3D_H
// Name: Matrix3D.H
// Last Update: 31/1/02 #include <math.h>
// Author: Poya Manouchehri #include "Vector3D.h"
// #include "Vector4D.h"
// Description: A Matrix class used for holding and
// manipulating transformation info. class CQuaternion;
//
//*********************************************************** /////////////////////////////////////////////////////////////////////////
// CMatrix3D: a 4x4 matrix class for common operations in 3D
#ifndef MATRIX3D_H class CMatrix3D
#define MATRIX3D_H {
public:
#include <math.h> // the matrix data itself - accessible as either longhand names
#include "Vector3D.h" // or via a flat array
#include "Vector4D.h" union {
struct {
class CMatrix3D float _11, _21, _31, _41;
{ float _12, _22, _32, _42;
public: float _13, _23, _33, _43;
union { float _14, _24, _34, _44;
struct { };
float _11, _12, _13, _14; float _data[16];
float _21, _22, _23, _24; };
float _31, _32, _33, _34;
float _41, _42, _43, _44; public:
}; // constructors
float _data[16]; CMatrix3D();
}; CMatrix3D(float a11,float a12,float a13,float a14,float a21,float a22,float a23,float a24,
float a31,float a32,float a33,float a34,float a41,float a42,float a43,float a44);
public:
CMatrix3D (); // accessors to individual elements of matrix
CMatrix3D (float a11,float a12,float a13,float a14,float a21,float a22,float a23,float a24, float& operator()(int col,int row) {
float a31,float a32,float a33,float a34,float a41,float a42,float a43,float a44); return _data[row*4+col];
}
// accessors to individual elements of matrix const float& operator()(int col,int row) const {
float& operator()(int row,int col) { return _data[row*4+col];
return _data[row*4+col]; }
}
const float& operator()(int row,int col) const { // matrix multiplication
return _data[row*4+col]; CMatrix3D operator*(const CMatrix3D &matrix) const;
} // matrix multiplication/assignment
CMatrix3D& operator*=(const CMatrix3D &matrix);
//Matrix multiplication // matrix scaling
CMatrix3D operator * (const CMatrix3D &matrix) const; CMatrix3D operator*(float f) const;
//Matrix multiplication/assignment // matrix scaling/assignment
CMatrix3D &operator *= (const CMatrix3D &matrix); CMatrix3D& operator*=(float f);
// matrix addition
//Sets the identity matrix CMatrix3D operator+(const CMatrix3D &matrix) const;
void SetIdentity (); // matrix addition/assignment
//Sets the zero matrix CMatrix3D& operator+=(const CMatrix3D &matrix);
void SetZero ();
// set this matrix to the identity matrix
//The following clear the matrix and set the void SetIdentity();
//rotation of each of the 3 axes // set this matrix to the zero matrix
void SetXRotation (float angle); void SetZero();
void SetYRotation (float angle);
void SetZRotation (float angle); // set this matrix to a rotation matrix for a rotation about X axis of given angle
void SetXRotation(float angle);
//The following apply a rotation to the matrix // set this matrix to a rotation matrix for a rotation about Y axis of given angle
//about each of the axes; void SetYRotation(float angle);
void RotateX (float angle); // set this matrix to a rotation matrix for a rotation about Z axis of given angle
void RotateY (float angle); void SetZRotation(float angle);
void RotateZ (float angle); // set this matrix to a rotation described by given quaternion
void SetRotation(const CQuaternion& quat);
//Sets the translation of the matrix
void SetTranslation (float x, float y, float z); // concatentate a rotation about the X axis onto this matrix
void SetTranslation (CVector3D &vector); void RotateX(float angle);
// concatentate a rotation about the Y axis onto this matrix
//Applies a translation to the matrix void RotateY(float angle);
void Translate (float x, float y, float z); // concatentate a rotation about the Z axis onto this matrix
void Translate (const CVector3D &vector); void RotateZ(float angle);
// concatentate a rotation described by given quaternion
CVector3D GetTranslation (); void Rotate(const CQuaternion& quat);
// calculate the inverse of this matrix, store in dst // set this matrix to given translation
void Invert(CMatrix3D& dst) const; void SetTranslation(float x, float y, float z);
void SetTranslation(const CVector3D& vector);
//Clears and sets the scaling of the matrix
void SetScaling (float x_scale, float y_scale, float z_scale); // concatenate given translation onto this matrix
//Scales the matrix void Translate(float x, float y, float z);
void Scale (float x_scale, float y_scale, float z_scale); void Translate(const CVector3D& vector);
//Returns the transpose of the matrix. For orthonormal // set this matrix to the given scaling matrix
//matrices, this is the same is the inverse matrix void SetScaling(float x_scale, float y_scale, float z_scale);
void GetTranspose(CMatrix3D& result) const;
// concatentate given scaling matrix onto this matrix
//Get a vector which points to the left of the matrix void Scale(float x_scale, float y_scale, float z_scale);
CVector3D GetLeft () const;
//Get a vector which points up from the matrix // calculate the inverse of this matrix, store in dst
CVector3D GetUp () const; void GetInverse(CMatrix3D& dst) const;
//Get a vector which points to front of the matrix
CVector3D GetIn () const; // calculate the transpose of this matrix, store in dst
void GetTranspose(CMatrix3D& dst) const;
//Set the matrix from two vectors (Up and In)
void SetFromUpIn (CVector3D &up, CVector3D &in, float scale); // return the translation component of this matrix
CVector3D GetTranslation() const;
public: //Vector manipulation methods // return left vector, derived from rotation
//Transform a 3D vector by this matrix CVector3D GetLeft() const;
CVector3D Transform (CVector3D &vector); // return up vector, derived from rotation
//Transform a 4D vector by this matrix CVector3D GetUp() const;
CVector4D Transform (const CVector4D &vector) const; // return forward vector, derived from rotation
//Only rotate (not translate) a vector by this matrix CVector3D GetIn() const;
CVector3D Rotate (CVector3D &vector);
}; // transform a 3D vector by this matrix
void Transform(const CVector3D &vector,CVector3D& result) const;
#endif CVector3D Transform(const CVector3D &vector) const;
// transform a 4D vector by this matrix
void Transform(const CVector4D &vector,CVector4D& result) const;
CVector4D Transform(const CVector4D &vector) const;
// rotate a vector by this matrix
void Rotate(const CVector3D& vector,CVector3D& result) const;
CVector3D Rotate(const CVector3D& vector) const;
// rotate a vector by the transpose of this matrix
void RotateTransposed(const CVector3D& vector,CVector3D& result) const;
CVector3D RotateTransposed(const CVector3D& vector) const;
};
#endif

View File

@ -1,21 +1,34 @@
#include "MiniPatch.h" ///////////////////////////////////////////////////////////////////////////////
#include "Patch.h" //
// Name: MiniPatch.h
CMiniPatch::CMiniPatch() // Author: Rich Cross
{ // Contact: rich@wildfiregames.com
Tex1 = 0; //
Tex1Priority = 0; ///////////////////////////////////////////////////////////////////////////////
m_Parent = NULL;
} #include "MiniPatch.h"
#include "Patch.h"
CMiniPatch::~CMiniPatch()
{ ///////////////////////////////////////////////////////////////////////////////
} // Constructor
CMiniPatch::CMiniPatch() : Tex1(0), Tex1Priority(0), m_Parent(0)
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; // 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;
}

View File

@ -1,29 +1,39 @@
#ifndef MINIPATCH_H ///////////////////////////////////////////////////////////////////////////////
#define MINIPATCH_H //
// Name: MiniPatch.h
#include "res/res.h" // Author: Rich Cross
// Contact: rich@wildfiregames.com
class CPatch; //
///////////////////////////////////////////////////////////////////////////////
class CMiniPatch
{ #ifndef _MINIPATCH_H
public: #define _MINIPATCH_H
CMiniPatch();
~CMiniPatch(); #include "res/res.h"
// get the index of this tile in the root terrain object; x,y in [0,MapSize) class CPatch;
void GetTileIndex(u32& x,u32& z);
///////////////////////////////////////////////////////////////////////////////
Handle Tex1; // CMiniPatch: definition of a single terrain tile
int Tex1Priority; class CMiniPatch
{
// Handle Tex2; public:
// Handle m_AlphaMap; // constructor
// unsigned int m_AlphaMapFlags; CMiniPatch();
// destructor
CPatch *m_Parent; ~CMiniPatch();
// STerrainVertex *m_pVertices;
}; // get the index of this tile in the root terrain object; x,y in [0,MapSize)
void GetTileIndex(u32& x,u32& z);
#endif 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

View File

@ -1,146 +1,169 @@
/************************************************************ ///////////////////////////////////////////////////////////////////////////////
* //
* File Name: Model.Cpp // Name: Model.cpp
* // Author: Rich Cross
* Description: CModel is a specific instance of a model. // Contact: rich@wildfiregames.com
* It contains a pointer to CModelDef, and //
* includes all instance information, such as ///////////////////////////////////////////////////////////////////////////////
* current animation pose.
* #include "Model.h"
************************************************************/ #include "Quaternion.h"
#include "Bound.h"
#include "Model.h"
#include "Quaternion.h" ///////////////////////////////////////////////////////////////////////////////
#include "Bound.h" // Constructor
CModel::CModel()
CModel::CModel() : m_pModelDef(0), m_Anim(0), m_AnimTime(0),
{ m_BoneMatrices(0), m_InvBoneMatrices(0)
m_pModelDef = NULL; {
m_pBonePoses = NULL; }
m_RenderData = 0;
} ///////////////////////////////////////////////////////////////////////////////
// Destructor
CModel::~CModel() CModel::~CModel()
{ {
Destroy(); ReleaseData();
} }
bool CModel::InitModel(CModelDef *modeldef) ///////////////////////////////////////////////////////////////////////////////
{ // ReleaseData: delete anything allocated by the model
m_pModelDef = modeldef; void CModel::ReleaseData()
{
m_pBonePoses = new CMatrix3D[m_pModelDef->GetNumBones()]; delete[] m_BoneMatrices;
delete[] m_InvBoneMatrices;
ClearPose(); }
return true; ///////////////////////////////////////////////////////////////////////////////
} // InitModel: setup model from given geometry
bool CModel::InitModel(CModelDef* modeldef)
void CModel::Destroy() {
{ // clean up any existing data first
m_pModelDef = NULL; ReleaseData();
if (m_pBonePoses) m_pModelDef = modeldef;
delete [] m_pBonePoses;
u32 numBones=modeldef->GetNumBones();
m_pBonePoses = NULL; if (numBones>0) {
} // allocate matrices for bone transformations
m_BoneMatrices=new CMatrix3D[numBones];
m_InvBoneMatrices=new CMatrix3D[numBones];
void CModel::SetPose (const char *anim_name, float time) // store default pose until animation assigned
{ CBoneState* defpose=modeldef->GetBones();
int AnimI = -1; for (uint i=0;i<numBones;i++) {
CMatrix3D& m=m_BoneMatrices[i];
for (int i=0; i<m_pModelDef->GetNumAnimations(); i++) m.SetIdentity();
{ m.Rotate(defpose[i].m_Rotation);
if ( strcmp(anim_name, m_pModelDef->GetAnimations()[i].m_Name) == 0 ) m.Translate(defpose[i].m_Translation);
{ m.GetInverse(m_InvBoneMatrices[i]);
AnimI = i; }
break; }
}
} return true;
}
if (AnimI == -1)
return; ///////////////////////////////////////////////////////////////////////////////
// SkinPoint: skin the given point using the given blend and bonestate data
SModelAnimation *pAnim = &m_pModelDef->GetAnimations()[AnimI]; static CVector3D SkinPoint(const CVector3D& pos,const SVertexBlend& blend,
const CBoneState* bonestates)
int StartI = (int)time; {
int EndI;// = (int)(time + 0.999999f); CVector3D result(0,0,0);
for (int i=0;i<SVertexBlend::SIZE && blend.m_Bone[i]!=0xff;i++) {
if ((float)StartI == time) CMatrix3D m;
EndI = StartI; m.SetIdentity();
else m.Rotate(bonestates[blend.m_Bone[i]].m_Rotation);
EndI = StartI+1; m.Translate(bonestates[blend.m_Bone[i]].m_Translation);
float factor = time - (float)StartI; CVector3D tmp=m.Transform(pos);
result+=tmp*blend.m_Weight[i];
if (EndI > pAnim->m_NumFrames-1) }
EndI = 0;
return result;
SModelAnimationFrame *pStartFrame = &m_pModelDef->GetAnimationFrames()[pAnim->m_FirstFrame + StartI]; }
SModelAnimationFrame *pEndFrame = &m_pModelDef->GetAnimationFrames()[pAnim->m_FirstFrame + EndI];
///////////////////////////////////////////////////////////////////////////////
for (i=0; i<m_pModelDef->GetNumBones(); i++) // CalcBound: calculate the world space bounds of this model
{ //
SModelAnimationKey *pKey1 = &m_pModelDef->GetAnimationKeys()[pStartFrame->m_FirstKey+i]; // TODO,RC 11/03/04: need to calculate (and store somewhere) the object space
SModelAnimationKey *pKey2 = &m_pModelDef->GetAnimationKeys()[pEndFrame->m_FirstKey+i]; // bounds, and then just retransform the bounds as necessary, rather than
// recalculating them from vertex data every time the transform changes
CVector3D Translation = pKey1->m_Translation + (pKey2->m_Translation - pKey1->m_Translation)*factor; void CModel::CalcBounds()
{
m_pBonePoses[i].SetIdentity(); m_Bounds.SetEmpty();
CQuaternion from, to, rotation; int numverts=m_pModelDef->GetNumVertices();
from.FromEularAngles (pKey1->m_Rotation.X, pKey1->m_Rotation.Y, pKey1->m_Rotation.Z); SModelVertex* verts=m_pModelDef->GetVertices();
to.FromEularAngles (pKey2->m_Rotation.X, pKey2->m_Rotation.Y, pKey2->m_Rotation.Z);
rotation.Slerp (from, to, factor); u32 numbones=m_pModelDef->GetNumBones();
if (numbones>0) {
m_pBonePoses[i] = rotation.ToMatrix(); // Boned object: tricky to get an ideal bound - for the minute, just use the bound of
// the reference pose. There's no guarantee that when animations are applied to the
m_pBonePoses[i].Translate(Translation); // model, the bounds will be within this bound - ideally, we want the bound of the
// object to be the union of the bounds of the model for each animation
int Parent = m_pModelDef->GetBones()[i].m_Parent; for (int i=0;i<numverts;i++) {
CVector3D tmp=SkinPoint(verts[i].m_Coords,verts[i].m_Blend,m_pModelDef->GetBones());
if (Parent > -1) m_Bounds+=m_Transform.Transform(tmp);
m_pBonePoses[i] = m_pBonePoses[Parent] * m_pBonePoses[i]; }
} } else {
} for (int i=0;i<numverts;i++) {
m_Bounds+=m_Transform.Transform(verts[i].m_Coords);
void CModel::ClearPose() }
{ }
//for each bone, set the bone's pose to the intial pose }
for (int i=0; i<m_pModelDef->GetNumBones(); i++)
m_pBonePoses[i] = m_pModelDef->GetBones()[i].m_Absolute; ///////////////////////////////////////////////////////////////////////////////
} // Update: update this model by the given time, in seconds
void CModel::Update(float time)
{
void RotateX (CMatrix3D *mat, float angle1, float angle2, float factor) // convert to ms
{ time*=1000;
float Cos = cosf(angle1) + (cosf(angle2)-cosf(angle1))*factor;
float Sin = sinf(angle1) + (sinf(angle2)-cosf(angle1))*factor; if (m_Anim && m_BoneMatrices) {
m_AnimTime+=time;
CMatrix3D RotX;
float duration=m_Anim->GetDuration();
RotX._11=1.0f; RotX._12=0.0f; RotX._13=0.0f; RotX._14=0.0f; if (m_AnimTime>duration) {
RotX._21=0.0f; RotX._22=Cos; RotX._23=-Sin; RotX._24=0.0f; m_AnimTime=(float) fmod(m_AnimTime,duration);
RotX._31=0.0f; RotX._32=Sin; RotX._33=Cos; RotX._34=0.0f; }
RotX._41=0.0f; RotX._42=0.0f; RotX._43=0.0f; RotX._44=1.0f;
m_Anim->BuildBoneMatrices(m_AnimTime,m_BoneMatrices);
*mat = RotX * (*mat); for (int i=0;i<m_pModelDef->GetNumBones();i++) {
} m_BoneMatrices[i].GetInverse(m_InvBoneMatrices[i]);
}
void CModel::CalcBounds(CBound& bound)
{ if (m_RenderData) m_RenderData->m_UpdateFlags|=RENDERDATA_UPDATE_VERTICES;
bound.SetEmpty(); }
}
for (int i=0; i<m_pModelDef->GetNumVertices(); i++)
{ /////////////////////////////////////////////////////////////////////////////////////
SModelVertex *pVertex = &m_pModelDef->GetVertices()[i]; // SetAnimation: set the given animation as the current animation on this model;
CVector3D coord; // return false on error, else true
if (pVertex->m_Bone!=-1) { bool CModel::SetAnimation(CSkeletonAnim* anim)
bound+=GetBonePoses()[pVertex->m_Bone].Transform(pVertex->m_Coords); {
} else { if (anim) {
bound+=pVertex->m_Coords; if (!m_BoneMatrices) {
} // not boned, can't animate
} return false;
} }
if (anim->GetNumKeys()!=m_pModelDef->GetNumBones()) {
// mismatch between models skeleton and animations skeleton
return false;
}
}
m_AnimTime=0;
m_Anim=anim;
return true;
}
/////////////////////////////////////////////////////////////////////////////////////
// Clone: return a clone of this model
CModel* CModel::Clone() const
{
CModel* clone=new CModel;
clone->InitModel(m_pModelDef);
clone->SetTexture(m_Texture);
clone->SetAnimation(m_Anim);
return clone;
}

View File

@ -1,52 +1,74 @@
/************************************************************ ///////////////////////////////////////////////////////////////////////////////
* //
* File Name: Model.H // Name: Model.cpp
* // Author: Rich Cross
* Description: CModel is a specific instance of a model. // Contact: rich@wildfiregames.com
* It contains a pointer to CModelDef, and //
* includes all instance information, such as ///////////////////////////////////////////////////////////////////////////////
* current animation pose.
* #ifndef _MODEL_H
************************************************************/ #define _MODEL_H
#ifndef MODEL_H #include "Texture.h"
#define MODEL_H #include "ModelDef.h"
#include "RenderableObject.h"
#include "Texture.h"
#include "ModelDef.h"
#include "RenderableObject.h" ///////////////////////////////////////////////////////////////////////////////
// CModel: basically, a mesh object - holds the texturing and skinning
// information for a model in game
class CBound; class CModel : public CRenderableObject
{
class CModel public:
{ // constructor
public: CModel();
CModel(); // destructor
~CModel(); ~CModel();
bool InitModel(CModelDef *modeldef); // setup model from given geometry
void Destroy(); bool InitModel(CModelDef *modeldef);
// calculate the world space bounds of this model
void SetPose (const char *anim_name, float time); void CalcBounds();
void ClearPose (); // update this model's state; 'time' is the time since the last update, in MS
void Update(float time);
void CalcBounds(CBound& bound);
// get the model's geometry data
CRenderData* m_RenderData; CModelDef *GetModelDef() { return m_pModelDef; }
//access functions // set the model's texture
public: void SetTexture(const CTexture& tex) { m_Texture=tex; }
CModelDef *GetModelDef() { return m_pModelDef; } // get the model's texture
CMatrix3D *GetBonePoses() { return m_pBonePoses; } CTexture* GetTexture() { return &m_Texture; }
void SetTexture(const CTexture& tex) { m_Texture=tex; } // set the given animation as the current animation on this model
CTexture* GetTexture() { return &m_Texture; } bool SetAnimation(CSkeletonAnim* anim);
// get the currently playing animation, if any
protected: CSkeletonAnim* GetAnimation() { return m_Anim; }
CTexture m_Texture;
CModelDef *m_pModelDef; // return the models bone matrices
CMatrix3D *m_pBonePoses; //describes the current pose for each bone const CMatrix3D* GetBoneMatrices() { return m_BoneMatrices; }
}; // return the models inverted bone matrices
const CMatrix3D* GetInvBoneMatrices() { return m_InvBoneMatrices; }
#endif
// return a clone of this model
CModel* Clone() const;
private:
// delete anything allocated by the model
void ReleaseData();
// texture used by model
CTexture m_Texture;
// pointer to the model's raw 3d data
CModelDef* m_pModelDef;
// animation currently playing on this model, if any
CSkeletonAnim* m_Anim;
// time (in MS) into the current animation
float m_AnimTime;
// current state of all bones on this model; null if associated modeldef isn't skeletal
CMatrix3D* m_BoneMatrices;
// inverse of all the above matrices
CMatrix3D* m_InvBoneMatrices;
};
#endif

View File

@ -1,112 +1,90 @@
/************************************************************ ///////////////////////////////////////////////////////////////////////////////
* //
* File Name: ModelDef.Cpp // Name: ModelDef.cpp
* // Author: Rich Cross
* Description: CModelDef is essentially a CModelFile, except // Contact: rich@wildfiregames.com
* that the data is stored in a more convenient //
* way. To create a CModelDef, call ///////////////////////////////////////////////////////////////////////////////
* CModelFile::ReadModelDef();
* #include "ModelDef.h"
************************************************************/ #include "FilePacker.h"
#include "FileUnpacker.h"
#include "ModelDef.h"
///////////////////////////////////////////////////////////////////////////////
CModelDef::CModelDef() // CModelDef Constructor
{ CModelDef::CModelDef()
m_pVertices = NULL; : m_pVertices(0), m_NumVertices(0), m_pFaces(0), m_NumFaces(0), m_Bones(0), m_NumBones(0)
m_pFaces = NULL; {
m_pBones = NULL; }
m_pAnimationKeys = NULL;
m_pAnimationFrames = NULL; ///////////////////////////////////////////////////////////////////////////////
m_pAnimations = NULL; // CModelDef Destructor
CModelDef::~CModelDef()
m_NumVertices = 0; {
m_NumFaces = 0; delete[] m_pVertices;
m_NumBones = 0; delete[] m_pFaces;
m_NumAnimationKeys = 0; delete[] m_Bones;
m_NumAnimationFrames = 0; }
m_NumAnimations = 0;
}
///////////////////////////////////////////////////////////////////////////////
CModelDef::~CModelDef() // Load: read and return a new CModelDef initialised with data from given file
{ CModelDef* CModelDef::Load(const char* filename)
Destroy(); {
} CFileUnpacker unpacker;
void CModelDef::Destroy() // read everything in from file
{ unpacker.Read(filename,"PSMD");
if (m_pVertices)
delete [] m_pVertices; // check version
if (m_pFaces) if (unpacker.GetVersion()<FILE_READ_VERSION) {
delete [] m_pFaces; throw CFileUnpacker::CFileVersionError();
if (m_pBones) }
delete [] m_pBones;
if (m_pAnimationKeys) CModelDef* mdef=new CModelDef;
delete [] m_pAnimationKeys; try {
if (m_pAnimationFrames) // now unpack everything
delete [] m_pAnimationFrames; unpacker.UnpackRaw(&mdef->m_NumVertices,sizeof(mdef->m_NumVertices));
if (m_pAnimations) mdef->m_pVertices=new SModelVertex[mdef->m_NumVertices];
delete [] m_pAnimations; unpacker.UnpackRaw(mdef->m_pVertices,sizeof(SModelVertex)*mdef->m_NumVertices);
m_pVertices = NULL; unpacker.UnpackRaw(&mdef->m_NumFaces,sizeof(mdef->m_NumFaces));
m_pFaces = NULL; mdef->m_pFaces=new SModelFace[mdef->m_NumFaces];
m_pBones = NULL; unpacker.UnpackRaw(mdef->m_pFaces,sizeof(SModelFace)*mdef->m_NumFaces);
m_pAnimationKeys = NULL;
m_pAnimationFrames = NULL; unpacker.UnpackRaw(&mdef->m_NumBones,sizeof(mdef->m_NumBones));
m_pAnimations = NULL; if (mdef->m_NumBones) {
mdef->m_Bones=new CBoneState[mdef->m_NumBones];
m_NumVertices = 0; unpacker.UnpackRaw(mdef->m_Bones,mdef->m_NumBones*sizeof(CBoneState));
m_NumFaces = 0; }
m_NumBones = 0; } catch (...) {
m_NumAnimationKeys = 0; delete mdef;
m_NumAnimationFrames = 0; throw CFileUnpacker::CFileEOFError();
m_NumAnimations = 0; }
}
return mdef;
void CModelDef::SetupBones() }
{
for (int i=0; i<m_NumBones; i++) ///////////////////////////////////////////////////////////////////////////////
{ // Save: write the given CModelDef to the given file
SModelBone *pBone = &m_pBones[i]; void CModelDef::Save(const char* filename,const CModelDef* mdef)
{
pBone->m_Relative.SetIdentity(); CFilePacker packer;
pBone->m_Absolute.SetIdentity();
// pack everything up
pBone->m_Relative.RotateX (pBone->m_Rotation.X); u32 numVertices=mdef->GetNumVertices();
pBone->m_Relative.RotateY (pBone->m_Rotation.Y); packer.PackRaw(&numVertices,sizeof(numVertices));
pBone->m_Relative.RotateZ (pBone->m_Rotation.Z); packer.PackRaw(mdef->GetVertices(),sizeof(SModelVertex)*numVertices);
// pBone->m_Relative.RotateX (DEGTORAD(90));
u32 numFaces=mdef->GetNumFaces();
pBone->m_Relative.Translate (pBone->m_Position); packer.PackRaw(&numFaces,sizeof(numFaces));
packer.PackRaw(mdef->GetFaces(),sizeof(SModelFace)*numFaces);
if (pBone->m_Parent >= 0)
{ packer.PackRaw(&mdef->m_NumBones,sizeof(mdef->m_NumBones));
SModelBone *pParent = &m_pBones[pBone->m_Parent]; if (mdef->m_NumBones) {
packer.PackRaw(mdef->m_Bones,sizeof(CBoneState)*mdef->m_NumBones);
pBone->m_Absolute = pParent->m_Absolute * pBone->m_Relative; }
}
else // flush everything out to file
pBone->m_Absolute = pBone->m_Relative; packer.Write(filename,FILE_VERSION,"PSMD");
} }
//we need to "un-transform" all the vertices by the initial
//pose of the bones they are attached to.
for (i=0; i<m_NumVertices; i++)
{
SModelVertex *pVertex = &m_pVertices[i];
if (pVertex->m_Bone>=0) {
SModelBone *pBone = &m_pBones[pVertex->m_Bone];
CVector3D BonePos = pBone->m_Absolute.GetTranslation();
pVertex->m_Coords.X -= BonePos.X;
pVertex->m_Coords.Y -= BonePos.Y;
pVertex->m_Coords.Z -= BonePos.Z;
CMatrix3D BoneInvMat;
pBone->m_Absolute.Invert(BoneInvMat);
pVertex->m_Coords = BoneInvMat.Rotate (pVertex->m_Coords);
}
}
}

View File

@ -1,120 +1,109 @@
/************************************************************ ///////////////////////////////////////////////////////////////////////////////
* //
* File Name: ModelDef.H // Name: ModelDef.h
* // Author: Rich Cross
* Description: CModelDef is essentially a CModelFile, except // Contact: rich@wildfiregames.com
* that the data is stored in a more convenient //
* way. To create a CModelDef, call ///////////////////////////////////////////////////////////////////////////////
* CModelFile::ReadModelDef();
* #ifndef _MODELDEF_H
************************************************************/ #define _MODELDEF_H
#ifndef MODELDEF_H ///////////////////////////////////////////////////////////////////////////////
#define MODELDEF_H // TODO,RC 11/03/04: get rid of all the m_Name[MAX_NAME_LENGTH] - use CStr
// - problem: conflicts with CStr in MAX's SDK; can't compile PMDExp if
#include "Vector3D.h" // ps\CStr.h included here
#include "Matrix3D.h" ///////////////////////////////////////////////////////////////////////////////
#define MAX_NAME_LENGTH (128) #include "res/res.h"
#include "Vector3D.h"
#include "SkeletonAnim.h"
struct SModelVertex
{ #ifndef MAX_NAME_LENGTH
CVector3D m_Coords; #define MAX_NAME_LENGTH (128)
CVector3D m_Norm; #endif
float m_U, m_V; ///////////////////////////////////////////////////////////////////////////////
int m_Bone; // SVertexBlend: structure containing the necessary data for blending vertices
}; // with multiple bones
struct SVertexBlend
{
struct SModelFace enum { SIZE = 4 };
{ // index of the influencing bone, or 0xff if none
int m_Verts[3]; u8 m_Bone[SIZE];
}; // weight of the influence; all weights sum to 1
float m_Weight[SIZE];
};
struct SModelBone
{ ///////////////////////////////////////////////////////////////////////////////
char m_Name[MAX_NAME_LENGTH]; // SModelVertex: structure containing per-vertex data
struct SModelVertex
int m_Parent; {
CVector3D m_Position; // vertex position
CVector3D m_Rotation; CVector3D m_Coords;
// vertex normal
//absolute and relative orientation of this bone CVector3D m_Norm;
CMatrix3D m_Relative; // vertex UVs
CMatrix3D m_Absolute; float m_U, m_V;
}; // vertex blend data
SVertexBlend m_Blend;
struct SModelAnimationKey };
{
CVector3D m_Translation;
CVector3D m_Rotation; ///////////////////////////////////////////////////////////////////////////////
}; // SModelFace: structure containing per-face data
struct SModelFace
//An animation frame contains one animation key for each of {
//the bones in the model // indices of the 3 vertices on this face
struct SModelAnimationFrame u16 m_Verts[3];
{ };
int m_FirstKey;
int m_NumKeys; //this should be that same as number of bones in the model
}; ////////////////////////////////////////////////////////////////////////////////////////
// CModelDef: a raw 3D model; describes the vertices, faces, skinning and skeletal
//a complete animation for all the bones // information of a model
struct SModelAnimation class CModelDef
{ {
char m_Name[MAX_NAME_LENGTH]; public:
// current file version given to saved animations
int m_FirstFrame; enum { FILE_VERSION = 1 };
int m_NumFrames; // supported file read version - files with a version less than this will be rejected
}; enum { FILE_READ_VERSION = 1 };
class CModelDef public:
{ // constructor
friend class CModelFile; CModelDef();
// destructor
public: virtual ~CModelDef();
CModelDef ();
virtual ~CModelDef (); // model I/O functions
static CModelDef* Load(const char* filename);
void SetupBones(); static void Save(const char* filename,const CModelDef* mdef);
void Destroy(); public:
// accessor: get vertex data
//access functions int GetNumVertices() const { return m_NumVertices; }
public: SModelVertex *GetVertices() const { return m_pVertices; }
SModelVertex *GetVertices() { return m_pVertices; }
SModelFace *GetFaces() { return m_pFaces; } // accessor: get face data
SModelBone *GetBones() { return m_pBones; } int GetNumFaces() const { return m_NumFaces; }
SModelAnimationKey *GetAnimationKeys() { return m_pAnimationKeys; } SModelFace *GetFaces() const { return m_pFaces; }
SModelAnimationFrame *GetAnimationFrames() { return m_pAnimationFrames; }
SModelAnimation *GetAnimations() { return m_pAnimations; } // accessor: get bone data
int GetNumBones() const { return m_NumBones; }
int GetNumVertices() { return m_NumVertices; } CBoneState *GetBones() const { return m_Bones; }
int GetNumFaces() { return m_NumFaces; }
int GetNumBones() { return m_NumBones; } public:
int GetNumAnimationKeys() { return m_NumAnimationKeys; } // vertex data
int GetNumAnimationFrames() { return m_NumAnimationFrames; } u32 m_NumVertices;
int GetNumAnimations() { return m_NumAnimations; } SModelVertex* m_pVertices;
// face data
public: u32 m_NumFaces;
SModelVertex *m_pVertices; SModelFace* m_pFaces;
SModelFace *m_pFaces; // bone data - default model pose
SModelBone *m_pBones; u32 m_NumBones;
SModelAnimationKey *m_pAnimationKeys; CBoneState* m_Bones;
SModelAnimationFrame *m_pAnimationFrames; };
SModelAnimation *m_pAnimations;
#endif
int m_NumVertices;
int m_NumFaces;
int m_NumBones;
int m_NumAnimationKeys;
int m_NumAnimationFrames;
int m_NumAnimations;
char m_TextureName[MAX_NAME_LENGTH];
};
#endif

View File

@ -1,352 +0,0 @@
/************************************************************
*
* File Name: ModelFile.Cpp
*
* Description: A CModelFile holds the structure of a model
* file. A model is easily read/written to disk
* using this interface.
*
************************************************************/
#include <stdio.h>
#include "ModelFile.h"
CModelFile::CModelFile ()
{
m_pVertices = NULL;
m_pFaces = NULL;
m_pBones = NULL;
m_pAnimationKeys = NULL;
m_pAnimationFrames = NULL;
m_pAnimations = NULL;
m_NumVertices = 0;
m_NumFaces = 0;
m_NumBones = 0;
m_NumAnimationKeys = 0;
m_NumAnimationFrames = 0;
m_NumAnimations = 0;
}
CModelFile::~CModelFile()
{
Destroy();
}
void CModelFile::Destroy()
{
if (m_pVertices)
delete [] m_pVertices;
if (m_pFaces)
delete [] m_pFaces;
if (m_pBones)
delete [] m_pBones;
if (m_pAnimationKeys)
delete [] m_pAnimationKeys;
if (m_pAnimationFrames)
delete [] m_pAnimationFrames;
if (m_pAnimations)
delete [] m_pAnimations;
m_pVertices = NULL;
m_pFaces = NULL;
m_pBones = NULL;
m_pAnimationKeys = NULL;
m_pAnimationFrames = NULL;
m_pAnimations = NULL;
m_NumVertices = 0;
m_NumFaces = 0;
m_NumBones = 0;
m_NumAnimationKeys = 0;
m_NumAnimationFrames = 0;
m_NumAnimations = 0;
}
bool CModelFile::WriteModelDef (const char *filename, CModelDef *modeldef)
{
FILE *out_f = NULL;
out_f = fopen (filename, "wb");
m_NumVertices = modeldef->m_NumVertices;
m_NumFaces = modeldef->m_NumFaces;
m_NumBones = modeldef->m_NumBones;
m_NumAnimationKeys = modeldef->m_NumAnimationKeys;
m_NumAnimationFrames = modeldef->m_NumAnimationFrames;
m_NumAnimations = modeldef->m_NumAnimations;
m_pVertices = new SModelFile_Vertex[m_NumVertices];
m_pFaces = new SModelFile_Face[m_NumFaces];
m_pBones = new SModelFile_Bone[m_NumBones];
m_pAnimationKeys = new SModelFile_AnimationKey[m_NumAnimationKeys];
m_pAnimationFrames = new SModelFile_AnimationFrame[m_NumAnimationFrames];
m_pAnimations = new SModelFile_Animation[m_NumAnimations];
for (int i=0; i<m_NumVertices; i++)
{
m_pVertices[i].m_Coords = modeldef->m_pVertices[i].m_Coords;
m_pVertices[i].m_Norm = modeldef->m_pVertices[i].m_Norm;
m_pVertices[i].m_U = modeldef->m_pVertices[i].m_U;
m_pVertices[i].m_V = modeldef->m_pVertices[i].m_V;
m_pVertices[i].m_Bone = modeldef->m_pVertices[i].m_Bone;
if (m_pVertices[i].m_Bone >= 0)
{
SModelBone *pBone = &modeldef->m_pBones[m_pVertices[i].m_Bone];
m_pVertices[i].m_Coords = pBone->m_Absolute.Transform (m_pVertices[i].m_Coords);
}
}
for (i=0; i<m_NumFaces; i++)
{
m_pFaces[i].m_Verts[0] = modeldef->m_pFaces[i].m_Verts[0];
m_pFaces[i].m_Verts[1] = modeldef->m_pFaces[i].m_Verts[1];
m_pFaces[i].m_Verts[2] = modeldef->m_pFaces[i].m_Verts[2];
}
for (i=0; i<m_NumBones; i++)
{
strcpy (m_pBones[i].m_Name, modeldef->m_pBones[i].m_Name);
m_pBones[i].m_Position = modeldef->m_pBones[i].m_Position;
m_pBones[i].m_Rotation = modeldef->m_pBones[i].m_Rotation;
m_pBones[i].m_Parent = modeldef->m_pBones[i].m_Parent;
}
for (i=0; i<m_NumAnimationKeys; i++)
{
m_pAnimationKeys[i].m_Translation = modeldef->m_pAnimationKeys[i].m_Translation;
m_pAnimationKeys[i].m_Rotation = modeldef->m_pAnimationKeys[i].m_Rotation;
}
for (i=0; i<m_NumAnimationFrames; i++)
{
m_pAnimationFrames[i].m_FirstKey = modeldef->m_pAnimationFrames[i].m_FirstKey;
m_pAnimationFrames[i].m_NumKeys = modeldef->m_pAnimationFrames[i].m_NumKeys;
}
for (i=0; i<m_NumAnimations; i++)
{
strcpy (m_pAnimations[i].m_Name, modeldef->m_pAnimations[i].m_Name);
m_pAnimations[i].m_FirstFrame = modeldef->m_pAnimations[i].m_FirstFrame;
m_pAnimations[i].m_NumFrames = modeldef->m_pAnimations[i].m_NumFrames;
}
m_Lumps[MF_VERTICES].m_Offset = MF_NUM_LUMPS*sizeof(SLump);
m_Lumps[MF_VERTICES].m_Length = m_NumVertices*sizeof(SModelFile_Vertex);
m_Lumps[MF_FACES].m_Offset = m_Lumps[MF_VERTICES].m_Offset + m_Lumps[MF_VERTICES].m_Length;
m_Lumps[MF_FACES].m_Length = m_NumFaces*sizeof(SModelFile_Face);
m_Lumps[MF_BONES].m_Offset = m_Lumps[MF_FACES].m_Offset + m_Lumps[MF_FACES].m_Length;
m_Lumps[MF_BONES].m_Length = m_NumBones*sizeof(SModelFile_Bone);
m_Lumps[MF_ANIMKEYS].m_Offset = m_Lumps[MF_BONES].m_Offset + m_Lumps[MF_BONES].m_Length;
m_Lumps[MF_ANIMKEYS].m_Length = m_NumAnimationKeys*sizeof(SModelFile_AnimationKey);
m_Lumps[MF_ANIMFRAMES].m_Offset = m_Lumps[MF_ANIMKEYS].m_Offset + m_Lumps[MF_ANIMKEYS].m_Length;
m_Lumps[MF_ANIMFRAMES].m_Length = m_NumAnimationFrames*sizeof(SModelFile_AnimationFrame);
m_Lumps[MF_ANIMS].m_Offset = m_Lumps[MF_ANIMFRAMES].m_Offset + m_Lumps[MF_ANIMFRAMES].m_Length;
m_Lumps[MF_ANIMS].m_Length = m_NumAnimations*sizeof(SModelFile_Animation);
//write the lumps
if (fwrite (m_Lumps, sizeof(SLump), MF_NUM_LUMPS, out_f) != MF_NUM_LUMPS)
{
fclose (out_f);
return false;
}
//write all the data
if (fwrite (m_pVertices, sizeof (SModelFile_Vertex), m_NumVertices, out_f) != (unsigned)m_NumVertices)
{
fclose (out_f);
return false;
}
if (fwrite (m_pFaces, sizeof (SModelFile_Face), m_NumFaces, out_f) != (unsigned)m_NumFaces)
{
fclose (out_f);
return false;
}
if (fwrite (m_pBones, sizeof (SModelFile_Bone), m_NumBones, out_f) != (unsigned)m_NumBones)
{
fclose (out_f);
return false;
}
if (fwrite (m_pAnimationKeys, sizeof (SModelFile_AnimationKey), m_NumAnimationKeys, out_f) != (unsigned)m_NumAnimationKeys)
{
fclose (out_f);
return false;
}
if (fwrite (m_pAnimationFrames, sizeof (SModelFile_AnimationFrame), m_NumAnimationFrames, out_f) != (unsigned)m_NumAnimationFrames)
{
fclose (out_f);
return false;
}
if (fwrite (m_pAnimations, sizeof (SModelFile_Animation), m_NumAnimations, out_f) != (unsigned)m_NumAnimations)
{
fclose (out_f);
return false;
}
fclose (out_f);
Destroy();
return true;
}
bool CModelFile::ReadModelDef (const char *filename, CModelDef *modeldef)
{
FILE *in_f = NULL;
in_f = fopen (filename, "rb");
if (!in_f) {
return false;
}
//read the lumps first
if (fread (m_Lumps, sizeof(SLump), MF_NUM_LUMPS, in_f) != MF_NUM_LUMPS)
{
fclose (in_f);
return false;
}
//calculate the number of each element
m_NumVertices = m_Lumps[MF_VERTICES].m_Length / sizeof(SModelFile_Vertex);
m_NumFaces = m_Lumps[MF_FACES].m_Length / sizeof(SModelFile_Face);
m_NumBones = m_Lumps[MF_BONES].m_Length / sizeof(SModelFile_Bone);
m_NumAnimationKeys = m_Lumps[MF_ANIMKEYS].m_Length / sizeof(SModelFile_AnimationKey);
m_NumAnimationFrames = m_Lumps[MF_ANIMFRAMES].m_Length / sizeof(SModelFile_AnimationFrame);
m_NumAnimations = m_Lumps[MF_ANIMS].m_Length / sizeof(SModelFile_Animation);
//allocate memory
m_pVertices = new SModelFile_Vertex[m_NumVertices];
m_pFaces = new SModelFile_Face[m_NumFaces];
m_pBones = new SModelFile_Bone[m_NumBones];
m_pAnimationKeys = new SModelFile_AnimationKey[m_NumAnimationKeys];
m_pAnimationFrames = new SModelFile_AnimationFrame[m_NumAnimationFrames];
m_pAnimations = new SModelFile_Animation[m_NumAnimations];
//read all the data
fseek (in_f, m_Lumps[MF_VERTICES].m_Offset, SEEK_SET);
if (fread (m_pVertices, sizeof(SModelFile_Vertex), m_NumVertices, in_f) != (unsigned)m_NumVertices)
{
fclose (in_f);
return false;
}
fseek (in_f, m_Lumps[MF_FACES].m_Offset, SEEK_SET);
if (fread (m_pFaces, sizeof (SModelFile_Face), m_NumFaces, in_f) != (unsigned)m_NumFaces)
{
fclose (in_f);
return false;
}
fseek (in_f, m_Lumps[MF_BONES].m_Offset, SEEK_SET);
if (fread (m_pBones, sizeof (SModelFile_Bone), m_NumBones, in_f) != (unsigned)m_NumBones)
{
fclose (in_f);
return false;
}
fseek (in_f, m_Lumps[MF_ANIMKEYS].m_Offset, SEEK_SET);
if (fread (m_pAnimationKeys, sizeof (SModelFile_AnimationKey), m_NumAnimationKeys, in_f) != (unsigned)m_NumAnimationKeys)
{
fclose (in_f);
return false;
}
fseek (in_f, m_Lumps[MF_ANIMFRAMES].m_Offset, SEEK_SET);
if (fread (m_pAnimationFrames, sizeof (SModelFile_AnimationFrame), m_NumAnimationFrames, in_f) != (unsigned)m_NumAnimationFrames)
{
fclose (in_f);
return false;
}
fseek (in_f, m_Lumps[MF_ANIMS].m_Offset, SEEK_SET);
if (fread (m_pAnimations, sizeof (SModelFile_Animation), m_NumAnimations, in_f) != (unsigned)m_NumAnimations)
{
fclose (in_f);
return false;
}
fclose (in_f);
modeldef->Destroy();
modeldef->m_NumVertices = m_NumVertices;
modeldef->m_NumFaces = m_NumFaces;
modeldef->m_NumBones = m_NumBones;
modeldef->m_NumAnimationKeys = m_NumAnimationKeys;
modeldef->m_NumAnimationFrames = m_NumAnimationFrames;
modeldef->m_NumAnimations = m_NumAnimations;
modeldef->m_pVertices = new SModelVertex[m_NumVertices];
modeldef->m_pFaces = new SModelFace[m_NumFaces];
modeldef->m_pBones = new SModelBone[m_NumBones];
modeldef->m_pAnimationKeys = new SModelAnimationKey[m_NumAnimationKeys];
modeldef->m_pAnimationFrames = new SModelAnimationFrame[m_NumAnimationFrames];
modeldef->m_pAnimations = new SModelAnimation[m_NumAnimations];
for (int i=0; i<m_NumVertices; i++)
{
modeldef->m_pVertices[i].m_Coords = m_pVertices[i].m_Coords;
modeldef->m_pVertices[i].m_Norm = m_pVertices[i].m_Norm;
modeldef->m_pVertices[i].m_U = m_pVertices[i].m_U;
modeldef->m_pVertices[i].m_V = m_pVertices[i].m_V;
modeldef->m_pVertices[i].m_Bone = m_pVertices[i].m_Bone;
}
for (i=0; i<m_NumFaces; i++)
{
modeldef->m_pFaces[i].m_Verts[0] = m_pFaces[i].m_Verts[0];
modeldef->m_pFaces[i].m_Verts[1] = m_pFaces[i].m_Verts[1];
modeldef->m_pFaces[i].m_Verts[2] = m_pFaces[i].m_Verts[2];
}
for (i=0; i<m_NumBones; i++)
{
strcpy (modeldef->m_pBones[i].m_Name, m_pBones[i].m_Name);
modeldef->m_pBones[i].m_Position = m_pBones[i].m_Position;
modeldef->m_pBones[i].m_Rotation = m_pBones[i].m_Rotation;
modeldef->m_pBones[i].m_Parent = m_pBones[i].m_Parent;
}
for (i=0; i<m_NumAnimationKeys; i++)
{
modeldef->m_pAnimationKeys[i].m_Translation = m_pAnimationKeys[i].m_Translation;
modeldef->m_pAnimationKeys[i].m_Rotation = m_pAnimationKeys[i].m_Rotation;
}
for (i=0; i<m_NumAnimationFrames; i++)
{
modeldef->m_pAnimationFrames[i].m_FirstKey = m_pAnimationFrames[i].m_FirstKey;
modeldef->m_pAnimationFrames[i].m_NumKeys = m_pAnimationFrames[i].m_NumKeys;
}
for (i=0; i<m_NumAnimations; i++)
{
strcpy (modeldef->m_pAnimations[i].m_Name, m_pAnimations[i].m_Name);
modeldef->m_pAnimations[i].m_FirstFrame = m_pAnimations[i].m_FirstFrame;
modeldef->m_pAnimations[i].m_NumFrames = m_pAnimations[i].m_NumFrames;
}
modeldef->SetupBones();
Destroy();
return true;
}

View File

@ -1,116 +0,0 @@
/************************************************************
*
* File Name: ModelFile.H
*
* Description: A CModelFile holds the structure of a model
* file, and is responsible for reading/writing
* a CModelDef from/to a file
*
************************************************************/
#ifndef MODELFILE_H
#define MODELFILE_H
#include <windows.h>
#include "Vector3D.h"
#include "ModelDef.h"
enum EModelFileLumps
{
MF_VERTICES = 0,
MF_FACES,
MF_BONES,
MF_ANIMKEYS,
MF_ANIMFRAMES,
MF_ANIMS,
MF_NUM_LUMPS
};
struct SLump
{
int m_Offset;
int m_Length;
};
struct SModelFile_Vertex
{
CVector3D m_Coords;
CVector3D m_Norm;
float m_U, m_V;
int m_Bone;
};
struct SModelFile_Face
{
int m_Verts[3];
};
struct SModelFile_Bone
{
char m_Name[MAX_NAME_LENGTH];
int m_Parent;
CVector3D m_Position;
CVector3D m_Rotation;
};
struct SModelFile_AnimationKey
{
CVector3D m_Translation;
CVector3D m_Rotation;
};
//animation keys of one animation for one bone
struct SModelFile_AnimationFrame
{
int m_FirstKey;
int m_NumKeys; //this should always be the same as the number of bones in the model.
};
//a complete animation for all the bones
struct SModelFile_Animation
{
char m_Name[MAX_NAME_LENGTH];
int m_FirstFrame;
int m_NumFrames;
};
class CModelFile
{
public:
CModelFile ();
~CModelFile ();
bool ReadModelDef (const char *filename, CModelDef *modeldef);
bool WriteModelDef (const char *filename, CModelDef *modeldef);
private:
void Destroy();
private:
SLump m_Lumps[MF_NUM_LUMPS];
SModelFile_Vertex *m_pVertices;
SModelFile_Face *m_pFaces;
SModelFile_Bone *m_pBones;
SModelFile_AnimationKey *m_pAnimationKeys;
SModelFile_AnimationFrame *m_pAnimationFrames;
SModelFile_Animation *m_pAnimations;
int m_NumVertices;
int m_NumFaces;
int m_NumBones;
int m_NumAnimationKeys;
int m_NumAnimationFrames;
int m_NumAnimations;
};
#endif

View File

@ -1,271 +1,257 @@
#include <assert.h> #include <assert.h>
#include <algorithm> #include <algorithm>
#include "res/tex.h" #include "res/tex.h"
#include "Renderer.h" #include "Renderer.h"
#include "TransparencyRenderer.h" #include "TransparencyRenderer.h"
#include "ModelRData.h" #include "ModelRData.h"
#include "terrain/Model.h" #include "terrain/Model.h"
extern CRenderer g_Renderer;
CModelRData::CModelRData(CModel* model) : m_Model(model), m_Vertices(0), m_Normals(0), m_Indices(0), m_VB(0)
CModelRData::CModelRData(CModel* model) : m_Model(model), m_Vertices(0), m_Indices(0), m_VB(0) {
{ assert(model);
assert(model); // build all data now
// set models renderdata pointer to point to this object Build();
m_Model->m_RenderData=this; }
// build all data now
Build(); CModelRData::~CModelRData()
} {
}
CModelRData::~CModelRData()
{ void CModelRData::Build()
} {
BuildVertices();
void CModelRData::Build() BuildIndices();
{ }
BuildVertices();
BuildIndices(); void CModelRData::BuildIndices()
} {
CModelDef* mdef=m_Model->GetModelDef();
void CModelRData::BuildIndices()
{ // allocate indices if we haven't got any already
CModelDef* mdef=m_Model->GetModelDef(); if (!m_Indices) {
m_Indices=new u16[mdef->GetNumFaces()*3];
// allocate indices if we haven't got any already }
if (!m_Indices) {
m_Indices=new u16[mdef->GetNumFaces()*3]; // build indices
} u32 indices=0;
SModelFace* faces=mdef->GetFaces();
// build indices for (int j=0; j<mdef->GetNumFaces(); j++) {
u32 indices=0; SModelFace& face=faces[j];
SModelFace* faces=mdef->GetFaces(); m_Indices[indices++]=face.m_Verts[0];
for (int j=0; j<mdef->GetNumFaces(); j++) { m_Indices[indices++]=face.m_Verts[1];
SModelFace& face=faces[j]; m_Indices[indices++]=face.m_Verts[2];
m_Indices[indices++]=face.m_Verts[0]; }
m_Indices[indices++]=face.m_Verts[1]; }
m_Indices[indices++]=face.m_Verts[2];
} inline int clamp(int x,int min,int max)
} {
if (x<min) return min;
inline int clamp(int x,int min,int max) else if (x>max) return max;
{ else return x;
if (x<min) return min; }
else if (x>max) return max;
else return x; static SColor4ub ConvertColor(const RGBColor& src)
} {
SColor4ub result;
static SColor4ub ConvertColor(const RGBColor& src) result.R=clamp(int(src.X*255),0,255);
{ result.G=clamp(int(src.Y*255),0,255);
SColor4ub result; result.B=clamp(int(src.Z*255),0,255);
result.R=clamp(int(src.X*255),0,255); result.A=0xff;
result.G=clamp(int(src.Y*255),0,255); return result;
result.B=clamp(int(src.Z*255),0,255); }
result.A=0xff;
return result; static CVector3D SkinPoint(const SModelVertex& vertex,const CMatrix3D* matrices)
} {
CVector3D result(0,0,0),tmp;
void CModelRData::BuildVertices()
{ for (u32 i=0;vertex.m_Blend.m_Bone[i]!=0xff && i<SVertexBlend::SIZE;i++) {
CModelDef* mdef=m_Model->GetModelDef(); const CMatrix3D& m=matrices[vertex.m_Blend.m_Bone[i]];
m.Transform(vertex.m_Coords,tmp);
// allocate vertices if we haven't got any already result+=tmp*vertex.m_Blend.m_Weight[i];
if (!m_Vertices) { }
m_Vertices=new SVertex[mdef->GetNumVertices()];
} return result;
}
// build vertices
SModelVertex* vertices=mdef->GetVertices(); static CVector3D SkinNormal(const SModelVertex& vertex,const CMatrix3D* invmatrices)
for (int j=0; j<mdef->GetNumVertices(); j++) { {
if (vertices[j].m_Bone!=-1) { CVector3D result(0,0,0),tmp;
m_Vertices[j].m_Position=m_Model->GetBonePoses()[vertices[j].m_Bone].Transform(vertices[j].m_Coords);
} else { for (u32 i=0;vertex.m_Blend.m_Bone[i]!=0xff && i<SVertexBlend::SIZE;i++) {
m_Vertices[j].m_Position=vertices[j].m_Coords; const CMatrix3D& m=invmatrices[vertex.m_Blend.m_Bone[i]];
} m.RotateTransposed(vertex.m_Norm,tmp);
result+=tmp*vertex.m_Blend.m_Weight[i];
m_Vertices[j].m_UVs[0]=vertices[j].m_U; }
m_Vertices[j].m_UVs[1]=1-vertices[j].m_V;
return result;
RGBColor c; }
g_Renderer.m_SHCoeffsUnits.Evaluate(vertices[j].m_Norm,c);
void CModelRData::BuildVertices()
m_Vertices[j].m_Color=ConvertColor(c); {
} CModelDef* mdef=m_Model->GetModelDef();
if (g_Renderer.m_Caps.m_VBO) { // allocate vertices if we haven't got any already
if (!m_VB) { if (!m_Vertices) {
glGenBuffersARB(1,(GLuint*) &m_VB); m_Vertices=new SVertex[mdef->GetNumVertices()];
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VB); m_Normals=new CVector3D[mdef->GetNumVertices()];
glBufferDataARB(GL_ARRAY_BUFFER_ARB,mdef->GetNumVertices()*sizeof(SVertex),0,GL_STATIC_DRAW_ARB); }
} else {
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VB); // build vertices
} u32 numVertices=mdef->GetNumVertices();
SModelVertex* vertices=mdef->GetVertices();
u8* vertices=(u8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB,GL_WRITE_ONLY_ARB); if (m_Model->GetBoneMatrices()) {
memcpy(vertices,m_Vertices,mdef->GetNumVertices()*sizeof(SVertex)); // boned model - calculate skinned vertex positions/normals
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); for (uint j=0; j<numVertices; j++) {
} m_Vertices[j].m_Position=SkinPoint(vertices[j],m_Model->GetBoneMatrices());
} m_Normals[j]=SkinNormal(vertices[j],m_Model->GetInvBoneMatrices());
}
void CModelRData::RenderWireframe(const CMatrix3D& transform,bool transparentPass) } else {
{ // just copy regular positions
// ignore transparent passes for (uint j=0; j<numVertices; j++) {
if (!transparentPass && g_Renderer.IsTextureTransparent(m_Model->GetTexture())) { m_Vertices[j].m_Position=vertices[j].m_Coords;
return; m_Normals[j]=vertices[j].m_Norm;
} }
}
assert(m_UpdateFlags==0);
// now fill in UV and vertex colour data
u8* base; for (uint j=0; j<numVertices; j++) {
if (g_Renderer.m_Caps.m_VBO) { m_Vertices[j].m_UVs[0]=vertices[j].m_U;
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VB); m_Vertices[j].m_UVs[1]=1-vertices[j].m_V;
base=0;
} else { RGBColor c;
base=(u8*) &m_Vertices[0]; g_Renderer.m_SHCoeffsUnits.Evaluate(m_Normals[j],c);
}
m_Vertices[j].m_Color=ConvertColor(c);
glMatrixMode(GL_MODELVIEW); }
glPushMatrix();
if (g_Renderer.m_Caps.m_VBO) {
CMatrix3D tmp; if (!m_VB) {
transform.GetTranspose(tmp); glGenBuffersARB(1,(GLuint*) &m_VB);
glMultMatrixf(&tmp._11); glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VB);
glBufferDataARB(GL_ARRAY_BUFFER_ARB,mdef->GetNumVertices()*sizeof(SVertex),0,mdef->GetNumBones() ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB);
}
// set vertex pointers glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VB);
glVertexPointer(3,GL_FLOAT,sizeof(SVertex),base+offsetof(SVertex,m_Position)); glBufferSubDataARB(GL_ARRAY_BUFFER_ARB,0,mdef->GetNumVertices()*sizeof(SVertex),m_Vertices);
}
// render the lot }
u32 numFaces=m_Model->GetModelDef()->GetNumFaces();
glDrawElements(GL_TRIANGLES,numFaces*3,GL_UNSIGNED_SHORT,m_Indices);
void CModelRData::RenderStreams(u32 streamflags,const CMatrix3D& transform,bool transparentPass)
// bump stats {
g_Renderer.m_Stats.m_DrawCalls++; // ignore transparent passes
if (transparentPass) { if (!transparentPass && g_Renderer.IsTextureTransparent(m_Model->GetTexture())) {
g_Renderer.m_Stats.m_TransparentTris+=numFaces; return;
} else { }
g_Renderer.m_Stats.m_ModelTris+=numFaces;
} CModelDef* mdldef=(CModelDef*) m_Model->GetModelDef();
glPopMatrix(); glMatrixMode(GL_MODELVIEW);
} glPushMatrix();
CMatrix3D tmp;
void CModelRData::Render(const CMatrix3D& transform,bool transparentPass) glMultMatrixf(&transform._11);
{
// ignore transparent passes if (streamflags & STREAM_UV0) g_Renderer.SetTexture(0,m_Model->GetTexture(),GL_CLAMP_TO_EDGE);
if (!transparentPass && g_Renderer.IsTextureTransparent(m_Model->GetTexture())) {
return; u8* base;
} if (g_Renderer.m_Caps.m_VBO) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VB);
CModelDef* mdldef=(CModelDef*) m_Model->GetModelDef(); base=0;
} else {
glMatrixMode(GL_MODELVIEW); base=(u8*) &m_Vertices[0];
glPushMatrix(); }
CMatrix3D tmp; // set vertex pointers
transform.GetTranspose(tmp); u32 stride=sizeof(SVertex);
glMultMatrixf(&tmp._11); glVertexPointer(3,GL_FLOAT,stride,base+offsetof(SVertex,m_Position));
if (streamflags & STREAM_COLOR) glColorPointer(4,GL_UNSIGNED_BYTE,stride,base+offsetof(SVertex,m_Color));
g_Renderer.SetTexture(0,m_Model->GetTexture()); if (streamflags & STREAM_UV0) glTexCoordPointer(2,GL_FLOAT,stride,base+offsetof(SVertex,m_UVs));
u8* base; // render the lot
if (g_Renderer.m_Caps.m_VBO) { u32 numFaces=mdldef->GetNumFaces();
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VB); glDrawElements(GL_TRIANGLES,numFaces*3,GL_UNSIGNED_SHORT,m_Indices);
base=0;
} else { // bump stats
base=(u8*) &m_Vertices[0]; g_Renderer.m_Stats.m_DrawCalls++;
} if (transparentPass) {
g_Renderer.m_Stats.m_TransparentTris+=numFaces;
// set vertex pointers } else {
u32 stride=sizeof(SVertex); g_Renderer.m_Stats.m_ModelTris+=numFaces;
glVertexPointer(3,GL_FLOAT,stride,base+offsetof(SVertex,m_Position)); }
glColorPointer(4,GL_UNSIGNED_BYTE,stride,base+offsetof(SVertex,m_Color));
glTexCoordPointer(2,GL_FLOAT,stride,base+offsetof(SVertex,m_UVs)); glPopMatrix();
}
// render the lot
u32 numFaces=mdldef->GetNumFaces();
glDrawElements(GL_TRIANGLES,numFaces*3,GL_UNSIGNED_SHORT,m_Indices); void CModelRData::Update()
{
// bump stats if (m_UpdateFlags!=0) {
g_Renderer.m_Stats.m_DrawCalls++; // renderdata changed : rebuild necessary portions
if (transparentPass) { if (m_UpdateFlags & RENDERDATA_UPDATE_VERTICES) {
g_Renderer.m_Stats.m_TransparentTris+=numFaces; BuildVertices();
} else { }
g_Renderer.m_Stats.m_ModelTris+=numFaces; if (m_UpdateFlags & RENDERDATA_UPDATE_INDICES) {
} BuildIndices();
}
glPopMatrix();
} m_UpdateFlags=0;
}
}
void CModelRData::Update()
{ typedef std::pair<int,float> IntFloatPair;
if (m_UpdateFlags!=0) { static std::vector<IntFloatPair> IndexSorter;
// renderdata changed : rebuild necessary portions
if (m_UpdateFlags & RENDERDATA_UPDATE_VERTICES) { struct SortFacesByDist {
BuildVertices(); bool operator()(const IntFloatPair& lhs,const IntFloatPair& rhs) {
} return lhs.second>rhs.second ? true : false;
if (m_UpdateFlags & RENDERDATA_UPDATE_INDICES) { }
BuildIndices(); };
}
float CModelRData::BackToFrontIndexSort(CMatrix3D& objToCam)
m_UpdateFlags=0; {
} float mindist=1.0e30f;
} CVector3D osvtx,csvtx;
typedef std::pair<int,float> IntFloatPair; CModelDef* mdldef=(CModelDef*) m_Model->GetModelDef();
static std::vector<IntFloatPair> IndexSorter;
SModelVertex* vtxs=mdldef->GetVertices();
struct SortFacesByDist {
bool operator()(const IntFloatPair& lhs,const IntFloatPair& rhs) { u32 numFaces=mdldef->GetNumFaces();
return lhs.second>rhs.second ? true : false; SModelFace* faces=mdldef->GetFaces();
}
}; IndexSorter.reserve(numFaces);
float CModelRData::BackToFrontIndexSort(CMatrix3D& objToCam) SModelFace* facePtr=faces;
{ u32 i;
float mindist=1.0e30f; for (i=0;i<numFaces;i++)
CVector3D osvtx,csvtx; {
osvtx=vtxs[facePtr->m_Verts[0]].m_Coords;
CModelDef* mdldef=(CModelDef*) m_Model->GetModelDef(); osvtx+=vtxs[facePtr->m_Verts[1]].m_Coords;
osvtx+=vtxs[facePtr->m_Verts[2]].m_Coords;
SModelVertex* vtxs=mdldef->GetVertices(); osvtx*=1.0f/3.0f;
u32 numFaces=mdldef->GetNumFaces(); csvtx=objToCam.Transform(osvtx);
SModelFace* faces=mdldef->GetFaces(); float distsqrd=SQR(csvtx.X)+SQR(csvtx.Y)+SQR(csvtx.Z);
if (distsqrd<mindist) mindist=distsqrd;
IndexSorter.reserve(numFaces);
IndexSorter.push_back(IntFloatPair(i,distsqrd));
SModelFace* facePtr=faces; facePtr++;
uint i; }
for (i=0;i<numFaces;i++)
{ std::sort(IndexSorter.begin(),IndexSorter.end(),SortFacesByDist());
osvtx=vtxs[facePtr->m_Verts[0]].m_Coords;
osvtx+=vtxs[facePtr->m_Verts[1]].m_Coords; // now build index list
osvtx+=vtxs[facePtr->m_Verts[2]].m_Coords; u32 indices=0;
osvtx*=1.0f/3.0f; for (i=0;i<numFaces;i++) {
SModelFace& face=faces[IndexSorter[i].first];
csvtx=objToCam.Transform(osvtx); m_Indices[indices++]=face.m_Verts[0];
float distsqrd=SQR(csvtx.X)+SQR(csvtx.Y)+SQR(csvtx.Z); m_Indices[indices++]=face.m_Verts[1];
if (distsqrd<mindist) mindist=distsqrd; m_Indices[indices++]=face.m_Verts[2];
}
IndexSorter.push_back(IntFloatPair(i,distsqrd));
facePtr++; // clear list for next call
} IndexSorter.clear();
std::sort(IndexSorter.begin(),IndexSorter.end(),SortFacesByDist()); return mindist;
}
// now build index list
u32 indices=0;
for (i=0;i<numFaces;i++) {
SModelFace& face=faces[IndexSorter[i].first];
m_Indices[indices++]=face.m_Verts[0];
m_Indices[indices++]=face.m_Verts[1];
m_Indices[indices++]=face.m_Verts[2];
}
// clear list for next call
IndexSorter.clear();
return mindist;
}

View File

@ -1,53 +1,54 @@
#ifndef _MODELRDATA_H #ifndef _MODELRDATA_H
#define _MODELRDATA_H #define _MODELRDATA_H
#include <vector> #include <vector>
#include "res/res.h" #include "res/res.h"
#include "Vector3D.h" #include "Vector3D.h"
#include "RenderableObject.h" #include "RenderableObject.h"
class CModel; class CModel;
class CModelRData : public CRenderData class CModelRData : public CRenderData
{ {
public: public:
CModelRData(CModel* model); CModelRData(CModel* model);
~CModelRData(); ~CModelRData();
void Update(); void Update();
void Render(const CMatrix3D& transform,bool transparentPass=false); void RenderStreams(u32 streamflags,const CMatrix3D& transform,bool transparentPass=false);
void RenderWireframe(const CMatrix3D& transform,bool transparentPass=false);
// sort indices of this object from back to front according to given
// sort indices of this object from back to front according to given // object to camera space transform; return sqrd distance to centre of nearest triangle
// object to camera space transform; return sqrd distance to centre of nearest triangle float BackToFrontIndexSort(CMatrix3D& objToCam);
float BackToFrontIndexSort(CMatrix3D& objToCam);
private:
private: // build this renderdata object
// build this renderdata object void Build();
void Build();
void BuildVertices();
void BuildVertices(); void BuildIndices();
void BuildIndices();
struct SVertex {
struct SVertex { // vertex position
// vertex position CVector3D m_Position;
CVector3D m_Position; // vertex uvs for base texture
// vertex uvs for base texture float m_UVs[2];
float m_UVs[2]; // vertex color
// vertex color SColor4ub m_Color;
SColor4ub m_Color; };
};
// owner model
// owner model CModel* m_Model;
CModel* m_Model; // handle to models vertex buffer
// handle to models vertex buffer u32 m_VB;
u32 m_VB; // model render vertices
// model render vertices SVertex* m_Vertices;
SVertex* m_Vertices; // transformed vertex normals - required for recalculating lighting on skinned models
// model render indices CVector3D* m_Normals;
u16* m_Indices; // model render indices
}; u16* m_Indices;
};
#endif
#endif

222
source/terrain/ObjectEntry.cpp Executable file
View File

@ -0,0 +1,222 @@
#include "ObjectEntry.h"
#include "ObjectManager.h"
#include "terrain/Model.h"
#include "terrain/ModelDef.h"
#include "UnitManager.h"
// xerces XML stuff
#include <xercesc/dom/DOM.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/PlatformUtils.hpp>
// Gee's custom error handler
#include <ps/XercesErrorHandler.h>
// automatically use namespace ..
XERCES_CPP_NAMESPACE_USE
CObjectEntry::CObjectEntry(int type) : m_Model(0), m_Type(type)
{
}
CObjectEntry::~CObjectEntry()
{
delete m_Model;
}
bool CObjectEntry::BuildModel()
{
// check we've enough data to consider building the object
if (m_ModelName.Length()==0 || m_TextureName.Length()==0) {
return false;
}
// get the root directory of this object
CStr dirname=g_ObjMan.m_ObjectTypes[m_Type].m_Name;
// remember the old model so we can replace any models using it later on
CModelDef* oldmodel=m_Model ? m_Model->GetModelDef() : 0;
// build filename
CStr modelfilename("mods\\official\\");
modelfilename+=m_ModelName;
// try and create a model
CModelDef* modeldef;
try {
modeldef=CModelDef::Load((const char*) modelfilename);
} catch (...) {
return false;
}
// create new Model
m_Model=new CModel;
m_Model->InitModel(modeldef);
CStr texturefilename(m_TextureName);
m_Model->SetTexture(CTexture((const char*) texturefilename));
if (m_Animations.size()) {
if (m_Animations[0].m_FileName.Length()>0) {
CStr animfilename("mods\\official\\");
animfilename+=m_Animations[0].m_FileName;
try {
CSkeletonAnim* anim=CSkeletonAnim::Load((const char*) animfilename);
m_Model->SetAnimation(anim);
} catch (...) {
m_Model->SetAnimation(0);
}
}
}
// rebuild model bounds
m_Model->CalcBounds();
// replace any units using old model to now use new model
const std::vector<CUnit*>& units=g_UnitMan.GetUnits();
for (uint i=0;i<units.size();++i) {
if (units[i]->m_Model->GetModelDef()==oldmodel) {
units[i]->m_Model->InitModel(m_Model->GetModelDef());
CSkeletonAnim* anim=m_Model->GetAnimation();
if (anim) {
units[i]->m_Model->SetAnimation(anim);
}
}
}
// and were done with the old model ..
delete oldmodel;
return true;
}
bool CObjectEntry::Load(const char* filename)
{
bool parseOK = false;
// Initialize XML library
XMLPlatformUtils::Initialize();
{
// 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
LocalFileInputSource source( XMLString::transcode(filename) );
// 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 = XMLString::transcode( element->getNodeName() );
// should have at least 3 children - Name, ModelName and TextureName
DOMNodeList *children = element->getChildNodes();
int numChildren=children->getLength();
for (int i=0; i<numChildren; ++i) {
// Get node
DOMNode *child = children->item(i);
// A child element
if (child->getNodeType() == DOMNode::ELEMENT_NODE)
{
// First get element and not node
DOMElement *child_element = (DOMElement*)child;
CStr element_name = XMLString::transcode( child_element->getNodeName() );
DOMNode *value_node= child_element->getChildNodes()->item(0);
CStr element_value=value_node ? XMLString::transcode(value_node->getNodeValue()) : "";
if (element_name==CStr("Name")) {
m_Name=element_value;
} else if (element_name==CStr("ModelName")) {
m_ModelName=element_value;
} else if (element_name==CStr("TextureName")) {
m_TextureName=element_value;
} else if (element_name==CStr("Animations")) {
DOMNodeList* animations=(DOMNodeList*) child_element->getChildNodes();
for (uint j=0; j<animations->getLength(); ++j) {
DOMElement *anim_element = (DOMElement*) animations->item(j);
CStr element_name = XMLString::transcode( anim_element->getNodeName() );
DOMNamedNodeMap* attributes=anim_element->getAttributes();
if (attributes) {
Anim anim;
DOMNode *nameattr=attributes->getNamedItem(XMLString::transcode("name"));
anim.m_AnimName=XMLString::transcode(nameattr->getChildNodes()->item(0)->getNodeValue());
DOMNode *fileattr=attributes->getNamedItem(XMLString::transcode("file"));
anim.m_FileName=XMLString::transcode(fileattr->getChildNodes()->item(0)->getNodeValue());
m_Animations.push_back(anim);
}
}
}
}
}
// try and build the model
BuildModel();
}
delete parser;
}
XMLPlatformUtils::Terminate();
return parseOK;
}
bool CObjectEntry::Save(const char* filename)
{
FILE* fp=fopen(filename,"w");
if (!fp) return false;
// write XML header
fprintf(fp,"<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>\n\n");
fprintf(fp,"<!DOCTYPE Object SYSTEM \"..\\object.dtd\">\n\n");
// write the object itself
fprintf(fp,"<!-- File automatically generated by ScEd -->\n");
fprintf(fp,"<Object>\n");
fprintf(fp,"\t<Name>%s</Name>\n",(const char*) m_Name);
fprintf(fp,"\t<ModelName>%s</ModelName>\n",(const char*) m_ModelName);
fprintf(fp,"\t<TextureName>%s</TextureName>\n",(const char*) m_TextureName);
if (m_Animations.size()>0) {
fprintf(fp,"\t<Animations>\n");
for (uint i=0;i<m_Animations.size();i++) {
fprintf(fp,"\t\t<Animation name=\"%s\" file=\"%s\"> </Animation>\n",(const char*) m_Animations[i].m_AnimName,(const char*) m_Animations[i].m_FileName);
}
fprintf(fp,"\t</Animations>\n");
}
fprintf(fp,"</Object>\n");
fclose(fp);
return true;
}

45
source/terrain/ObjectEntry.h Executable file
View File

@ -0,0 +1,45 @@
#ifndef _OBJECTENTRY_H
#define _OBJECTENTRY_H
class CModel;
#include <vector>
#include "CStr.h"
#include "terrain/Bound.h"
class CObjectEntry
{
public:
struct Anim {
CStr m_AnimName;
CStr m_FileName;
};
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;
// animation name
std::vector<Anim> m_Animations;
// object space bounds of model
// CBound m_Bound;
// corresponding model
CModel* m_Model;
// type of object; index into object managers types array
int m_Type;
};
#endif

129
source/terrain/ObjectManager.cpp Executable file
View File

@ -0,0 +1,129 @@
#include "ObjectManager.h"
#include <io.h>
#include <algorithm>
CObjectManager g_ObjMan;
CObjectManager::CObjectManager() : m_SelectedObject(0)
{
m_ObjectTypes.reserve(32);
}
CObjectEntry* CObjectManager::FindObject(const char* objectname)
{
for (uint k=0;k<m_ObjectTypes.size();k++) {
std::vector<CObjectEntry*>& objects=m_ObjectTypes[k].m_Objects;
for (uint i=0;i<objects.size();i++) {
if (strcmp(objectname,(const char*) objects[i]->m_Name)==0) {
return objects[i];
}
}
}
return 0;
}
void CObjectManager::AddObjectType(const char* name)
{
m_ObjectTypes.resize(m_ObjectTypes.size()+1);
SObjectType& type=m_ObjectTypes.back();
type.m_Name=name;
type.m_Index=m_ObjectTypes.size()-1;
}
void CObjectManager::AddObject(CObjectEntry* object,int type)
{
assert((uint)type<m_ObjectTypes.size());
m_ObjectTypes[type].m_Objects.push_back(object);
}
void CObjectManager::DeleteObject(CObjectEntry* entry)
{
std::vector<CObjectEntry*>& objects=m_ObjectTypes[entry->m_Type].m_Objects;
typedef std::vector<CObjectEntry*>::iterator Iter;
Iter i=std::find(objects.begin(),objects.end(),entry);
if (i!=objects.end()) {
objects.erase(i);
}
delete entry;
}
void CObjectManager::LoadObjects()
{
// find all the object types by directory name
BuildObjectTypes();
// now iterate through terrain types loading all textures of that type
for (uint i=0;i<m_ObjectTypes.size();i++) {
LoadObjects(i);
}
}
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);
}
}

47
source/terrain/ObjectManager.h Executable file
View File

@ -0,0 +1,47 @@
#ifndef _OBJECTMANAGER_H
#define _OBJECTMANAGER_H
#include <vector>
#include "ObjectEntry.h"
class CObjectManager
{
public:
struct SObjectType
{
// name of this object type (derived from directory name)
CStr m_Name;
// index in parent array
int m_Index;
// list of objects of this type (found from the objects directory)
std::vector<CObjectEntry*> m_Objects;
};
public:
CObjectManager();
void LoadObjects();
void AddObjectType(const char* name);
CObjectEntry* FindObject(const char* objname);
void AddObject(CObjectEntry* entry,int type);
void DeleteObject(CObjectEntry* entry);
CObjectEntry* GetSelectedObject() const { return m_SelectedObject; }
void SetSelectedObject(CObjectEntry* obj) { m_SelectedObject=obj; }
std::vector<SObjectType> m_ObjectTypes;
private:
void BuildObjectTypes();
void LoadObjects(int type);
CObjectEntry* m_SelectedObject;
};
extern CObjectManager g_ObjMan;
#endif

View File

@ -1,62 +1,60 @@
//*********************************************************** ///////////////////////////////////////////////////////////////////////////////
// //
// Name: Patch.Cpp // Name: ModelDef.cpp
// Last Update: 23/2/02 // Author: Rich Cross
// Author: Poya Manouchehri // Contact: rich@wildfiregames.com
// //
// Description: CPatch is a smaller portion of the terrain. ///////////////////////////////////////////////////////////////////////////////
// It handles the ROAM implementation and its
// own rendering. #include "Patch.h"
// #include "Terrain.h"
//***********************************************************
#include "Patch.h" ///////////////////////////////////////////////////////////////////////////////
#include "Terrain.h" // CPatch constructor
CPatch::CPatch() : m_Parent(0)
{
CPatch::CPatch() }
{
m_Parent = NULL; ///////////////////////////////////////////////////////////////////////////////
} // CPatch destructor
CPatch::~CPatch()
CPatch::~CPatch() {
{ }
}
///////////////////////////////////////////////////////////////////////////////
void CPatch::Initialize(CTerrain* parent,u32 x,u32 z) // Initialize: setup patch data
{ void CPatch::Initialize(CTerrain* parent,u32 x,u32 z)
delete m_RenderData; {
m_RenderData; delete m_RenderData;
m_RenderData=0;
m_Parent=parent;
m_X=x; m_Parent=parent;
m_Z=z; m_X=x;
m_Z=z;
u32 mapSize=m_Parent->GetVerticesPerSide();
// set parent of each patch
for (int j=0; j<16; j++) { for (int j=0;j<16;j++) {
for (int i=0; i<16; i++) { for (int i=0;i<16;i++) {
m_MiniPatches[j][i].m_Parent=this; m_MiniPatches[j][i].m_Parent=this;
} }
} }
CalcBounds(); CalcBounds();
} }
void CPatch::CalcBounds() ///////////////////////////////////////////////////////////////////////////////
{ // CalcBounds: calculating the bounds of this patch
u32 mapSize=m_Parent->GetVerticesPerSide(); void CPatch::CalcBounds()
{
m_Bounds.SetEmpty(); m_Bounds.SetEmpty();
for (int j=0; j<PATCH_SIZE+1; j++) for (int j=0;j<PATCH_SIZE+1;j++) {
{ for (int i=0;i<PATCH_SIZE+1;i++) {
for (int i=0; i<PATCH_SIZE+1; i++) CVector3D pos;
{ m_Parent->CalcPosition(m_X*PATCH_SIZE+i,m_Z*PATCH_SIZE+j,pos);
CVector3D pos; m_Bounds+=pos;
m_Parent->CalcPosition(m_X*PATCH_SIZE+i,m_Z*PATCH_SIZE+j,pos); }
m_Bounds+=pos; }
} }
}
}

View File

@ -1,43 +1,42 @@
//*********************************************************** ///////////////////////////////////////////////////////////////////////////////
// //
// Name: Patch.h // Name: Patch.h
// Last Update: 23/2/02 // Author: Rich Cross
// Author: Poya Manouchehri // Contact: rich@wildfiregames.com
// //
// Description: CPatch is a smaller portion of the terrain. ///////////////////////////////////////////////////////////////////////////////
// It handles its own rendering
// #ifndef _PATCH_H
//*********************************************************** #define _PATCH_H
#ifndef PATCH_H #include "MiniPatch.h"
#define PATCH_H #include "RenderableObject.h"
#include "Matrix3D.h" class CTerrain;
#include "Camera.h"
#include "TerrGlobals.h" ///////////////////////////////////////////////////////////////////////////////
#include "MiniPatch.h" // CPatch: a single terrain patch, 16 tiles square
#include "RenderableObject.h" class CPatch : public CRenderableObject
{
public:
class CPatch : public CRenderableObject // constructor
{ CPatch();
public: // destructor
CPatch(); ~CPatch();
~CPatch();
// initialize the patch
//initialize the patch void Initialize(CTerrain* parent,u32 x,u32 z);
void Initialize(CTerrain* parent,u32 x,u32 z); // calculate and store bounds of this patch
void CalcBounds();
// calculate and store bounds of this patch
void CalcBounds(); public:
// minipatches (tiles) making up the patch
// minipatches (tiles) making up the patch CMiniPatch m_MiniPatches[16][16];
CMiniPatch m_MiniPatches[16][16]; // position of patch in parent terrain grid
// position of patch in parent terrain grid u32 m_X,m_Z;
u32 m_X,m_Z; // parent terrain
// parent terrain CTerrain* m_Parent;
CTerrain* m_Parent; };
};
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,89 +1,91 @@
#ifndef _PATCHRDATA_H #ifndef _PATCHRDATA_H
#define _PATCHRDATA_H #define _PATCHRDATA_H
#include <vector> #include <vector>
#include "res/res.h" #include "res/res.h"
#include "Vector3D.h" #include "Color.h"
#include "RenderableObject.h" #include "Vector3D.h"
#include "RenderableObject.h"
class CPatchRData : public CRenderData class CPatch;
{
public: class CPatchRData : public CRenderData
CPatchRData(CPatch* patch); {
~CPatchRData(); public:
CPatchRData(CPatch* patch);
void Update(); ~CPatchRData();
void RenderBase();
void RenderBlends(); void Update();
void RenderOutline(); void RenderBase();
void RenderWireframe(); void RenderBlends();
void RenderOutline();
private: void RenderStreams(u32 streamflags);
// build this renderdata object
void Build(); private:
// build this renderdata object
void BuildBlends(); void Build();
void BuildIndices();
void BuildVertices(); void BuildBlends();
void BuildIndices();
struct SSplat { void BuildVertices();
SSplat() : m_Texture(0), m_IndexCount(0) {}
struct SSplat {
// handle of texture to apply during splat SSplat() : m_Texture(0), m_IndexCount(0) {}
Handle m_Texture;
// offset into the index array for this patch where splat starts // handle of texture to apply during splat
u32 m_IndexStart; Handle m_Texture;
// number of indices used by splat // offset into the index array for this patch where splat starts
u32 m_IndexCount; u32 m_IndexStart;
}; // number of indices used by splat
u32 m_IndexCount;
struct SBaseVertex { };
// vertex position
CVector3D m_Position; struct SBaseVertex {
// vertex color // vertex position
SColor4ub m_Color; CVector3D m_Position;
// vertex uvs for base texture // vertex color
float m_UVs[2]; SColor4ub m_Color;
}; // vertex uvs for base texture
float m_UVs[2];
struct SBlendVertex { };
// vertex position
CVector3D m_Position; struct SBlendVertex {
// vertex color // vertex position
SColor4ub m_Color; CVector3D m_Position;
// vertex uvs for base texture // vertex color
float m_UVs[2]; SColor4ub m_Color;
// vertex uvs for alpha texture // vertex uvs for base texture
float m_AlphaUVs[2]; float m_UVs[2];
}; // vertex uvs for alpha texture
float m_AlphaUVs[2];
struct STex { };
bool operator==(const STex& rhs) const { return m_Handle==rhs.m_Handle; }
bool operator<(const STex& rhs) const { return m_Priority<rhs.m_Priority; } struct STex {
Handle m_Handle; bool operator==(const STex& rhs) const { return m_Handle==rhs.m_Handle; }
int m_Priority; bool operator<(const STex& rhs) const { return m_Priority<rhs.m_Priority; }
}; Handle m_Handle;
int m_Priority;
// owner patch };
CPatch* m_Patch;
// vertex buffer handle for base vertices // owner patch
u32 m_VBBase; CPatch* m_Patch;
// vertex buffer handle for blend vertices // vertex buffer handle for base vertices
u32 m_VBBlends; u32 m_VBBase;
// patch render vertices // vertex buffer handle for blend vertices
SBaseVertex* m_Vertices; u32 m_VBBlends;
// patch index list // patch render vertices
std::vector<unsigned short> m_Indices; SBaseVertex* m_Vertices;
// list of base splats to apply to this patch // patch index list
std::vector<SSplat> m_Splats; std::vector<unsigned short> m_Indices;
// vertices to use for blending transition texture passes // list of base splats to apply to this patch
std::vector<SBlendVertex> m_BlendVertices; std::vector<SSplat> m_Splats;
// indices into blend vertices for the blend splats // vertices to use for blending transition texture passes
std::vector<unsigned short> m_BlendIndices; std::vector<SBlendVertex> m_BlendVertices;
// splats used in blend pass // indices into blend vertices for the blend splats
std::vector<SSplat> m_BlendSplats; std::vector<unsigned short> m_BlendIndices;
}; // splats used in blend pass
std::vector<SSplat> m_BlendSplats;
};
#endif
#endif

View File

@ -1,179 +1,189 @@
/************************************************************ /************************************************************
* *
* File Name: Quaternion.Cpp * File Name: Quaternion.Cpp
* *
* Description: * Description:
* *
************************************************************/ ************************************************************/
#include "Quaternion.h" #include "Quaternion.h"
const float EPSILON=0.0001f; const float EPSILON=0.0001f;
CQuaternion::CQuaternion() CQuaternion::CQuaternion()
{ {
m_V.Clear (); m_V.Clear ();
m_W = 0; m_W = 0;
} }
//quaternion addition //quaternion addition
CQuaternion CQuaternion::operator + (CQuaternion &quat) CQuaternion CQuaternion::operator + (CQuaternion &quat)
{ {
CQuaternion Temp; CQuaternion Temp;
Temp.m_W = m_W + quat.m_W; Temp.m_W = m_W + quat.m_W;
Temp.m_V = m_V + quat.m_V; Temp.m_V = m_V + quat.m_V;
return Temp; return Temp;
} }
//quaternion addition/assignment //quaternion addition/assignment
CQuaternion &CQuaternion::operator += (CQuaternion &quat) CQuaternion &CQuaternion::operator += (CQuaternion &quat)
{ {
m_W += quat.m_W; m_W += quat.m_W;
m_V += quat.m_V; m_V += quat.m_V;
return (*this); return (*this);
} }
//quaternion multiplication //quaternion multiplication
CQuaternion CQuaternion::operator * (CQuaternion &quat) CQuaternion CQuaternion::operator * (CQuaternion &quat)
{ {
CQuaternion Temp; CQuaternion Temp;
Temp.m_W = (m_W * quat.m_W) - (m_V.Dot(quat.m_V)); Temp.m_W = (m_W * quat.m_W) - (m_V.Dot(quat.m_V));
Temp.m_V = (m_V.Cross(quat.m_V)) + (quat.m_V * m_W) + (m_V * quat.m_W); Temp.m_V = (m_V.Cross(quat.m_V)) + (quat.m_V * m_W) + (m_V * quat.m_W);
return Temp; return Temp;
} }
//quaternion multiplication/assignment //quaternion multiplication/assignment
CQuaternion &CQuaternion::operator *= (CQuaternion &quat) CQuaternion &CQuaternion::operator *= (CQuaternion &quat)
{ {
(*this) = (*this) * quat; (*this) = (*this) * quat;
return (*this); return (*this);
} }
void CQuaternion::FromEularAngles (float x, float y, float z) void CQuaternion::FromEularAngles (float x, float y, float z)
{ {
float cr, cp, cy; float cr, cp, cy;
float sr, sp, sy; float sr, sp, sy;
CQuaternion QRoll, QPitch, QYaw; CQuaternion QRoll, QPitch, QYaw;
cr = cosf(x * 0.5f); cr = cosf(x * 0.5f);
cp = cosf(y * 0.5f); cp = cosf(y * 0.5f);
cy = cosf(z * 0.5f); cy = cosf(z * 0.5f);
sr = sinf(x * 0.5f); sr = sinf(x * 0.5f);
sp = sinf(y * 0.5f); sp = sinf(y * 0.5f);
sy = sinf(z * 0.5f); sy = sinf(z * 0.5f);
QRoll.m_V.Set (sr,0,0); QRoll.m_V.Set (sr,0,0);
QRoll.m_W = cr; QRoll.m_W = cr;
QPitch.m_V.Set (0,sp,0); QPitch.m_V.Set (0,sp,0);
QPitch.m_W = cp; QPitch.m_W = cp;
QYaw.m_V.Set (0,0,sy); QYaw.m_V.Set (0,0,sy);
QYaw.m_W = cy; QYaw.m_W = cy;
(*this) = QYaw * QPitch * QRoll; (*this) = QYaw * QPitch * QRoll;
} }
CMatrix3D CQuaternion::ToMatrix () CMatrix3D CQuaternion::ToMatrix () const
{ {
CMatrix3D R; CMatrix3D result;
float x2, y2, z2; ToMatrix(result);
float wx, wy, wz, xx, xy, xz, yy, yz, zz; return result;
}
// calculate coefficients
x2 = m_V.X + m_V.X; void CQuaternion::ToMatrix(CMatrix3D& result) const
y2 = m_V.Y + m_V.Y; {
z2 = m_V.Z + m_V.Z; float x2, y2, z2;
float wx, wy, wz, xx, xy, xz, yy, yz, zz;
xx = m_V.X * x2;
xy = m_V.X * y2; // calculate coefficients
xz = m_V.X * z2; x2 = m_V.X + m_V.X;
y2 = m_V.Y + m_V.Y;
yy = m_V.Y * y2; z2 = m_V.Z + m_V.Z;
yz = m_V.Y * z2;
xx = m_V.X * x2;
zz = m_V.Z * z2; xy = m_V.X * y2;
xz = m_V.X * z2;
wx = m_W * x2;
wy = m_W * y2; yy = m_V.Y * y2;
wz = m_W * z2; yz = m_V.Y * z2;
R.SetIdentity(); zz = m_V.Z * z2;
R._11 = 1.0f - (yy + zz); wx = m_W * x2;
R._12 = xy - wz; wy = m_W * y2;
R._13 = xz + wy; wz = m_W * z2;
R._21 = xy + wz; result._11 = 1.0f - (yy + zz);
R._22 = 1.0f - (xx + zz); result._12 = xy - wz;
R._23 = yz - wx; result._13 = xz + wy;
result._14 = 0;
R._31 = xz - wy;
R._32 = yz + wx; result._21 = xy + wz;
R._33 = 1.0f - (xx + yy); result._22 = 1.0f - (xx + zz);
result._23 = yz - wx;
return R; result._24 = 0;
}
result._31 = xz - wy;
void CQuaternion::Slerp(CQuaternion &from, CQuaternion &to, float ratio) result._32 = yz + wx;
{ result._33 = 1.0f - (xx + yy);
float to1[4]; result._34 = 0;
float omega, cosom, sinom, scale0, scale1;
result._41 = 0;
// calc cosine result._42 = 0;
cosom = from.m_V.X * to.m_V.X + result._43 = 0;
from.m_V.Y * to.m_V.Y + result._44 = 1;
from.m_V.Z * to.m_V.Z + }
from.m_W * to.m_W;
void CQuaternion::Slerp(const CQuaternion& from,const CQuaternion& to, float ratio)
{
// adjust signs (if necessary) float to1[4];
if (cosom < 0.0) float omega, cosom, sinom, scale0, scale1;
{
cosom = -cosom; // calc cosine
to1[0] = -to.m_V.X; cosom = from.m_V.X * to.m_V.X +
to1[1] = -to.m_V.Y; from.m_V.Y * to.m_V.Y +
to1[2] = -to.m_V.Z; from.m_V.Z * to.m_V.Z +
to1[3] = -to.m_W; from.m_W * to.m_W;
}
else
{ // adjust signs (if necessary)
to1[0] = to.m_V.X; if (cosom < 0.0)
to1[1] = to.m_V.Y; {
to1[2] = to.m_V.Z; cosom = -cosom;
to1[3] = to.m_W; to1[0] = -to.m_V.X;
} to1[1] = -to.m_V.Y;
to1[2] = -to.m_V.Z;
// calculate coefficients to1[3] = -to.m_W;
if ((1.0f - cosom) > EPSILON) }
{ else
// standard case (slerp) {
omega = acosf(cosom); to1[0] = to.m_V.X;
sinom = sinf(omega); to1[1] = to.m_V.Y;
scale0 = sinf((1.0f - ratio) * omega) / sinom; to1[2] = to.m_V.Z;
scale1 = sinf(ratio * omega) / sinom; to1[3] = to.m_W;
} }
else
{ // calculate coefficients
// "from" and "to" quaternions are very close if ((1.0f - cosom) > EPSILON)
// ... so we can do a linear interpolation {
scale0 = 1.0f - ratio; // standard case (slerp)
scale1 = ratio; omega = acosf(cosom);
} sinom = sinf(omega);
scale0 = sinf((1.0f - ratio) * omega) / sinom;
// calculate final values scale1 = sinf(ratio * omega) / sinom;
m_V.X = scale0 * from.m_V.X + scale1 * to1[0]; }
m_V.Y = scale0 * from.m_V.Y + scale1 * to1[1]; else
m_V.Z = scale0 * from.m_V.Z + scale1 * to1[2]; {
m_W = scale0 * from.m_W + scale1 * to1[3]; // "from" and "to" quaternions are very close
} // ... so we can do a linear interpolation
scale0 = 1.0f - ratio;
scale1 = ratio;
}
// calculate final values
m_V.X = scale0 * from.m_V.X + scale1 * to1[0];
m_V.Y = scale0 * from.m_V.Y + scale1 * to1[1];
m_V.Z = scale0 * from.m_V.Z + scale1 * to1[2];
m_W = scale0 * from.m_W + scale1 * to1[3];
}

View File

@ -1,42 +1,43 @@
/************************************************************ /************************************************************
* *
* File Name: Quaternion.H * File Name: Quaternion.H
* *
* Description: * Description:
* *
************************************************************/ ************************************************************/
#ifndef QUATERNION_H #ifndef QUATERNION_H
#define QUATERNION_H #define QUATERNION_H
#include "Matrix3D.h" #include "Matrix3D.h"
class CQuaternion class CQuaternion
{ {
public: public:
CVector3D m_V; CVector3D m_V;
float m_W; float m_W;
public: public:
CQuaternion(); CQuaternion();
//quaternion addition //quaternion addition
CQuaternion operator + (CQuaternion &quat); CQuaternion operator + (CQuaternion &quat);
//quaternion addition/assignment //quaternion addition/assignment
CQuaternion &operator += (CQuaternion &quat); CQuaternion &operator += (CQuaternion &quat);
//quaternion multiplication //quaternion multiplication
CQuaternion operator * (CQuaternion &quat); CQuaternion operator * (CQuaternion &quat);
//quaternion multiplication/assignment //quaternion multiplication/assignment
CQuaternion &operator *= (CQuaternion &quat); CQuaternion &operator *= (CQuaternion &quat);
void FromEularAngles (float x, float y, float z); void FromEularAngles (float x, float y, float z);
//convert the quaternion to matrix //convert the quaternion to matrix
CMatrix3D ToMatrix (); CMatrix3D ToMatrix() const;
void ToMatrix(CMatrix3D& result) const;
//sphere interpolation
void Slerp(CQuaternion &from, CQuaternion &to, float ratio); //sphere interpolation
}; void Slerp(const CQuaternion& from,const CQuaternion& to, float ratio);
};
#endif
#endif

View File

@ -1,52 +1,94 @@
#ifndef _RENDERABLEOBJECT_H ///////////////////////////////////////////////////////////////////////////////
#define _RENDERABLEOBJECT_H //
// Name: RenderableObject.h
#include "res/res.h" // Author: Rich Cross
#include "types.h" // Contact: rich@wildfiregames.com
#include "terrain/Bound.h" //
#include "terrain/Matrix3D.h" ///////////////////////////////////////////////////////////////////////////////
#ifndef _RENDERABLEOBJECT_H
// dirty flags #define _RENDERABLEOBJECT_H
#define RENDERDATA_UPDATE_VERTICES (1<<1)
#define RENDERDATA_UPDATE_INDICES (1<<2) #include <assert.h>
#include "res/res.h"
class CRenderData #include "terrain/Bound.h"
{ #include "terrain/Matrix3D.h"
public:
CRenderData() : m_UpdateFlags(0) {}
virtual ~CRenderData() {} // dirty flags - used as notification to the renderer that some bit of data
// need updating
u32 m_UpdateFlags; #define RENDERDATA_UPDATE_VERTICES (1<<1)
}; #define RENDERDATA_UPDATE_INDICES (1<<2)
class CRenderableObject
{ ///////////////////////////////////////////////////////////////////////////////
public: // CRenderData: base class of all the renderer's renderdata classes - the
CRenderableObject() : m_RenderData(0) { // derived class stores necessary information for rendering an object of a
m_Transform.SetIdentity(); // particular type
} class CRenderData
virtual ~CRenderableObject() { delete m_RenderData; } {
public:
void SetTransform(const CMatrix3D& transform) { CRenderData() : m_UpdateFlags(0) {}
m_Transform=transform; virtual ~CRenderData() {}
CalcBounds();
} u32 m_UpdateFlags;
const CMatrix3D& GetTransform() const { return m_Transform; } };
///////////////////////////////////////////////////////////////////////////////
// CalcBounds: calculate (and store in m_Bounds) the world space bounds of this object // CRenderableObject: base class of all renderable objects - patches, models,
virtual void CalcBounds() = 0; // sprites, etc; stores position and bound information, and a pointer to
const CBound& GetBounds() const { return m_Bounds; } // some renderdata necessary for the renderer to actually render it
class CRenderableObject
// object renderdata {
CRenderData* m_RenderData; public:
// constructor
protected: CRenderableObject() : m_RenderData(0) {
// object bounds m_Transform.SetIdentity();
CBound m_Bounds; }
// local->world space transform // destructor
CMatrix3D m_Transform; virtual ~CRenderableObject() { delete m_RenderData; }
};
// set object transform
#endif void SetTransform(const CMatrix3D& transform) {
m_Transform=transform;
CalcBounds();
}
// get object transform
const CMatrix3D& GetTransform() const { return m_Transform; }
// 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;
// object renderdata
CRenderData* m_RenderData;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,251 +1,267 @@
//---------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////////
// //
// Name: Renderer.h // Name: Renderer.h
// Last Update: 25/11/03 // Author: Rich Cross
// Author: Rich Cross // Contact: rich@wildfiregames.com
// Contact: rich@0ad.wildfiregames.com //
// // Description: OpenGL renderer class; a higher level interface
// Description: OpenGL renderer class; a higher level interface // on top of OpenGL to handle rendering the basic visual games
// on top of OpenGL to handle rendering the basic visual games // types - terrain, models, sprites, particles etc
// types - terrain, models, sprites, particles etc //
//---------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////////
#ifndef RENDERER_H
#ifndef RENDERER_H #define RENDERER_H
#define RENDERER_H
#include <vector>
#include <vector> #include "res/res.h"
#include "res/res.h" #include "ogl.h"
#include "ogl.h" #include "Camera.h"
#include "Camera.h" #include "Frustum.h"
#include "Frustum.h" #include "PatchRData.h"
#include "PatchRData.h" #include "ModelRData.h"
#include "ModelRData.h" #include "SHCoeffs.h"
#include "SHCoeffs.h" #include "Terrain.h"
#include "Terrain.h"
// necessary declarations
// necessary declarations class CCamera;
class CCamera; class CPatch;
class CPatch; class CSprite;
class CVisual; class CParticleSys;
class CSprite; class COverlay;
class CParticleSys; class CMaterial;
class COverlay; class CLightEnv;
class CMaterial; class CTexture;
class CLightEnv; class CTerrain;
class CTexture;
class CTerrain;
// rendering modes
enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES };
// rendering modes
enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES }; // stream flags
#define STREAM_POS 0x01
#define STREAM_NORMAL 0x02
////////////////////////////////////////////////////////////////////////////////////////// #define STREAM_COLOR 0x04
// SSubmission: generalised class representating a submission of objects to renderer #define STREAM_UV0 0x08
template <class T> #define STREAM_UV1 0x10
struct SSubmission #define STREAM_UV2 0x20
{ #define STREAM_UV3 0x40
T m_Object;
CMatrix3D* m_Transform; //////////////////////////////////////////////////////////////////////////////////////////
}; // SVertex3D: simple 3D vertex declaration
struct SVertex3D
////////////////////////////////////////////////////////////////////////////////////////// {
// SVertex3D: simple 3D vertex declaration float m_Position[3];
struct SVertex3D float m_TexCoords[2];
{ unsigned int m_Color;
float m_Position[3]; };
float m_TexCoords[2];
unsigned int m_Color; //////////////////////////////////////////////////////////////////////////////////////////
}; // SVertex2D: simple 2D vertex declaration
struct SVertex2D
////////////////////////////////////////////////////////////////////////////////////////// {
// SVertex2D: simple 2D vertex declaration float m_Position[2];
struct SVertex2D float m_TexCoords[2];
{ unsigned int m_Color;
float m_Position[2]; };
float m_TexCoords[2];
unsigned int m_Color;
}; ///////////////////////////////////////////////////////////////////////////////////////////
// CRenderer: base renderer class - primary interface to the rendering engine
class CRenderer
/////////////////////////////////////////////////////////////////////////////////////////// {
// CRenderer: base renderer class - primary interface to the rendering engine public:
class CRenderer // various enumerations and renderer related constants
{ enum { NumAlphaMaps=14 };
public: enum Option {
// various enumerations and renderer related constants OPT_NOVBO
enum { NumAlphaMaps=14 }; };
// stats class - per frame counts of number of draw calls, poly counts etc // stats class - per frame counts of number of draw calls, poly counts etc
struct Stats { struct Stats {
// set all stats to zero // set all stats to zero
void Reset() { memset(this,0,sizeof(*this)); } void Reset() { memset(this,0,sizeof(*this)); }
// add given stats to this stats // add given stats to this stats
Stats& operator+=(const Stats& rhs) { Stats& operator+=(const Stats& rhs) {
m_Counter++; m_Counter++;
m_DrawCalls+=rhs.m_DrawCalls; m_DrawCalls+=rhs.m_DrawCalls;
m_TerrainTris+=rhs.m_TerrainTris; m_TerrainTris+=rhs.m_TerrainTris;
m_ModelTris+=rhs.m_ModelTris; m_ModelTris+=rhs.m_ModelTris;
m_TransparentTris+=rhs.m_TransparentTris; m_TransparentTris+=rhs.m_TransparentTris;
m_BlendSplats+=rhs.m_BlendSplats; m_BlendSplats+=rhs.m_BlendSplats;
return *this; return *this;
} }
// count of the number of stats added together // count of the number of stats added together
u32 m_Counter; u32 m_Counter;
// number of draw calls per frame - total DrawElements + Begin/End immediate mode loops // number of draw calls per frame - total DrawElements + Begin/End immediate mode loops
u32 m_DrawCalls; u32 m_DrawCalls;
// number of terrain triangles drawn // number of terrain triangles drawn
u32 m_TerrainTris; u32 m_TerrainTris;
// number of (non-transparent) model triangles drawn // number of (non-transparent) model triangles drawn
u32 m_ModelTris; u32 m_ModelTris;
// number of transparent model triangles drawn // number of transparent model triangles drawn
u32 m_TransparentTris; u32 m_TransparentTris;
// number of splat passes for alphamapping // number of splat passes for alphamapping
u32 m_BlendSplats; u32 m_BlendSplats;
}; };
public: public:
// constructor, destructor // constructor, destructor
CRenderer(); CRenderer();
~CRenderer(); ~CRenderer();
// open up the renderer: performs any necessary initialisation // open up the renderer: performs any necessary initialisation
bool Open(int width,int height,int depth); bool Open(int width,int height,int depth);
// shutdown the renderer: performs any necessary cleanup // shutdown the renderer: performs any necessary cleanup
void Close(); void Close();
// resize renderer view // resize renderer view
void Resize(int width,int height); void Resize(int width,int height);
// signal frame start // set boolean renderer option
void BeginFrame(); void SetOption(enum Option opt,bool value);
// force rendering of any batched objects
void FlushFrame(); // return view width
// signal frame end : implicitly flushes batched objects int GetWidth() const { return m_Width; }
void EndFrame(); // return view height
int GetHeight() const { return m_Height; }
// return current frame counter // return view aspect ratio
int GetFrameCounter() const { return m_FrameCounter; } float GetAspect() const { return float(m_Width)/float(m_Height); }
// set camera used for subsequent rendering operations; includes viewport, projection and modelview matrices // signal frame start
void SetCamera(CCamera& camera); void BeginFrame();
// force rendering of any batched objects
// submission of objects for rendering; the passed matrix indicating the transform must be scoped such that it is valid beyond void FlushFrame();
// the call to frame end, as must the object itself // signal frame end : implicitly flushes batched objects
void Submit(CPatch* patch); void EndFrame();
void Submit(CVisual* visual);
void Submit(CSprite* sprite,CMatrix3D* transform); // set color used to clear screen in BeginFrame()
void Submit(CParticleSys* psys,CMatrix3D* transform); void SetClearColor(u32 color);
void Submit(COverlay* overlay);
// return current frame counter
// basic primitive rendering operations in 2 and 3D; handy for debugging stuff, but also useful in int GetFrameCounter() const { return m_FrameCounter; }
// editor tools (eg for highlighting specific terrain patches)
// note: // set camera used for subsequent rendering operations; includes viewport, projection and modelview matrices
// * all 3D vertices specified in world space void SetCamera(CCamera& camera);
// * primitive operations rendered immediatedly, never batched
// * primitives rendered in current material (set via SetMaterial) // submission of objects for rendering; the passed matrix indicating the transform must be scoped such that it is valid beyond
void RenderLine(const SVertex2D* vertices); // the call to frame end, as must the object itself
void RenderLineLoop(int len,const SVertex2D* vertices); void Submit(CPatch* patch);
void RenderTri(const SVertex2D* vertices); void Submit(CModel* model);
void RenderQuad(const SVertex2D* vertices); void Submit(CSprite* sprite);
void RenderLine(const SVertex3D* vertices); void Submit(CParticleSys* psys);
void RenderLineLoop(int len,const SVertex3D* vertices); void Submit(COverlay* overlay);
void RenderTri(const SVertex3D* vertices);
void RenderQuad(const SVertex3D* vertices); // basic primitive rendering operations in 2 and 3D; handy for debugging stuff, but also useful in
// editor tools (eg for highlighting specific terrain patches)
// set the current lighting environment; (note: the passed pointer is just copied to a variable within the renderer, // note:
// so the lightenv passed must be scoped such that it is not destructed until after the renderer is no longer rendering) // * all 3D vertices specified in world space
void SetLightEnv(CLightEnv* lightenv) { // * primitive operations rendered immediatedly, never batched
m_LightEnv=lightenv; // * primitives rendered in current material (set via SetMaterial)
} void RenderLine(const SVertex2D* vertices);
void RenderLineLoop(int len,const SVertex2D* vertices);
// set the mode to render subsequent terrain patches void RenderTri(const SVertex2D* vertices);
void SetTerrainRenderMode(ERenderMode mode) { m_TerrainRenderMode=mode; } void RenderQuad(const SVertex2D* vertices);
// get the mode to render subsequent terrain patches void RenderLine(const SVertex3D* vertices);
ERenderMode GetTerrainRenderMode() const { return m_TerrainRenderMode; } void RenderLineLoop(int len,const SVertex3D* vertices);
void RenderTri(const SVertex3D* vertices);
// set the mode to render subsequent models void RenderQuad(const SVertex3D* vertices);
void SetModelRenderMode(ERenderMode mode) { m_ModelRenderMode=mode; }
// get the mode to render subsequent models // set the current lighting environment; (note: the passed pointer is just copied to a variable within the renderer,
ERenderMode GetModelRenderMode() const { return m_ModelRenderMode; } // so the lightenv passed must be scoped such that it is not destructed until after the renderer is no longer rendering)
void SetLightEnv(CLightEnv* lightenv) {
// try and load the given texture m_LightEnv=lightenv;
bool LoadTexture(CTexture* texture); }
// set the given unit to reference the given texture; pass a null texture to disable texturing on any unit
// note - active texture always set to given unit on exit // set the mode to render subsequent terrain patches
void SetTexture(int unit,CTexture* texture,u32 wrapflags=0); void SetTerrainRenderMode(ERenderMode mode) { m_TerrainRenderMode=mode; }
// query transparency of given texture // get the mode to render subsequent terrain patches
bool IsTextureTransparent(CTexture* texture); ERenderMode GetTerrainRenderMode() const { return m_TerrainRenderMode; }
// load the default set of alphamaps; return false if any alphamap fails to load, true otherwise // set the mode to render subsequent models
bool LoadAlphaMaps(const char* fnames[]); void SetModelRenderMode(ERenderMode mode) { m_ModelRenderMode=mode; }
// get the mode to render subsequent models
// return stats accumulated for current frame ERenderMode GetModelRenderMode() const { return m_ModelRenderMode; }
const Stats& GetStats() { return m_Stats; }
// try and load the given texture
inline int GetWidth() const { return m_Width; } bool LoadTexture(CTexture* texture);
inline int GetHeight() const { return m_Height; } // set the given unit to reference the given texture; pass a null texture to disable texturing on any unit
// note - active texture always set to given unit on exit
protected: void SetTexture(int unit,CTexture* texture,u32 wrapflags=0);
friend class CPatchRData; // query transparency of given texture
friend class CModelRData; bool IsTextureTransparent(CTexture* texture);
friend class CTransparencyRenderer;
// load the default set of alphamaps; return false if any alphamap fails to load, true otherwise
// patch rendering stuff bool LoadAlphaMaps(const char* fnames[]);
void RenderPatchSubmissions();
void RenderPatches(); // return stats accumulated for current frame
const Stats& GetStats() { return m_Stats; }
// model rendering stuff
void BuildTransparentPasses(CVisual* visual); protected:
void RenderModelSubmissions(); friend class CPatchRData;
void RenderModels(); friend class CModelRData;
friend class CTransparencyRenderer;
// RENDERER DATA:
// view width // update renderdata of everything submitted
int m_Width; void UpdateSubmittedObjectData();
// view height
int m_Height; // patch rendering stuff
// view depth (bpp) void RenderPatchSubmissions();
int m_Depth; void RenderPatches();
// frame counter
int m_FrameCounter; // model rendering stuff
// current terrain rendering mode void BuildTransparentPasses(CModel* model);
ERenderMode m_TerrainRenderMode; void RenderModelSubmissions();
// current model rendering mode void RenderModels();
ERenderMode m_ModelRenderMode;
// current view camera // RENDERER DATA:
CCamera m_Camera; // view width
// submitted object lists for batching int m_Width;
std::vector<SSubmission<CPatch*> > m_TerrainPatches; // view height
std::vector<SSubmission<CVisual*> > m_Models; int m_Height;
std::vector<SSubmission<CSprite*> > m_Sprites; // view depth (bpp)
std::vector<SSubmission<CParticleSys*> > m_ParticleSyses; int m_Depth;
std::vector<SSubmission<COverlay*> > m_Overlays; // frame counter
// current lighting setup int m_FrameCounter;
CLightEnv* m_LightEnv; // current terrain rendering mode
// current spherical harmonic coefficients (for unit lighting), derived from lightenv ERenderMode m_TerrainRenderMode;
CSHCoeffs m_SHCoeffsUnits; // current model rendering mode
// current spherical harmonic coefficients (for terrain lighting), derived from lightenv ERenderMode m_ModelRenderMode;
CSHCoeffs m_SHCoeffsTerrain; // current view camera
// default alpha maps CCamera m_Camera;
//Handle m_AlphaMaps[NumAlphaMaps]; // color used to clear screen in BeginFrame
// all the alpha maps packed into one texture float m_ClearColor[4];
unsigned int m_CompositeAlphaMap; // submitted object lists for batching
// coordinates of each (untransformed) alpha map within the packed texture std::vector<CPatch*> m_TerrainPatches;
struct { std::vector<CModel*> m_Models;
float u0,u1,v0,v1; std::vector<CSprite*> m_Sprites;
} m_AlphaMapCoords[NumAlphaMaps]; std::vector<CParticleSys*> m_ParticleSyses;
std::vector<COverlay*> m_Overlays;
// card capabilities // current lighting setup
struct Caps { CLightEnv* m_LightEnv;
bool m_VBO; // current spherical harmonic coefficients (for unit lighting), derived from lightenv
} m_Caps; CSHCoeffs m_SHCoeffsUnits;
// build card cap bits // current spherical harmonic coefficients (for terrain lighting), derived from lightenv
void EnumCaps(); CSHCoeffs m_SHCoeffsTerrain;
// per-frame renderer stats // handle of composite alpha map (all the alpha maps packed into one texture)
Stats m_Stats; u32 m_CompositeAlphaMap;
}; // coordinates of each (untransformed) alpha map within the packed texture
struct {
float u0,u1,v0,v1;
#endif } m_AlphaMapCoords[NumAlphaMaps];
// renderer options
bool m_OptNOVBO;
// card capabilities
struct Caps {
bool m_VBO;
} m_Caps;
// build card cap bits
void EnumCaps();
// per-frame renderer stats
Stats m_Stats;
};
// declaration of sole renderer object
extern CRenderer g_Renderer;
#endif

View File

@ -1,69 +1,77 @@
//---------------------------------------------------------------- //----------------------------------------------------------------
// //
// Name: SHCoeffs.h // Name: SHCoeffs.h
// Last Update: 25/11/03 // Last Update: 25/11/03
// Author: Rich Cross // Author: Rich Cross
// Contact: rich@0ad.wildfiregames.com // Contact: rich@0ad.wildfiregames.com
// //
// Description: implementation of 9 component spherical harmonic // Description: implementation of 9 component spherical harmonic
// lighting // lighting
//---------------------------------------------------------------- //----------------------------------------------------------------
#include "SHCoeffs.h" #include "SHCoeffs.h"
CSHCoeffs::CSHCoeffs() CSHCoeffs::CSHCoeffs()
{ {
Clear(); Clear();
} }
void CSHCoeffs::Clear() void CSHCoeffs::Clear()
{ {
for (int i=0;i<9;i++) { for (int i=0;i<9;i++) {
_data[i].Clear(); _data[i].Clear();
} }
} }
void CSHCoeffs::AddAmbientLight(const RGBColor& color) void CSHCoeffs::AddAmbientLight(const RGBColor& color)
{ {
_data[0]+=color; _data[0]+=color;
} }
void CSHCoeffs::AddDirectionalLight(const CVector3D& lightDir,const RGBColor& lightColor) void CSHCoeffs::AddDirectionalLight(const CVector3D& lightDir,const RGBColor& lightColor)
{ {
CVector3D dirToLight(-lightDir.X,-lightDir.Y,-lightDir.Z); CVector3D dirToLight(-lightDir.X,-lightDir.Y,-lightDir.Z);
const float normalisation = PI*16/17; const float normalisation = PI*16/17;
const float c1 = SQR(0.282095f) * normalisation * 1.0f; const float c1 = SQR(0.282095f) * normalisation * 1.0f;
const float c2 = SQR(0.488603f) * normalisation * (2.0f/3.0f); const float c2 = SQR(0.488603f) * normalisation * (2.0f/3.0f);
const float c3 = SQR(1.092548f) * normalisation * (1.0f/4.0f); const float c3 = SQR(1.092548f) * normalisation * (1.0f/4.0f);
const float c4 = SQR(0.315392f) * normalisation * (1.0f/4.0f); const float c4 = SQR(0.315392f) * normalisation * (1.0f/4.0f);
const float c5 = SQR(0.546274f) * normalisation * (1.0f/4.0f); const float c5 = SQR(0.546274f) * normalisation * (1.0f/4.0f);
_data[0]+=lightColor*c1; _data[0]+=lightColor*c1;
_data[1]+=lightColor*c2*dirToLight.X; _data[1]+=lightColor*c2*dirToLight.X;
_data[2]+=lightColor*c2*dirToLight.Y; _data[2]+=lightColor*c2*dirToLight.Y;
_data[3]+=lightColor*c2*dirToLight.Z; _data[3]+=lightColor*c2*dirToLight.Z;
_data[4]+=lightColor*c3*dirToLight.X*dirToLight.Z; _data[4]+=lightColor*c3*dirToLight.X*dirToLight.Z;
_data[5]+=lightColor*c3*dirToLight.Z*dirToLight.Y; _data[5]+=lightColor*c3*dirToLight.Z*dirToLight.Y;
_data[6]+=lightColor*c3*dirToLight.Y*dirToLight.X; _data[6]+=lightColor*c3*dirToLight.Y*dirToLight.X;
_data[7]+=lightColor*c4*(3.0f*SQR(dirToLight.Z)-1.0f); _data[7]+=lightColor*c4*(3.0f*SQR(dirToLight.Z)-1.0f);
_data[8]+=lightColor*c5*(SQR(dirToLight.X)-SQR(dirToLight.Y)); _data[8]+=lightColor*c5*(SQR(dirToLight.X)-SQR(dirToLight.Y));
} }
void CSHCoeffs::Evaluate(const CVector3D& normal,RGBColor& color) const void CSHCoeffs::Evaluate(const CVector3D& normal,RGBColor& color) const
{ {
#if 1 #if 1
color=_data[0]; float c4=normal.X*normal.Z;
color+=_data[1]*normal.X; float c5=normal.Z*normal.Y;
color+=_data[2]*normal.Y; float c6=normal.Y*normal.X;
color+=_data[3]*normal.Z; float c7=(3*SQR(normal.Z)-1.0f);
color+=_data[4]*(normal.X*normal.Z); float c8=(SQR(normal.X)-SQR(normal.Y));
color+=_data[5]*(normal.Z*normal.Y);
color+=_data[6]*(normal.Y*normal.X); for (int i=0;i<3;i++) {
color+=_data[7]*(3*SQR(normal.Z)-1.0f); color[i]=_data[0][i];
color+=_data[8]*(SQR(normal.X)-SQR(normal.Y)); color[i]+=_data[1][i]*normal.X;
#else color[i]+=_data[2][i]*normal.Y;
// debug aid: output quantised normal color[i]+=_data[3][i]*normal.Z;
color=RGBColor((normal.X+1)*0.5,(normal.Y+1)*0.5,(normal.Z+1)*0.5); color[i]+=_data[4][i]*c4;
#endif color[i]+=_data[5][i]*c5;
} color[i]+=_data[6][i]*c6;
color[i]+=_data[7][i]*c7;
color[i]+=_data[8][i]*c8;
}
#else
// debug aid: output quantised normal
color=RGBColor((normal.X+1)*0.5,(normal.Y+1)*0.5,(normal.Z+1)*0.5);
#endif
}

105
source/terrain/SkeletonAnim.cpp Executable file
View File

@ -0,0 +1,105 @@
///////////////////////////////////////////////////////////////////////////////
//
// Name: SkeletonAnim.cpp
// Author: Rich Cross
// Contact: rich@wildfiregames.com
//
///////////////////////////////////////////////////////////////////////////////
#include "SkeletonAnim.h"
#include "FilePacker.h"
#include "FileUnpacker.h"
///////////////////////////////////////////////////////////////////////////////////////////
// CSkeletonAnim constructor
CSkeletonAnim::CSkeletonAnim() : m_Keys(0), m_NumKeys(0), m_NumFrames(0), m_FrameTime(0)
{
m_Name[0]='\0';
}
///////////////////////////////////////////////////////////////////////////////////////////
// CSkeletonAnim destructor
CSkeletonAnim::~CSkeletonAnim()
{
delete[] m_Keys;
}
///////////////////////////////////////////////////////////////////////////////////////////
// BuildBoneMatrices: build matrices for all bones at the given time (in MS) in this
// animation
void CSkeletonAnim::BuildBoneMatrices(float time,CMatrix3D* matrices) const
{
float fstartframe=time/m_FrameTime;
u32 startframe=u32(time/m_FrameTime);
float deltatime=fstartframe-startframe;
startframe%=m_NumFrames;
u32 endframe=startframe+1;
endframe%=m_NumFrames;
u32 i;
for (i=0;i<m_NumKeys;i++) {
const Key& startkey=GetKey(startframe,i);
const Key& endkey=GetKey(endframe,i);
CVector3D trans=startkey.m_Translation*(1-deltatime)+endkey.m_Translation*deltatime;
CQuaternion rot;
rot.Slerp(startkey.m_Rotation,endkey.m_Rotation,deltatime);
matrices[i].SetIdentity();
matrices[i].Rotate(rot);
matrices[i].Translate(trans);
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Load: try to load the anim from given file; return a new anim if successful
CSkeletonAnim* CSkeletonAnim::Load(const char* filename)
{
CFileUnpacker unpacker;
unpacker.Read(filename,"PSSA");
// check version
if (unpacker.GetVersion()<FILE_READ_VERSION) {
throw CFileUnpacker::CFileVersionError();
}
// unpack the data
CSkeletonAnim* anim=new CSkeletonAnim;
try {
CStr str;
unpacker.UnpackString(str);
strcpy(anim->m_Name,(const char*) str);
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 CSkeletonAnim::Save(const char* filename,const CSkeletonAnim* 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");
}

82
source/terrain/SkeletonAnim.h Executable file
View File

@ -0,0 +1,82 @@
///////////////////////////////////////////////////////////////////////////////
//
// Name: SkeletonAnim.h
// Author: Rich Cross
// Contact: rich@wildfiregames.com
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _SKELETONANIM_H
#define _SKELETONANIM_H
#include "res/res.h"
#include "Vector3D.h"
#include "Quaternion.h"
#ifndef MAX_NAME_LENGTH
#define MAX_NAME_LENGTH 128
#endif
////////////////////////////////////////////////////////////////////////////////////////
// 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;
};
////////////////////////////////////////////////////////////////////////////////////////
// CSkeletonAnim: description of an animation that plays upon a skeleton
class CSkeletonAnim
{
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:
// CSkeletonAnim constructor + destructor
CSkeletonAnim();
~CSkeletonAnim();
// 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; }
// 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 CSkeletonAnim* Load(const char* filename);
static void Save(const char* filename,const CSkeletonAnim* anim);
public:
// name of the animation
char m_Name[MAX_NAME_LENGTH];
// 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

View File

@ -1,20 +0,0 @@
//***********************************************************
//
// Name: TerrGlobals.H
// Last Update: 27/2/02
// Author: Poya Manouchehri
//
// Description: Some globals and macros, used by the CTerrain
// and CPatch
//
//***********************************************************
#ifndef TERRGLOBALS_H
#define TERRGLOBALS_H
const int PATCH_SIZE = 16;
const int CELL_SIZE = 4; //horizontal scale of the patches
const float HEIGHT_SCALE = 0.35f/256.0f;
#endif

View File

@ -1,280 +1,292 @@
//*********************************************************** ///////////////////////////////////////////////////////////////////////////////
// //
// Name: Terrain.Cpp // Name: Terrain.cpp
// Last Update: 23/2/02 // Author: Rich Cross
// Author: Poya Manouchehri // Contact: rich@wildfiregames.com
// //
// Description: CTerrain handles the terrain portion of the ///////////////////////////////////////////////////////////////////////////////
// engine. It holds open the file to the terrain
// information, so terrain data can be loaded #include "res/tex.h"
// dynamically. We use a ROAM method to render #include "res/mem.h"
// the terrain, ie using binary triangle trees.
// The terrain consists of smaller PATCHS, which #include <string.h>
// do most of the work. #include "Terrain.h"
//
//***********************************************************
///////////////////////////////////////////////////////////////////////////////
// CTerrain constructor
#include "res/tex.h" CTerrain::CTerrain() : m_Heightmap(0), m_Patches(0), m_MapSize(0), m_MapSizePatches(0)
#include "res/mem.h" {
}
#include <string.h>
#include "Terrain.h" ///////////////////////////////////////////////////////////////////////////////
// CTerrain constructor
CTerrain::~CTerrain()
CTerrain::CTerrain() {
{ ReleaseData();
m_Heightmap = NULL; }
m_Patches = NULL;
m_MapSize = 0;
m_MapSizePatches = 0; ///////////////////////////////////////////////////////////////////////////////
} // ReleaseData: delete any data allocated by this terrain
void CTerrain::ReleaseData()
CTerrain::~CTerrain() {
{ delete[] m_Heightmap;
Reset(); delete[] m_Patches;
} }
void CTerrain::Reset() ///////////////////////////////////////////////////////////////////////////////
{ // Initialise: initialise this terrain to the given size (in patches per side);
delete[] m_Heightmap; // using given heightmap to setup elevation data
delete[] m_Patches; bool CTerrain::Initialize(u32 size,const u16* data)
} {
// clean up any previous terrain
ReleaseData();
bool CTerrain::Initialize(u32 size,const u16* data)
{ // store terrain size
// clean up any previous terrain m_MapSize=(size*PATCH_SIZE)+1;
Reset(); m_MapSizePatches=size;
// store terrain size // allocate data for new terrain
m_MapSize=(size*PATCH_SIZE)+1; m_Heightmap=new u16[m_MapSize*m_MapSize];
m_MapSizePatches=size; m_Patches=new CPatch[m_MapSizePatches*m_MapSizePatches];
// allocate data for new terrain // given a heightmap?
m_Heightmap=new u16[m_MapSize*m_MapSize]; if (data) {
m_Patches=new CPatch[m_MapSizePatches*m_MapSizePatches]; // yes; keep a copy of it
memcpy(m_Heightmap,data,m_MapSize*m_MapSize*sizeof(u16));
// given a heightmap? } else {
if (data) { // build a flat terrain
// yes; keep a copy of it memset(m_Heightmap,0,m_MapSize*m_MapSize*sizeof(u16));
memcpy(m_Heightmap,data,m_MapSize*m_MapSize*sizeof(u16)); }
} else {
// build a flat terrain // setup patch parents, indices etc
memset(m_Heightmap,0,m_MapSize*m_MapSize*sizeof(u16)); InitialisePatches();
}
return true;
// 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)
{
void CTerrain::CalcPosition(u32 i,u32 j,CVector3D& pos) u16 height=m_Heightmap[j*m_MapSize + i];
{ pos.X = float(i)*CELL_SIZE;
u16 height=m_Heightmap[j*m_MapSize + i]; pos.Y = float(height)*HEIGHT_SCALE;
pos.X = float(i)*CELL_SIZE; pos.Z = float(j)*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) void CTerrain::CalcNormal(u32 i,u32 j,CVector3D& normal)
{ {
CVector3D left, right, up, down; CVector3D left, right, up, down;
left.Clear(); left.Clear();
right.Clear(); right.Clear();
up.Clear(); up.Clear();
down.Clear(); down.Clear();
// get position of vertex where normal is being evaluated // get position of vertex where normal is being evaluated
CVector3D basepos; CVector3D basepos;
CalcPosition(i,j,basepos); CalcPosition(i,j,basepos);
CVector3D tmp; CVector3D tmp;
if (i>0) { if (i>0) {
CalcPosition(i-1,j,tmp); CalcPosition(i-1,j,tmp);
left=tmp-basepos; left=tmp-basepos;
} }
if (i<m_MapSize-1) { if (i<m_MapSize-1) {
CalcPosition(i+1,j,tmp); CalcPosition(i+1,j,tmp);
right=tmp-basepos; right=tmp-basepos;
} }
if (j>0) { if (j>0) {
CalcPosition(i,j-1,tmp); CalcPosition(i,j-1,tmp);
up=tmp-basepos; up=tmp-basepos;
} }
if (j<m_MapSize-1) { if (j<m_MapSize-1) {
CalcPosition(i,j+1,tmp); CalcPosition(i,j+1,tmp);
down=tmp-basepos; down=tmp-basepos;
} }
CVector3D n0 = up.Cross(left); CVector3D n0 = up.Cross(left);
CVector3D n1 = left.Cross(down); CVector3D n1 = left.Cross(down);
CVector3D n2 = down.Cross(right); CVector3D n2 = down.Cross(right);
CVector3D n3 = right.Cross(up); CVector3D n3 = right.Cross(up);
normal = n0 + n1 + n2 + n3; normal = n0 + n1 + n2 + n3;
float nlen=normal.GetLength(); float nlen=normal.GetLength();
if (nlen>0.00001f) normal*=1.0f/nlen; if (nlen>0.00001f) normal*=1.0f/nlen;
} }
CPatch* CTerrain::GetPatch(int32 x,int32 z) ///////////////////////////////////////////////////////////////////////////////
{ // GetPatch: return the patch at (x,z) in patch space, or null if the patch is
if (x<0 || x>=int32(m_MapSizePatches)) return 0; // out of bounds
if (z<0 || z>=int32(m_MapSizePatches)) return 0; CPatch* CTerrain::GetPatch(int32 x,int32 z)
return &m_Patches[(z*m_MapSizePatches)+x]; {
} if (x<0 || x>=int32(m_MapSizePatches)) return 0;
if (z<0 || z>=int32(m_MapSizePatches)) return 0;
CMiniPatch* CTerrain::GetTile(int32 x,int32 z) return &m_Patches[(z*m_MapSizePatches)+x];
{ }
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); // GetPatch: return the tile at (x,z) in tile space, or null if the tile is out
return &patch->m_MiniPatches[z%16][x%16]; // of bounds
} CMiniPatch* CTerrain::GetTile(int32 x,int32 z)
{
if (x<0 || x>=int32(m_MapSize)-1) return 0;
void CTerrain::Resize(u32 size) if (z<0 || z>=int32(m_MapSize)-1) return 0;
{
if (size==m_MapSizePatches) { CPatch* patch=GetPatch(x/16,z/16);
// inexplicable request to resize terrain to the same size .. ignore it return &patch->m_MiniPatches[z%16][x%16];
return; }
}
if (!m_Heightmap) { ///////////////////////////////////////////////////////////////////////////////
// not yet created a terrain; build a default terrain of the given size now // Resize: resize this terrain to the given size (in patches per side)
Initialize(size,0); void CTerrain::Resize(u32 size)
return; {
} if (size==m_MapSizePatches) {
// inexplicable request to resize terrain to the same size .. ignore it
// allocate data for new terrain return;
u32 newMapSize=(size*PATCH_SIZE)+1; }
u16* newHeightmap=new u16[newMapSize*newMapSize];
CPatch* newPatches=new CPatch[size*size]; if (!m_Heightmap) {
// not yet created a terrain; build a default terrain of the given size now
if (size>m_MapSizePatches) { Initialize(size,0);
// new map is bigger than old one - zero the heightmap so we don't get uninitialised return;
// height data along the expanded edges }
memset(newHeightmap,0,newMapSize*newMapSize);
} // allocate data for new terrain
u32 newMapSize=(size*PATCH_SIZE)+1;
// now copy over rows of data u16* newHeightmap=new u16[newMapSize*newMapSize];
u32 j; CPatch* newPatches=new CPatch[size*size];
u16* src=m_Heightmap;
u16* dst=newHeightmap; if (size>m_MapSizePatches) {
u32 copysize=newMapSize>m_MapSize ? m_MapSize : newMapSize; // new map is bigger than old one - zero the heightmap so we don't get uninitialised
for (j=0;j<copysize;j++) { // height data along the expanded edges
memcpy(dst,src,copysize*sizeof(u16)); memset(newHeightmap,0,newMapSize*newMapSize);
dst+=copysize; }
src+=m_MapSize;
if (newMapSize>m_MapSize) { // now copy over rows of data
// entend the last height to the end of the row u32 j;
for (u32 i=0;i<newMapSize-m_MapSize;i++) { u16* src=m_Heightmap;
*dst++=*(src-1); u16* dst=newHeightmap;
} u32 copysize=newMapSize>m_MapSize ? m_MapSize : newMapSize;
} for (j=0;j<copysize;j++) {
} memcpy(dst,src,copysize*sizeof(u16));
dst+=copysize;
src+=m_MapSize;
if (newMapSize>m_MapSize) { if (newMapSize>m_MapSize) {
// copy over heights of the last row to any remaining rows // entend the last height to the end of the row
src=newHeightmap+((m_MapSize-1)*newMapSize); for (u32 i=0;i<newMapSize-m_MapSize;i++) {
dst=src+newMapSize; *dst++=*(src-1);
for (u32 i=0;i<newMapSize-m_MapSize;i++) { }
memcpy(dst,src,newMapSize*sizeof(u16)); }
dst+=newMapSize; }
}
}
if (newMapSize>m_MapSize) {
// now build new patches // copy over heights of the last row to any remaining rows
for (j=0;j<size;j++) { src=newHeightmap+((m_MapSize-1)*newMapSize);
for (u32 i=0;i<size;i++) { dst=src+newMapSize;
// copy over texture data from existing tiles, if possible for (u32 i=0;i<newMapSize-m_MapSize;i++) {
if (i<m_MapSizePatches && j<m_MapSizePatches) { memcpy(dst,src,newMapSize*sizeof(u16));
memcpy(newPatches[j*size+i].m_MiniPatches,m_Patches[j*m_MapSizePatches+i].m_MiniPatches,sizeof(CMiniPatch)*16*16); dst+=newMapSize;
} }
} }
if (j<m_MapSizePatches && size>m_MapSizePatches) { // now build new patches
// copy over the last tile from each column for (j=0;j<size;j++) {
for (u32 n=0;n<size-m_MapSizePatches;n++) { for (u32 i=0;i<size;i++) {
for (int m=0;m<16;m++) { // copy over texture data from existing tiles, if possible
CMiniPatch& src=m_Patches[j*m_MapSizePatches+m_MapSizePatches-1].m_MiniPatches[m][15]; if (i<m_MapSizePatches && j<m_MapSizePatches) {
for (int k=0;k<16;k++) { memcpy(newPatches[j*size+i].m_MiniPatches,m_Patches[j*m_MapSizePatches+i].m_MiniPatches,sizeof(CMiniPatch)*16*16);
CMiniPatch& dst=newPatches[j*size+m_MapSizePatches+n].m_MiniPatches[m][k]; }
dst.Tex1=src.Tex1; }
dst.Tex1Priority=src.Tex1Priority;
} if (j<m_MapSizePatches && size>m_MapSizePatches) {
} // copy over the last tile from each column
} for (u32 n=0;n<size-m_MapSizePatches;n++) {
} for (int m=0;m<16;m++) {
} CMiniPatch& src=m_Patches[j*m_MapSizePatches+m_MapSizePatches-1].m_MiniPatches[m][15];
for (int k=0;k<16;k++) {
if (size>m_MapSizePatches) { CMiniPatch& dst=newPatches[j*size+m_MapSizePatches+n].m_MiniPatches[m][k];
// copy over the last tile from each column dst.Tex1=src.Tex1;
CPatch* srcpatch=&newPatches[(m_MapSizePatches-1)*size]; dst.Tex1Priority=src.Tex1Priority;
CPatch* dstpatch=srcpatch+size; }
for (u32 p=0;p<size-m_MapSizePatches;p++) { }
for (u32 n=0;n<size;n++) { }
for (int m=0;m<16;m++) { }
for (int k=0;k<16;k++) { }
CMiniPatch& src=srcpatch->m_MiniPatches[15][k];
CMiniPatch& dst=dstpatch->m_MiniPatches[m][k]; if (size>m_MapSizePatches) {
dst.Tex1=src.Tex1; // copy over the last tile from each column
dst.Tex1Priority=src.Tex1Priority; CPatch* srcpatch=&newPatches[(m_MapSizePatches-1)*size];
} CPatch* dstpatch=srcpatch+size;
} for (u32 p=0;p<size-m_MapSizePatches;p++) {
srcpatch++; for (u32 n=0;n<size;n++) {
dstpatch++; for (int m=0;m<16;m++) {
} for (int k=0;k<16;k++) {
} CMiniPatch& src=srcpatch->m_MiniPatches[15][k];
} CMiniPatch& dst=dstpatch->m_MiniPatches[m][k];
dst.Tex1=src.Tex1;
dst.Tex1Priority=src.Tex1Priority;
// release all the original data }
Reset(); }
srcpatch++;
// store new data dstpatch++;
m_Heightmap=newHeightmap; }
m_Patches=newPatches; }
m_MapSize=newMapSize; }
m_MapSizePatches=size;
// initialise all the new patches // release all the original data
InitialisePatches(); ReleaseData();
}
// store new data
void CTerrain::InitialisePatches() m_Heightmap=newHeightmap;
{ m_Patches=newPatches;
for (u32 j=0;j<m_MapSizePatches;j++) { m_MapSize=newMapSize;
for (u32 i=0;i<m_MapSizePatches;i++) { m_MapSizePatches=size;
CPatch* patch=GetPatch(i,j);
patch->Initialize(this,i,j); // initialise all the new patches
} InitialisePatches();
} }
}
///////////////////////////////////////////////////////////////////////////////
// SetHeightMap: set up a new heightmap from 16-bit source data; // InitialisePatches: initialise patch data
// assumes heightmap matches current terrain size void CTerrain::InitialisePatches()
void CTerrain::SetHeightMap(u16* heightmap) {
{ for (u32 j=0;j<m_MapSizePatches;j++) {
// keep a copy of the given heightmap for (u32 i=0;i<m_MapSizePatches;i++) {
memcpy(m_Heightmap,heightmap,m_MapSize*m_MapSize*sizeof(u16)); CPatch* patch=GetPatch(i,j);
patch->Initialize(this,i,j);
// recalculate patch bounds, invalidate vertices }
for (u32 j=0;j<m_MapSizePatches;j++) { }
for (u32 i=0;i<m_MapSizePatches;i++) { }
CPatch* patch=GetPatch(i,j);
patch->CalcBounds(); ///////////////////////////////////////////////////////////////////////////////
if (patch->m_RenderData) patch->m_RenderData->m_UpdateFlags|=RENDERDATA_UPDATE_VERTICES; // SetHeightMap: set up a new heightmap from 16-bit source data;
} // assumes heightmap matches current terrain size
} void CTerrain::SetHeightMap(u16* heightmap)
} {
// keep a copy of the given heightmap
memcpy(m_Heightmap,heightmap,m_MapSize*m_MapSize*sizeof(u16));
// recalculate patch bounds, invalidate vertices
for (u32 j=0;j<m_MapSizePatches;j++) {
for (u32 i=0;i<m_MapSizePatches;i++) {
CPatch* patch=GetPatch(i,j);
patch->CalcBounds();
patch->SetDirty(RENDERDATA_UPDATE_VERTICES);
}
}
}

View File

@ -1,78 +1,82 @@
//*********************************************************** ///////////////////////////////////////////////////////////////////////////////
// //
// Name: Terrain.h // Name: Terrain.h
// Last Update: 23/2/02 // Author: Rich Cross
// Author: Poya Manouchehri // Contact: rich@wildfiregames.com
// //
// Description: CTerrain handles the terrain portion of the ///////////////////////////////////////////////////////////////////////////////
// engine. It holds open the file to the terrain
// information, so terrain data can be loaded
// dynamically. We use a ROAM method to render #ifndef _TERRAIN_H
// the terrain, ie using binary triangle trees. #define _TERRAIN_H
// The terrain consists of smaller PATCHS, which
// do most of the work. #include "Patch.h"
// #include "Vector3D.h"
//***********************************************************
///////////////////////////////////////////////////////////////////////////////
#ifndef TERRAIN_H // Terrain Constants:
#define TERRAIN_H //
// PATCH_SIZE: number of tiles in each patch
#include "Patch.h" const int PATCH_SIZE = 16;
#include "Vector3D.h" // CELL_SIZE: size of each tile in x and z
#include "TerrGlobals.h" const int CELL_SIZE = 4;
// HEIGHT_SCALE: vertical scale of terrain - terrain has a coordinate range of
class CLightEnv; // 0 to 65536*HEIGHT_SCALE
class CSHCoeffs; const float HEIGHT_SCALE = 0.35f/256.0f;
class CTerrain ///////////////////////////////////////////////////////////////////////////////
{ // CTerrain: main terrain class; contains the heightmap describing elevation
public: // data, and the smaller subpatches that form the terrain
CTerrain(); class CTerrain
~CTerrain(); {
public:
bool Initialize(u32 size,const u16* ptr); CTerrain();
~CTerrain();
// return number of vertices along edge of the terrain
u32 GetVerticesPerSide() { return m_MapSize; } bool Initialize(u32 size,const u16* ptr);
// return number of patches along edge of the terrain
u32 GetPatchesPerSide() { return m_MapSizePatches; } // return number of vertices along edge of the terrain
u32 GetVerticesPerSide() { return m_MapSize; }
// resize this terrain such that each side has given number of patches // return number of patches along edge of the terrain
void Resize(u32 size); u32 GetPatchesPerSide() { return m_MapSizePatches; }
// set up a new heightmap from 16 bit data; assumes heightmap matches current terrain size // resize this terrain such that each side has given number of patches
void SetHeightMap(u16* heightmap); void Resize(u32 size);
// return a pointer to the heightmap
u16* GetHeightMap() const { return m_Heightmap; } // set up a new heightmap from 16 bit data; assumes heightmap matches current terrain size
void SetHeightMap(u16* heightmap);
// get patch at given coordinates, expressed in patch-space; return 0 if // return a pointer to the heightmap
// coordinates represent patch off the edge of the map u16* GetHeightMap() const { return m_Heightmap; }
CPatch* GetPatch(int32 x,int32 z);
// get tile at given coordinates, expressed in tile-space; return 0 if // get patch at given coordinates, expressed in patch-space; return 0 if
// coordinates represent tile off the edge of the map // coordinates represent patch off the edge of the map
CMiniPatch* GetTile(int32 x,int32 z); CPatch* GetPatch(int32 x,int32 z);
// get tile at given coordinates, expressed in tile-space; return 0 if
// calculate the position of a given vertex // coordinates represent tile off the edge of the map
void CalcPosition(u32 i,u32 j,CVector3D& pos); CMiniPatch* GetTile(int32 x,int32 z);
// calculate the normal at a given vertex
void CalcNormal(u32 i,u32 j,CVector3D& normal); // calculate the position of a given vertex
void CalcPosition(u32 i,u32 j,CVector3D& pos);
private: // calculate the normal at a given vertex
// clean up terrain data void CalcNormal(u32 i,u32 j,CVector3D& normal);
void Reset();
// setup patch pointers etc private:
void InitialisePatches(); // delete any data allocated by this terrain
void ReleaseData();
// size of this map in each direction, in vertices; ie. total tiles = sqr(m_MapSize-1) // setup patch pointers etc
u32 m_MapSize; void InitialisePatches();
// size of this map in each direction, in patches; total patches = sqr(m_MapSizePatches)
u32 m_MapSizePatches; // size of this map in each direction, in vertices; ie. total tiles = sqr(m_MapSize-1)
// the patches comprising this terrain u32 m_MapSize;
CPatch* m_Patches; // size of this map in each direction, in patches; total patches = sqr(m_MapSizePatches)
// 16-bit heightmap data u32 m_MapSizePatches;
u16* m_Heightmap; // the patches comprising this terrain
CPatch* m_Patches;
}; // 16-bit heightmap data
u16* m_Heightmap;
#endif };
extern CTerrain g_Terrain;
#endif

View File

@ -1,24 +1,24 @@
#ifndef _TEXTUREENTRY_H #ifndef _TEXTUREENTRY_H
#define _TEXTUREENTRY_H #define _TEXTUREENTRY_H
#include "res/res.h" #include "res/res.h"
#include "CStr.h" #include "CStr.h"
class CTextureEntry class CTextureEntry
{ {
public: public:
CTextureEntry() : m_Bitmap(0) {} CTextureEntry() : m_Bitmap(0), m_Handle(0), m_BaseColor(0), m_Type(0) {}
// filename // filename
CStr m_Name; CStr m_Name;
// UI bitmap object // UI bitmap object
void* m_Bitmap; void* m_Bitmap;
// handle to GL texture data // handle to GL texture data
Handle m_Handle; Handle m_Handle;
// BGRA color of topmost mipmap level, for coloring minimap // BGRA color of topmost mipmap level, for coloring minimap
unsigned int m_BaseColor; unsigned int m_BaseColor;
// "type" of texture - index into TextureManager texturetypes array // "type" of texture - index into TextureManager texturetypes array
int m_Type; int m_Type;
}; };
#endif #endif

View File

@ -1,215 +1,201 @@
#include "TextureManager.h" #include "TextureManager.h"
#include "lib.h" #include "lib.h"
#include "ogl.h" #include "ogl.h"
#include "res/tex.h" #include "res/tex.h"
#ifdef _WIN32 #ifdef _WIN32
#include <io.h> #include <io.h>
#endif #endif
#include <algorithm> #include <algorithm>
const char* SupportedTextureFormats[] = { "png", "dds", "tga", "bmp" }; const char* SupportedTextureFormats[] = { "png", "dds", "tga", "bmp" };
CTextureManager g_TexMan; CTextureManager g_TexMan;
int GetNumMipmaps(int w,int h)
{ CTextureManager::CTextureManager()
int mip=0; {
int dim=(w > h) ? w : h; m_TerrainTextures.reserve(32);
while(dim) { }
dim>>=1;
mip++; void CTextureManager::AddTextureType(const char* name)
} {
return mip; m_TerrainTextures.resize(m_TerrainTextures.size()+1);
} STextureType& ttype=m_TerrainTextures.back();
ttype.m_Name=name;
CTextureManager::CTextureManager() ttype.m_Index=m_TerrainTextures.size()-1;
{ }
m_TerrainTextures.reserve(32);
} CTextureEntry* CTextureManager::FindTexture(const char* filename)
{
void CTextureManager::AddTextureType(const char* name) // check if file already loaded
{ for (uint k=0;k<m_TerrainTextures.size();k++) {
m_TerrainTextures.resize(m_TerrainTextures.size()+1); STextureType& ttype=m_TerrainTextures[k];
STextureType& ttype=m_TerrainTextures.back(); for (uint i=0;i<ttype.m_Textures.size();i++) {
ttype.m_Name=name; if (strcmp((const char*) ttype.m_Textures[i]->m_Name,filename)==0) {
ttype.m_Index=m_TerrainTextures.size()-1; return ttype.m_Textures[i];
} }
}
CTextureEntry* CTextureManager::FindTexture(const char* filename) }
{
// check if file already loaded return 0;
for (uint k=0;k<m_TerrainTextures.size();k++) { }
STextureType& ttype=m_TerrainTextures[k];
for (uint i=0;i<ttype.m_Textures.size();i++) { CTextureEntry* CTextureManager::FindTexture(Handle handle)
if (strcmp((const char*) ttype.m_Textures[i]->m_Name,filename)==0) { {
return ttype.m_Textures[i]; for (uint k=0;k<m_TerrainTextures.size();k++) {
} STextureType& ttype=m_TerrainTextures[k];
} for (uint i=0;i<ttype.m_Textures.size();i++) {
} if (handle==ttype.m_Textures[i]->m_Handle) {
return ttype.m_Textures[i];
return 0; }
} }
}
CTextureEntry* CTextureManager::FindTexture(Handle handle)
{ return 0;
for (uint k=0;k<m_TerrainTextures.size();k++) { }
STextureType& ttype=m_TerrainTextures[k];
for (uint i=0;i<ttype.m_Textures.size();i++) { CTextureEntry* CTextureManager::AddTexture(const char* filename,int type)
if (handle==ttype.m_Textures[i]->m_Handle) { {
return ttype.m_Textures[i]; assert((uint)type<m_TerrainTextures.size());
}
} CStr pathname("art/textures/terrain/types/");
} pathname+=m_TerrainTextures[type].m_Name;
pathname+='/';
return 0; pathname+=filename;
}
Handle h=tex_load((const char*) pathname);
static bool IsCompressed(Handle h) if (!h) {
{ return 0;
int fmt; } else {
tex_info(h, NULL, NULL, &fmt, NULL, NULL); int tw;
if (fmt==GL_COMPRESSED_RGB_S3TC_DXT1_EXT) return true; int th;
if (fmt==GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) return true;
if (fmt==GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) return true; tex_info(h, &tw, &th, NULL, NULL, NULL);
if (fmt==GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) return true;
return false; tw &= (tw-1);
} th &= (th-1);
if (tw || th) {
CTextureEntry* CTextureManager::AddTexture(const char* filename,int type) return 0;
{ }
assert(type<m_TerrainTextures.size()); }
CStr pathname("art/textures/terrain/types/"); // create new texture entry
pathname+=m_TerrainTextures[type].m_Name; CTextureEntry* texentry=new CTextureEntry;
pathname+='/'; texentry->m_Name=filename;
pathname+=filename; texentry->m_Handle=h;
texentry->m_Type=type;
Handle h=tex_load((const char*) pathname);
if (!h) { // upload texture for future GL use
return 0; tex_upload(h,GL_LINEAR_MIPMAP_LINEAR);
} else {
int tw; // setup texture to repeat
int th; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
tex_info(h, &tw, &th, NULL, NULL, NULL);
// get root color for coloring minimap by querying root level of the texture
tw &= (tw-1); // (this should decompress any compressed textures for us),
th &= (th-1); // then scaling it down to a 1x1 size
if (tw || th) { // - an alternative approach of just grabbing the top level of the mipmap tree fails
return 0; // (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:
// create new texture entry int width,height;
CTextureEntry* texentry=new CTextureEntry; glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_WIDTH,&width);
texentry->m_Name=filename; glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_HEIGHT,&height);
texentry->m_Handle=h;
texentry->m_Type=type; unsigned char* buf=new unsigned char[width*height*4];
glGetTexImage(GL_TEXTURE_2D,0,GL_BGRA_EXT,GL_UNSIGNED_BYTE,buf);
// upload texture for future GL use gluScaleImage(GL_BGRA_EXT,width,height,GL_UNSIGNED_BYTE,buf,
if (IsCompressed(h)) { 1,1,GL_UNSIGNED_BYTE,&texentry->m_BaseColor);
tex_upload(h,GL_LINEAR); delete[] buf;
} else {
tex_upload(h,GL_LINEAR_MIPMAP_LINEAR); // add entry to list ..
} m_TerrainTextures[type].m_Textures.push_back(texentry);
// setup texture to repeat // .. and return it
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); return texentry;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); }
// get root color for coloring minimap void CTextureManager::DeleteTexture(CTextureEntry* entry)
int width,height; {
glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_WIDTH,&width); // find entry in list
glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_HEIGHT,&height); std::vector<CTextureEntry*>& textures=m_TerrainTextures[entry->m_Type].m_Textures;
int mip=GetNumMipmaps(width,height);
glGetTexImage(GL_TEXTURE_2D,mip-1,GL_BGRA_EXT,GL_UNSIGNED_BYTE,&texentry->m_BaseColor); typedef std::vector<CTextureEntry*>::iterator Iter;
Iter i=std::find(textures.begin(),textures.end(),entry);
// add entry to list .. if (i!=textures.end()) {
m_TerrainTextures[type].m_Textures.push_back(texentry); textures.erase(i);
}
// .. and return it delete entry;
return texentry; }
}
void CTextureManager::LoadTerrainTextures(int terraintype,const char* fileext)
void CTextureManager::DeleteTexture(CTextureEntry* entry) {
{ #ifdef _WIN32
// find entry in list struct _finddata_t file;
std::vector<CTextureEntry*>& textures=m_TerrainTextures[entry->m_Type].m_Textures; long handle;
typedef std::vector<CTextureEntry*>::iterator Iter; // build pathname
Iter i=std::find(textures.begin(),textures.end(),entry); CStr pathname("mods\\official\\art\\textures\\terrain\\types\\");
if (i!=textures.end()) { pathname+=m_TerrainTextures[terraintype].m_Name;
textures.erase(i); pathname+="\\";
}
delete entry; CStr findname(pathname);
} findname+="*.";
findname+=fileext;
void CTextureManager::LoadTerrainTextures(int terraintype,const char* fileext)
{ // Find first matching file in directory for this terrain type
#ifdef _WIN32 if ((handle=_findfirst((const char*) findname,&file))!=-1) {
struct _finddata_t file;
long handle; AddTexture(file.name,terraintype);
// build pathname // Find the rest of the matching files
CStr pathname("mods\\official\\art\\textures\\terrain\\types\\"); while( _findnext(handle,&file)==0) {
pathname+=m_TerrainTextures[terraintype].m_Name; AddTexture((const char*) file.name,terraintype);
pathname+="\\"; }
CStr findname(pathname); _findclose(handle);
findname+="*."; }
findname+=fileext; #endif
}
// Find first matching file in directory for this terrain type
if ((handle=_findfirst((const char*) findname,&file))!=-1) { void CTextureManager::BuildTerrainTypes()
{
AddTexture(file.name,terraintype); #ifdef _WIN32
struct _finddata_t file;
// Find the rest of the matching files long handle;
while( _findnext(handle,&file)==0) {
AddTexture((const char*) file.name,terraintype); // Find first matching directory in terrain\textures
} if ((handle=_findfirst("mods\\official\\art\\textures\\terrain\\types\\*",&file))!=-1) {
_findclose(handle); if ((file.attrib & _A_SUBDIR) && file.name[0]!='.') {
} AddTextureType(file.name);
#endif }
}
// Find the rest of the matching files
void CTextureManager::BuildTerrainTypes() while( _findnext(handle,&file)==0) {
{ if ((file.attrib & _A_SUBDIR) && file.name[0]!='.') {
#ifdef _WIN32 AddTextureType(file.name);
struct _finddata_t file; }
long handle; }
// Find first matching directory in terrain\textures _findclose(handle);
if ((handle=_findfirst("mods\\official\\art\\textures\\terrain\\types\\*",&file))!=-1) { }
#endif
if ((file.attrib & _A_SUBDIR) && file.name[0]!='.' && file.name[0]!='_') { }
AddTextureType(file.name);
} void CTextureManager::LoadTerrainTextures()
{
// Find the rest of the matching files // find all the terrain types by directory name
while( _findnext(handle,&file)==0) { BuildTerrainTypes();
if ((file.attrib & _A_SUBDIR) && file.name[0]!='.' && file.name[0]!='_') {
AddTextureType(file.name); // now iterate through terrain types loading all textures of that type
} for (uint i=0;i<m_TerrainTextures.size();i++) {
} for (uint j=0;j<sizeof(SupportedTextureFormats)/sizeof(const char*);j++) {
LoadTerrainTextures(i,SupportedTextureFormats[j]);
_findclose(handle); }
} }
#endif }
}
void CTextureManager::LoadTerrainTextures()
{
// find all the terrain types by directory name
BuildTerrainTypes();
// now iterate through terrain types loading all textures of that type
for (uint i=0;i<m_TerrainTextures.size();i++) {
for (uint j=0;j<sizeof(SupportedTextureFormats)/sizeof(const char*);j++) {
LoadTerrainTextures(i,SupportedTextureFormats[j]);
}
}
}

View File

@ -1,138 +1,136 @@
#include <algorithm> #include <algorithm>
#include "Renderer.h" #include "Renderer.h"
#include "TransparencyRenderer.h" #include "TransparencyRenderer.h"
#include "terrain/Model.h" #include "terrain/Model.h"
#include "terrain/Visual.h"
extern CRenderer g_Renderer; CTransparencyRenderer g_TransparencyRenderer;
CTransparencyRenderer g_TransparencyRenderer;
struct SortObjectsByDist {
typedef CTransparencyRenderer::SObject SortObj;
struct SortObjectsByDist {
typedef CTransparencyRenderer::SObject SortObj; bool operator()(const SortObj& lhs,const SortObj& rhs) {
return lhs.m_Dist>rhs.m_Dist? true : false;
bool operator()(const SortObj& lhs,const SortObj& rhs) { }
return lhs.m_Dist>rhs.m_Dist? true : false; };
}
}; void CTransparencyRenderer::Render()
{
void CTransparencyRenderer::Render() // coarsely sort submitted objects in back to front manner
{ std::sort(m_Objects.begin(),m_Objects.end(),SortObjectsByDist());
// coarsely sort submitted objects in back to front manner
std::sort(m_Objects.begin(),m_Objects.end(),SortObjectsByDist()); // switch on wireframe if we need it
if (g_Renderer.m_ModelRenderMode==WIREFRAME) {
// switch on wireframe if we need it glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
if (g_Renderer.m_ModelRenderMode==WIREFRAME) { }
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
} // switch on client states
glEnableClientState(GL_VERTEX_ARRAY);
// switch on client states glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); // setup texture environment to modulate diffuse color with texture color
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
// setup texture environment to modulate diffuse color with texture color glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR); // just pass through texture's alpha
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
// just pass through texture's alpha glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA); glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER,0.975f);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER,0.975f); uint i;
for (i=0;i<m_Objects.size();++i) {
uint i; CModel* model=m_Objects[i].m_Model;
for (i=0;i<m_Objects.size();++i) { CModelRData* modeldata=(CModelRData*) model->GetRenderData();
CVisual* visual=m_Objects[i].m_Visual; modeldata->RenderStreams(STREAM_POS|STREAM_COLOR|STREAM_UV0,model->GetTransform(),true);
CModelRData* modeldata=(CModelRData*) visual->m_Model->m_RenderData; }
modeldata->Render(visual->GetTransform(),true);
} glDepthMask(0);
glAlphaFunc(GL_LEQUAL,0.975f);
glDepthMask(0);
glAlphaFunc(GL_LEQUAL,0.975f); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); for (i=0;i<m_Objects.size();++i) {
CModel* model=m_Objects[i].m_Model;
for (i=0;i<m_Objects.size();++i) { CModelRData* modeldata=(CModelRData*) model->GetRenderData();
CVisual* visual=m_Objects[i].m_Visual; modeldata->RenderStreams(STREAM_POS|STREAM_COLOR|STREAM_UV0,model->GetTransform(),true);
CModelRData* modeldata=(CModelRData*) visual->m_Model->m_RenderData; }
modeldata->Render(visual->GetTransform(),true); glDisable(GL_BLEND);
} glDisable(GL_ALPHA_TEST);
glDisable(GL_BLEND); glDepthMask(1);
glDisable(GL_ALPHA_TEST);
glDepthMask(1); // switch off client states
glDisableClientState(GL_VERTEX_ARRAY);
// switch off client states glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY); if (g_Renderer.m_ModelRenderMode==WIREFRAME) {
// switch wireframe off again
if (g_Renderer.m_ModelRenderMode==WIREFRAME) { glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
// switch wireframe off again } else if (g_Renderer.m_ModelRenderMode==EDGED_FACES) {
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); // edged faces: need to make a second pass over the data:
} else if (g_Renderer.m_ModelRenderMode==EDGED_FACES) { // first switch on wireframe
// edged faces: need to make a second pass over the data: glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
// first switch on wireframe
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); // setup some renderstate ..
glDepthMask(0);
// setup some renderstate .. g_Renderer.SetTexture(0,0);
glDepthMask(0); glColor4f(1,1,1,0.75f);
g_Renderer.SetTexture(0,0); glLineWidth(1.0f);
glColor4f(1,1,1,0.75f);
glLineWidth(1.0f); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); // .. and some client states
glEnableClientState(GL_VERTEX_ARRAY);
// .. and some client states
glEnableClientState(GL_VERTEX_ARRAY); // render each model
for (i=0;i<m_Objects.size();++i) {
// render each model CModel* model=m_Objects[i].m_Model;
for (uint i=0;i<m_Objects.size();++i) { CModelRData* modeldata=(CModelRData*) model->GetRenderData();
CVisual* visual=m_Objects[i].m_Visual; modeldata->RenderStreams(STREAM_POS,model->GetTransform(),true);
CModelRData* modeldata=(CModelRData*) visual->m_Model->m_RenderData; }
modeldata->RenderWireframe(visual->GetTransform(),true);
} // .. and switch off the client states
glDisableClientState(GL_VERTEX_ARRAY);
// .. and switch off the client states
glDisableClientState(GL_VERTEX_ARRAY); // .. and restore the renderstates
glDisable(GL_BLEND);
// .. and restore the renderstates glDepthMask(1);
glDisable(GL_BLEND);
glDepthMask(1); // restore fill mode, and we're done
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
// restore fill mode, and we're done }
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
} // all transparent objects rendered; release them
m_Objects.clear();
// all transparent objects rendered; release them }
m_Objects.clear();
} void CTransparencyRenderer::Add(CModel* model)
{
void CTransparencyRenderer::Add(CVisual* visual) // resize array, get last object in list
{ m_Objects.resize(m_Objects.size()+1);
// resize array, get last object in list
m_Objects.resize(m_Objects.size()+1); SObject& obj=m_Objects.back();
obj.m_Model=model;
SObject& obj=m_Objects.back();
obj.m_Visual=visual; // build transform from object to camera space
CMatrix3D objToCam,invcam;
// build transform from object to camera space g_Renderer.m_Camera.m_Orientation.GetInverse(objToCam);
CMatrix3D objToCam,invcam; objToCam*=model->GetTransform();
g_Renderer.m_Camera.m_Orientation.Invert(objToCam);
objToCam*=visual->GetTransform(); // resort model indices from back to front, according to camera position - and store
// the returned sqrd distance to the centre of the nearest triangle
// resort model indices from back to front, according to camera position - and store CModelRData* modeldata=(CModelRData*) model->GetRenderData();
// the returned sqrd distance to the centre of the nearest triangle obj.m_Dist=modeldata->BackToFrontIndexSort(objToCam);
CModelRData* modeldata=(CModelRData*) visual->m_Model->m_RenderData; }
obj.m_Dist=modeldata->BackToFrontIndexSort(objToCam);
}

View File

@ -1,31 +1,31 @@
#ifndef __TRANSPARENCYRENDERER_H #ifndef __TRANSPARENCYRENDERER_H
#define __TRANSPARENCYRENDERER_H #define __TRANSPARENCYRENDERER_H
#include <vector> #include <vector>
class CVisual; class CModel;
class CTransparencyRenderer class CTransparencyRenderer
{ {
public: public:
struct SObject { struct SObject {
// visual representation of object // the transparent model
CVisual* m_Visual; CModel* m_Model;
// sqrd distance from camera to centre of nearest triangle // sqrd distance from camera to centre of nearest triangle
float m_Dist; float m_Dist;
}; };
public: public:
// add object to render in deferred transparency pass // add object to render in deferred transparency pass
void Add(CVisual* visual); void Add(CModel* model);
// render all deferred objects // render all deferred objects
void Render(); void Render();
private: private:
// list of transparent objects to render // list of transparent objects to render
std::vector<SObject> m_Objects; std::vector<SObject> m_Objects;
}; };
extern CTransparencyRenderer g_TransparencyRenderer; extern CTransparencyRenderer g_TransparencyRenderer;
#endif #endif

View File

@ -1,60 +0,0 @@
#include "Triangle.h"
#include "Plane.h"
#define EPSILON 0.00001f
Triangle::Triangle()
{
}
Triangle::Triangle(const CVector3D& p0,const CVector3D& p1,const CVector3D& p2)
{
_vertices[0]=p0;
_vertices[1]=p1;
_vertices[2]=p2;
// calculate edge vectors
_edge[0]=_vertices[1]-_vertices[0];
_edge[1]=_vertices[2]-_vertices[0];
}
bool Triangle::RayIntersect(const CVector3D& origin,const CVector3D& dir,float& dist) const
{
// begin calculating determinant - also used to calculate U parameter
CVector3D pvec=dir.Cross(_edge[1]);
// if determinant is near zero, ray lies in plane of triangle
float det = _edge[0].Dot(pvec);
if (fabs(det)<EPSILON)
return false;
float inv_det = 1.0f/det;
// calculate vector from vert0 to ray origin
CVector3D tvec;
for (int i=0;i<3;++i) {
tvec[i]=origin[i]-_vertices[0][i];
}
// calculate U parameter, test bounds
float u=tvec.Dot(pvec)*inv_det;
if (u<-0.01f || u>1.01f)
return false;
// prepare to test V parameter
CVector3D qvec=tvec.Cross(_edge[0]);
// calculate V parameter and test bounds
float v=dir.Dot(qvec)*inv_det;
if (v<-0.01f || u+v>1.01f)
return false;
// calculate distance to intersection point from ray origin
float d=_edge[1].Dot(qvec)*inv_det;
if (d>=0 && d<dist) {
dist=d;
return true;
}
return false;
}

View File

@ -1,24 +0,0 @@
#ifndef _TRIANGLE_H
#define _TRIANGLE_H
// necessary includes
#include "Vector3D.h"
/////////////////////////////////////////////////////////////////////////////////////////
class Triangle
{
public:
Triangle();
Triangle(const CVector3D& p0,const CVector3D& p1,const CVector3D& p2);
bool RayIntersect(const CVector3D& origin,const CVector3D& dir,float& maxdist) const;
private:
CVector3D _vertices[3];
CVector3D _edge[2];
};
/////////////////////////////////////////////////////////////////////////////////////////
#endif

View File

@ -1,62 +0,0 @@
//***********************************************************
//
// Name: Types.h
// Last Update: 25/1/02
// Author: Poya Manouchehri
//
// Description: The basic types used by the engine
//
//***********************************************************
#ifndef TYPES_H
#define TYPES_H
#include <stdio.h>
//color structures
struct SColor4ub
{
unsigned char R;
unsigned char G;
unsigned char B;
unsigned char A;
};
struct SColor4f
{
float R;
float G;
float B;
float A;
};
//all the major classes:
class CCamera;
class CEngine;
class CEntity;
class CFrustum;
class CMatrix3D;
class CMesh;
class CMeshPoly;
class CShadyMesh;
class CShadyMeshPoly;
class CNode;
class CPatch;
class CPlane;
class CRenderer;
class CTerrain;
class CVector3D;
class CWorld;
#endif

16
source/terrain/Unit.h Executable file
View File

@ -0,0 +1,16 @@
#ifndef _UNIT_H
#define _UNIT_H
class CModel;
class CObjectEntry;
class CUnit
{
public:
// object from which unit was created
CObjectEntry* m_Object;
// object model representation
CModel* m_Model;
};
#endif

28
source/terrain/UnitManager.cpp Executable file
View File

@ -0,0 +1,28 @@
#include "res/res.h"
#include "UnitManager.h"
#include <algorithm>
CUnitManager g_UnitMan;
void CUnitManager::AddUnit(CUnit* unit)
{
m_Units.push_back(unit);
}
void CUnitManager::RemoveUnit(CUnit* unit)
{
// find entry in list
typedef std::vector<CUnit*>::iterator Iter;
Iter i=std::find(m_Units.begin(),m_Units.end(),unit);
if (i!=m_Units.end()) {
m_Units.erase(i);
}
}
void CUnitManager::DeleteAll()
{
for (uint i=0;i<m_Units.size();i++) {
delete m_Units[i];
}
m_Units.clear();
}

25
source/terrain/UnitManager.h Executable file
View File

@ -0,0 +1,25 @@
#ifndef _UNITMANAGER_H
#define _UNITMANAGER_H
#include <vector>
#include "Unit.h"
class CUnitManager
{
public:
CUnitManager() {}
void AddUnit(CUnit* unit);
void RemoveUnit(CUnit* unit);
void DeleteAll();
const std::vector<CUnit*>& GetUnits() const { return m_Units; }
private:
std::vector<CUnit*> m_Units;
};
extern CUnitManager g_UnitMan;
#endif

View File

@ -1,192 +1,153 @@
//*********************************************************** //***********************************************************
// //
// Name: Vector3D.Cpp // Name: Vector3D.Cpp
// Last Update: 28/1/02 // Last Update: 28/1/02
// Author: Poya Manouchehri // Author: Poya Manouchehri
// //
// Description: Provides an interface for a vector in R3 and // Description: Provides an interface for a vector in R3 and
// allows vector and scalar operations on it // allows vector and scalar operations on it
// //
//*********************************************************** //***********************************************************
#include "Vector3D.h" #include "Vector3D.h"
CVector3D::CVector3D () CVector3D::CVector3D (float x, float y, float z)
{ {
X = Y = Z = 0.0f; X = x;
} Y = y;
Z = z;
CVector3D::CVector3D (float x, float y, float z) }
{
X = x; int CVector3D::operator ! () const
Y = y; {
Z = z; if (X != 0.0f ||
} Y != 0.0f ||
Z != 0.0f)
int CVector3D::operator == (const CVector3D &vector) const
{ return 0;
if (X != vector.X ||
Y != vector.Y || return 1;
Z != vector.Z) }
return 0; //vector addition
CVector3D CVector3D::operator + (const CVector3D &vector) const
return 1; {
} CVector3D Temp;
int CVector3D::operator != (const CVector3D &vector) const Temp.X = X + vector.X;
{ Temp.Y = Y + vector.Y;
if (X != vector.X || Temp.Z = Z + vector.Z;
Y != vector.Y ||
Z != vector.Z) return Temp;
}
return 1;
//vector addition/assignment
return 0; CVector3D &CVector3D::operator += (const CVector3D &vector)
} {
X += vector.X;
int CVector3D::operator ! () const Y += vector.Y;
{ Z += vector.Z;
if (X != 0.0f ||
Y != 0.0f || return *this;
Z != 0.0f) }
return 0; //vector subtraction
CVector3D CVector3D::operator - (const CVector3D &vector) const
return 1; {
} CVector3D Temp;
//vector addition Temp.X = X - vector.X;
CVector3D CVector3D::operator + (const CVector3D &vector) const Temp.Y = Y - vector.Y;
{ Temp.Z = Z - vector.Z;
CVector3D Temp;
return Temp;
Temp.X = X + vector.X; }
Temp.Y = Y + vector.Y;
Temp.Z = Z + vector.Z; //vector negation
CVector3D CVector3D::operator-() const
return Temp; {
} CVector3D Temp;
//vector addition/assignment Temp.X = -X;
CVector3D &CVector3D::operator += (const CVector3D &vector) Temp.Y = -Y;
{ Temp.Z = -Z;
X += vector.X;
Y += vector.Y; return Temp;
Z += vector.Z; }
//vector subtrcation/assignment
return *this; CVector3D &CVector3D::operator -= (const CVector3D &vector)
} {
X -= vector.X;
//vector subtraction Y -= vector.Y;
CVector3D CVector3D::operator - (const CVector3D &vector) const Z -= vector.Z;
{
CVector3D Temp; return *this;
}
Temp.X = X - vector.X;
Temp.Y = Y - vector.Y; //scalar multiplication
Temp.Z = Z - vector.Z; CVector3D CVector3D::operator * (float value) const
{
return Temp; CVector3D Temp;
}
Temp.X = X * value;
//vector negation Temp.Y = Y * value;
CVector3D CVector3D::operator-() const Temp.Z = Z * value;
{
CVector3D Temp; return Temp;
}
Temp.X = -X;
Temp.Y = -Y; //scalar multiplication/assignment
Temp.Z = -Z; CVector3D& CVector3D::operator *= (float value)
{
return Temp; X *= value;
} Y *= value;
//vector subtrcation/assignment Z *= value;
CVector3D &CVector3D::operator -= (const CVector3D &vector)
{ return *this;
X -= vector.X; }
Y -= vector.Y;
Z -= vector.Z; void CVector3D::Set (float x, float y, float z)
{
return *this; X = x;
} Y = y;
Z = z;
//scalar multiplication }
CVector3D CVector3D::operator * (float value) const
{ void CVector3D::Clear ()
CVector3D Temp; {
X = Y = Z = 0.0f;
Temp.X = X * value; }
Temp.Y = Y * value;
Temp.Z = Z * value; //Dot product
float CVector3D::Dot (const CVector3D &vector) const
return Temp; {
} return ( X * vector.X +
Y * vector.Y +
//scalar multiplication/assignment Z * vector.Z );
CVector3D& CVector3D::operator *= (float value) }
{
X *= value; //Cross product
Y *= value; CVector3D CVector3D::Cross (const CVector3D &vector) const
Z *= value; {
CVector3D Temp;
return *this;
} Temp.X = (Y * vector.Z) - (Z * vector.Y);
Temp.Y = (Z * vector.X) - (X * vector.Z);
void CVector3D::Set (float x, float y, float z) Temp.Z = (X * vector.Y) - (Y * vector.X);
{
X = x; return Temp;
Y = y; }
Z = z;
} float CVector3D::GetLength () const
{
void CVector3D::Clear () return sqrtf ( SQR(X) + SQR(Y) + SQR(Z) );
{ }
X = Y = Z = 0.0f;
} void CVector3D::Normalize ()
{
//Dot product float scale = 1.0f/GetLength ();
float CVector3D::Dot (const CVector3D &vector) const
{ X *= scale;
return ( X * vector.X + Y *= scale;
Y * vector.Y + Z *= scale;
Z * vector.Z ); }
}
//Cross product
CVector3D CVector3D::Cross (const CVector3D &vector) const
{
CVector3D Temp;
Temp.X = (Y * vector.Z) - (Z * vector.Y);
Temp.Y = (Z * vector.X) - (X * vector.Z);
Temp.Z = (X * vector.Y) - (Y * vector.X);
return Temp;
}
float CVector3D::GetLength () const
{
return sqrtf ( SQR(X) + SQR(Y) + SQR(Z) );
}
void CVector3D::Normalize ()
{
float scale = 1.0f/GetLength ();
X *= scale;
Y *= scale;
Z *= scale;
}
SColor4ub CVector3D::ConvertToColor (float alpha_factor) const
{
SColor4ub color;
color.R = (unsigned char)(127.0f * X + 128.0f);
color.G = (unsigned char)(127.0f * Y + 128.0f);
color.B = (unsigned char)(127.0f * Z + 128.0f);
color.A = (unsigned char)(255.0f * alpha_factor);
return color;
}

View File

@ -1,71 +1,67 @@
//*********************************************************** //***********************************************************
// //
// Name: Vector3D.H // Name: Vector3D.H
// Last Update: 28/1/02 // Last Update: 28/1/02
// Author: Poya Manouchehri // Author: Poya Manouchehri
// //
// Description: Provides an interface for a vector in R3 and // Description: Provides an interface for a vector in R3 and
// allows vector and scalar operations on it // allows vector and scalar operations on it
// //
//*********************************************************** //***********************************************************
#ifndef VECTOR3D_H #ifndef VECTOR3D_H
#define VECTOR3D_H #define VECTOR3D_H
#include <math.h> #include <math.h>
#include "MathUtil.h" #include "res/res.h"
#include "Types.h" #include "MathUtil.h"
class CVector3D class CVector3D
{ {
public: public:
float X, Y, Z; float X, Y, Z;
public: public:
CVector3D (); CVector3D () { }
CVector3D (float x, float y, float z); CVector3D (float x, float y, float z);
int operator == (const CVector3D &vector) const ; int operator ! () const ;
int operator != (const CVector3D &vector) const ;
int operator ! () const ; float& operator[](int index) { return *((&X)+index); }
const float& operator[](int index) const { return *((&X)+index); }
float& operator[](int index) { return *((&X)+index); }
const float& operator[](int index) const { return *((&X)+index); } //vector addition
CVector3D operator + (const CVector3D &vector) const ;
//vector addition //vector addition/assignment
CVector3D operator + (const CVector3D &vector) const ; CVector3D &operator += (const CVector3D &vector);
//vector addition/assignment
CVector3D &operator += (const CVector3D &vector); //vector subtraction
CVector3D operator - (const CVector3D &vector) const ;
//vector subtraction //vector subtraction/assignment
CVector3D operator - (const CVector3D &vector) const ; CVector3D &operator -= (const CVector3D &vector);
//vector subtraction/assignment
CVector3D &operator -= (const CVector3D &vector); //scalar multiplication
CVector3D operator * (float value) const ;
//scalar multiplication //scalar multiplication/assignment
CVector3D operator * (float value) const ; CVector3D& operator *= (float value);
//scalar multiplication/assignment
CVector3D& operator *= (float value); // negation
CVector3D operator-() const;
// negation
CVector3D operator-() const; public:
void Set (float x, float y, float z);
public: void Clear ();
void Set (float x, float y, float z);
void Clear (); //Dot product
float Dot (const CVector3D &vector) const;
//Dot product //Cross product
float Dot (const CVector3D &vector) const; CVector3D Cross (const CVector3D &vector) const;
//Cross product
CVector3D Cross (const CVector3D &vector) const; //Returns length of the vector
float GetLength () const;
//Returns length of the vector void Normalize ();
float GetLength () const;
void Normalize (); };
//Returns a color which describes the vector
SColor4ub ConvertToColor (float alpha_factor) const; #endif
};
#endif

View File

@ -1,111 +1,110 @@
//*********************************************************** //***********************************************************
// //
// Name: CVector4D.h // Name: CVector4D.h
// Last Update: 02/11/03 // Last Update: 02/11/03
// Author: Rich Cross // Author: Rich Cross
// //
// Description: Provides an interface for a vector in R4 and // Description: Provides an interface for a vector in R4 and
// allows vector and scalar operations on it // allows vector and scalar operations on it
// //
//*********************************************************** //***********************************************************
#ifndef _VECTOR4D_H #ifndef _VECTOR4D_H
#define _VECTOR4D_H #define _VECTOR4D_H
#include <math.h> #include <math.h>
#include "MathUtil.h"
///////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // CVector4D:
// CVector4D: class CVector4D
class CVector4D {
{ public:
public: CVector4D() {}
CVector4D() {} CVector4D(const float f[4]) { m_X=f[0]; m_Y=f[1]; m_Z=f[2]; m_W=f[3]; }
CVector4D(const float f[4]) { m_X=f[0]; m_Y=f[1]; m_Z=f[2]; m_W=f[3]; } CVector4D(float x,float y,float z,float w) { m_X=x; m_Y=y; m_Z=z; m_W=w; }
CVector4D(float x,float y,float z,float w) { m_X=x; m_Y=y; m_Z=z; m_W=w; } CVector4D(const CVector4D& p) { m_X=p.m_X; m_Y=p.m_Y; m_Z=p.m_Z; m_W=p.m_W; }
CVector4D(const CVector4D& p) { m_X=p.m_X; m_Y=p.m_Y; m_Z=p.m_Z; m_W=p.m_W; }
operator float*() {
operator float*() { return &m_X;
return &m_X; }
}
operator const float*() const {
operator const float*() const { return &m_X;
return &m_X; }
}
CVector4D operator-() const {
CVector4D operator-() const { return CVector4D(-m_X,-m_Y,-m_Z,-m_W);
return CVector4D(-m_X,-m_Y,-m_Z,-m_W); }
}
CVector4D operator+(const CVector4D& t) const {
CVector4D operator+(const CVector4D& t) const { return CVector4D(m_X+t.m_X,m_Y+t.m_Y,m_Z+t.m_Z,m_W+t.m_W);
return CVector4D(m_X+t.m_X,m_Y+t.m_Y,m_Z+t.m_Z,m_W+t.m_W); }
}
CVector4D operator-(const CVector4D& t) const {
CVector4D operator-(const CVector4D& t) const { return CVector4D(m_X-t.m_X,m_Y-t.m_Y,m_Z-t.m_Z,m_W-t.m_W);
return CVector4D(m_X-t.m_X,m_Y-t.m_Y,m_Z-t.m_Z,m_W-t.m_W); }
}
CVector4D operator*(const CVector4D& t) const {
CVector4D operator*(const CVector4D& t) const { return CVector4D(m_X*t.m_X,m_Y*t.m_Y,m_Z*t.m_Z,m_W*t.m_W);
return CVector4D(m_X*t.m_X,m_Y*t.m_Y,m_Z*t.m_Z,m_W*t.m_W); }
}
CVector4D operator*(float f) const {
CVector4D operator*(float f) const { return CVector4D(m_X*f,m_Y*f,m_Z*f,m_W*f);
return CVector4D(m_X*f,m_Y*f,m_Z*f,m_W*f); }
}
CVector4D operator/(float f) const {
CVector4D operator/(float f) const { float inv=1.0f/f;
float inv=1.0f/f; return CVector4D(m_X*inv,m_Y*inv,m_Z*inv,m_W*inv);
return CVector4D(m_X*inv,m_Y*inv,m_Z*inv,m_W*inv); }
}
CVector4D& operator+=(const CVector4D& t) {
CVector4D& operator+=(const CVector4D& t) { m_X+=t.m_X; m_Y+=t.m_Y; m_Z+=t.m_Z; m_W+=t.m_W;
m_X+=t.m_X; m_Y+=t.m_Y; m_Z+=t.m_Z; m_W+=t.m_W; return *this;
return *this; }
}
CVector4D& operator-=(const CVector4D& t) {
CVector4D& operator-=(const CVector4D& t) { m_X-=t.m_X; m_Y-=t.m_Y; m_Z-=t.m_Z; m_W-=t.m_W;
m_X-=t.m_X; m_Y-=t.m_Y; m_Z-=t.m_Z; m_W-=t.m_W; return *this;
return *this; }
}
CVector4D& operator*=(const CVector4D& t) {
CVector4D& operator*=(const CVector4D& t) { m_X*=t.m_X; m_Y*=t.m_Y; m_Z*=t.m_Z; m_W*=t.m_W;
m_X*=t.m_X; m_Y*=t.m_Y; m_Z*=t.m_Z; m_W*=t.m_W; return *this;
return *this; }
}
CVector4D& operator*=(float f) {
CVector4D& operator*=(float f) { m_X*=f; m_Y*=f; m_Z*=f; m_W*=f;
m_X*=f; m_Y*=f; m_Z*=f; m_W*=f; return *this;
return *this; }
}
CVector4D& operator/=(float f) {
CVector4D& operator/=(float f) { float invf=1.0f/f;
float invf=1.0f/f; m_X*=invf; m_Y*=invf; m_Z*=invf; m_W*=invf;
m_X*=invf; m_Y*=invf; m_Z*=invf; m_W*=invf; return *this;
return *this; }
}
float dot(const CVector4D& a) const {
float dot(const CVector4D& a) const { return m_X*a.m_X+m_Y*a.m_Y+m_Z*a.m_Z+m_W*a.m_W;
return m_X*a.m_X+m_Y*a.m_Y+m_Z*a.m_Z+m_W*a.m_W; }
}
float lengthSquared() const {
float lengthSquared() const { return SQR(m_X)+SQR(m_Y)+SQR(m_Z)+SQR(m_W);
return SQR(m_X)+SQR(m_Y)+SQR(m_Z)+SQR(m_W); }
}
float length() const {
float length() const { return (float) sqrt(lengthSquared());
return (float) sqrt(lengthSquared()); }
}
void normalize() {
void normalize() { float mag=length();
float mag=length(); m_X/=mag; m_Y/=mag; m_Z/=mag; m_W/=mag;
m_X/=mag; m_Y/=mag; m_Z/=mag; m_W/=mag; }
}
public:
public: float m_X,m_Y,m_Z,m_W;
float m_X,m_Y,m_Z,m_W; };
}; //////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif
#endif

View File

@ -1,19 +0,0 @@
#include "Visual.h"
#include "Model.h"
void CVisual::CalcBounds()
{
m_Bounds.SetEmpty();
for (int i=0; i<m_Model->GetModelDef()->GetNumVertices(); i++)
{
SModelVertex *pVertex = &m_Model->GetModelDef()->GetVertices()[i];
CVector3D coord1,coord2;
if (pVertex->m_Bone!=-1) {
coord1=m_Model->GetBonePoses()[pVertex->m_Bone].Transform(pVertex->m_Coords);
} else {
coord1=pVertex->m_Coords;
}
m_Bounds+=m_Transform.Transform(coord1);
}
}

View File

@ -1,18 +0,0 @@
#ifndef _VISUAL_H
#define _VISUAL_H
#include "RenderableObject.h"
class CModel;
class CVisual : public CRenderableObject
{
public:
CVisual() : m_Model(0) {}
void CalcBounds();
CModel* m_Model;
};
#endif

View File

@ -1,364 +1,327 @@
#include "Matrix3D.h" #include "Matrix3D.h"
#include "Renderer.h" #include "Renderer.h"
#include "Terrain.h" #include "Terrain.h"
#include "LightEnv.h" #include "LightEnv.h"
#include "TextureManager.h" #include "TextureManager.h"
#include "Prometheus.h" #include "ObjectManager.h"
#include "Prometheus.h"
#include "time.h"
#include "sdl.h" #include "time.h"
#include "res/tex.h" #include "sdl.h"
#include "detect.h" #include "res/tex.h"
#include "detect.h"
#include <malloc.h>
#include <malloc.h>
// TODO: fix scrolling hack - framerate independent, use SDL
//#include "win.h" // REMOVEME // TODO: fix scrolling hack - framerate independent, use SDL
//#include "win.h" // REMOVEME
void InitScene ();
void InitResources (); void InitScene ();
void RenderScene (); void InitResources ();
void RenderScene ();
extern bool keys[512]; // SDL also defines non-ascii keys; 512 should be enough
extern bool keys[512]; // SDL also defines non-ascii keys; 512 should be enough
CMatrix3D g_WorldMat;
CRenderer g_Renderer; CMatrix3D g_WorldMat;
CTerrain g_Terrain; CRenderer g_Renderer;
CCamera g_Camera; CTerrain g_Terrain;
CLightEnv g_LightEnv; CCamera g_Camera;
CLightEnv g_LightEnv;
int SelPX, SelPY, SelTX, SelTY;
int g_BaseTexCounter = 0; int SelPX, SelPY, SelTX, SelTY;
int g_SecTexCounter = 1; int g_BaseTexCounter = 0;
int g_TransTexCounter = 0; int g_SecTexCounter = 1;
int g_TransTexCounter = 0;
int g_TickCounter = 0;
double g_LastTime; int g_TickCounter = 0;
double g_LastTime;
const int NUM_ALPHA_MAPS = 13;
const int NUM_ALPHA_MAPS = 13;
int mouse_x=50, mouse_y=50;
int mouse_x=50, mouse_y=50;
void terr_init()
{ void terr_init()
int xres,yres; {
get_cur_resolution(xres,yres); int xres,yres;
g_Renderer.Open(xres,yres,32); get_cur_resolution(xres,yres);
g_Renderer.Open(xres,yres,32);
SViewPort vp;
vp.m_X=0; SViewPort vp;
vp.m_Y=0; vp.m_X=0;
vp.m_Width=xres; vp.m_Y=0;
vp.m_Height=yres; vp.m_Width=xres;
g_Camera.SetViewPort(&vp); vp.m_Height=yres;
g_Camera.SetViewPort(&vp);
InitResources ();
InitScene (); InitResources ();
} InitScene ();
}
void terr_update()
{ void terr_update(float time)
// start new frame {
g_Renderer.BeginFrame(); CVector3D right(time*60,0,time*60);
g_Renderer.SetCamera(g_Camera); CVector3D up(time*60,0,-time*60);
// switch on wireframe for terrain if we want it if (mouse_x >= g_xres-2)
g_Renderer.SetTerrainRenderMode(SOLID); g_Camera.m_Orientation.Translate(right);
if (mouse_x <= 3)
///////////////////////////////////////////// g_Camera.m_Orientation.Translate(right*-1);
CVector3D right(1,0,1);
CVector3D up(1,0,-1); if (mouse_y >= g_yres-2)
right.Normalize (); g_Camera.m_Orientation.Translate(up);
up.Normalize (); if (mouse_y <= 3)
g_Camera.m_Orientation.Translate(up*-1);
if (mouse_x >= g_xres-2)
g_Camera.m_Orientation.Translate (right);
if (mouse_x <= 3)
g_Camera.m_Orientation.Translate (right*-1); float fov = g_Camera.GetFOV();
float d = DEGTORAD(0.4f);
if (mouse_y >= g_yres-2) if(keys[SDLK_KP_MINUS])
g_Camera.m_Orientation.Translate (up); if (fov+d < DEGTORAD(90))
if (mouse_y <= 3) g_Camera.SetProjection(1, 1000, fov + d);
g_Camera.m_Orientation.Translate (up*-1); if(keys[SDLK_KP_PLUS])
if (fov-d > DEGTORAD(20))
g_Camera.SetProjection(1, 1000, fov - d);
float fov = g_Camera.GetFOV(); g_Camera.UpdateFrustum ();
float d = DEGTORAD(0.4f); }
if(keys[SDLK_KP_MINUS])
if (fov+d < DEGTORAD(90))
g_Camera.SetProjection (1, 1000, fov + d);
if(keys[SDLK_KP_PLUS])
if (fov-d > DEGTORAD(20))
g_Camera.SetProjection (1, 1000, fov - d);
bool terr_handler(const SDL_Event& ev)
g_Camera.UpdateFrustum (); {
///////////////////////////////////////////// switch(ev.type)
{
case SDL_MOUSEMOTION:
CFrustum frustum=g_Camera.GetFustum(); mouse_x = ev.motion.x;
mouse_y = ev.motion.y;
// iterate through patches; cull everything not visible break;
for (uint j=0; j<g_Terrain.GetPatchesPerSide(); j++)
{ case SDL_KEYDOWN:
for (uint i=0; i<g_Terrain.GetPatchesPerSide(); i++) switch(ev.key.keysym.sym)
{ {
if (frustum.IsBoxVisible (CVector3D(0,0,0),g_Terrain.GetPatch(j, i)->GetBounds())) { case 'W':
g_Renderer.Submit(g_Terrain.GetPatch(j, i)); if (g_Renderer.GetTerrainRenderMode()==WIREFRAME) {
} g_Renderer.SetTerrainRenderMode(SOLID);
} } else {
} g_Renderer.SetTerrainRenderMode(WIREFRAME);
}
// flush the frame to force terrain to be renderered before overlays break;
g_Renderer.FlushFrame();
case 'H':
// g_Renderer.RenderTileOutline (&(g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX])); // quick hack to return camera home, for screenshots (after alt+tabbing)
g_Camera.SetProjection (1, 1000, DEGTORAD(20));
g_Renderer.EndFrame(); g_Camera.m_Orientation.SetXRotation(DEGTORAD(30));
} g_Camera.m_Orientation.RotateY(DEGTORAD(-45));
g_Camera.m_Orientation.Translate (100, 150, -100);
break;
/* case 'L':
g_HillShading = !g_HillShading;
break;*/
bool terr_handler(const SDL_Event& ev)
{ // tile selection
switch(ev.type) case SDLK_DOWN:
{ if(++SelTX > 15)
case SDL_MOUSEMOTION: if(SelPX == g_Terrain.GetPatchesPerSide()-1)
mouse_x = ev.motion.x; SelTX = 15;
mouse_y = ev.motion.y; else
break; SelTX = 0, SelPX++;
break;
case SDL_KEYDOWN:
switch(ev.key.keysym.sym) case SDLK_UP:
{ if(--SelTX < 0)
case 'W': if(SelPX == 0)
if (g_Renderer.GetTerrainRenderMode()==WIREFRAME) { SelTX = 0;
g_Renderer.SetTerrainRenderMode(SOLID); else
} else { SelTX = 15, SelPX--;
g_Renderer.SetTerrainRenderMode(WIREFRAME); break;
} case SDLK_RIGHT:
break; if(++SelTY > 15)
if(SelPY == g_Terrain.GetPatchesPerSide()-1)
case 'H': SelTY = 15;
// quick hack to return camera home, for screenshots (after alt+tabbing) else
g_Camera.SetProjection (1, 1000, DEGTORAD(20)); SelTY = 0, SelPY++;
g_Camera.m_Orientation.SetXRotation(DEGTORAD(30)); break;
g_Camera.m_Orientation.RotateY(DEGTORAD(-45));
g_Camera.m_Orientation.Translate (100, 150, -100); case SDLK_LEFT:
break; if(--SelTY < 0)
if(SelPY == 0)
/* case 'L': SelTY = 0;
g_HillShading = !g_HillShading; else
break;*/ SelTY = 15, SelPY--;
break;
// tile selection
case SDLK_DOWN:
if(++SelTX > 15) case SDLK_KP0:
if(SelPX == g_Terrain.GetPatchesPerSide()-1) {
SelTX = 15; CMiniPatch *MPatch = &g_Terrain.GetPatch(SelPY, SelPX)->m_MiniPatches[SelTY][SelTX];
else /*if (!MPatch->Tex2)
SelTX = 0, SelPX++; {
break; MPatch->m_AlphaMap = AlphaMaps[g_TransTexCounter];
MPatch->Tex2 = BaseTexs[g_SecTexCounter];
case SDLK_UP: }
if(--SelTX < 0) else
if(SelPX == 0) {
SelTX = 0; MPatch->Tex2 = 0;
else MPatch->m_AlphaMap = 0;
SelTX = 15, SelPX--; }*/
break; break;
case SDLK_RIGHT: }
if(++SelTY > 15)
if(SelPY == g_Terrain.GetPatchesPerSide()-1) /*case SDLK_KP1:
SelTY = 15; {
else CMiniPatch *MPatch = &g_Terrain.GetPatch(SelPY, SelPX)->m_MiniPatches[SelTY][SelTX];
SelTY = 0, SelPY++;
break; g_BaseTexCounter++;
if (g_BaseTexCounter > 4)
case SDLK_LEFT: g_BaseTexCounter = 0;
if(--SelTY < 0)
if(SelPY == 0) MPatch->Tex1 = BaseTexs[g_BaseTexCounter];
SelTY = 0; break;
else }
SelTY = 15, SelPY--;
break; case SDLK_KP2:
{
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX];
case SDLK_KP0:
{ if (MPatch->Tex2)
CMiniPatch *MPatch = &g_Terrain.GetPatch(SelPY, SelPX)->m_MiniPatches[SelTY][SelTX]; {
/*if (!MPatch->Tex2) g_SecTexCounter++;
{ if (g_SecTexCounter > 4)
MPatch->m_AlphaMap = AlphaMaps[g_TransTexCounter]; g_SecTexCounter = 0;
MPatch->Tex2 = BaseTexs[g_SecTexCounter];
} MPatch->Tex2 = BaseTexs[g_SecTexCounter];
else }
{
MPatch->Tex2 = 0; break;
MPatch->m_AlphaMap = 0; }
}*/
break; case SDLK_KP3:
} {
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX];
/*case SDLK_KP1:
{ if (MPatch->m_AlphaMap)
CMiniPatch *MPatch = &g_Terrain.GetPatch(SelPY, SelPX)->m_MiniPatches[SelTY][SelTX]; {
g_TransTexCounter++;
g_BaseTexCounter++; if (g_TransTexCounter >= NUM_ALPHA_MAPS)
if (g_BaseTexCounter > 4) g_TransTexCounter = 0;
g_BaseTexCounter = 0;
MPatch->m_AlphaMap = AlphaMaps[g_TransTexCounter];
MPatch->Tex1 = BaseTexs[g_BaseTexCounter]; }
break;
} break;
}*/
case SDLK_KP2:
{ }
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX]; }
if (MPatch->Tex2) return false;
{ }
g_SecTexCounter++;
if (g_SecTexCounter > 4)
g_SecTexCounter = 0;
MPatch->Tex2 = BaseTexs[g_SecTexCounter]; void InitScene ()
} {
// setup default lighting environment
break; g_LightEnv.m_SunColor=RGBColor(1,1,1);
} g_LightEnv.m_Rotation=DEGTORAD(270);
g_LightEnv.m_Elevation=DEGTORAD(45);
case SDLK_KP3: g_LightEnv.m_TerrainAmbientColor=RGBColor(0,0,0);
{ g_LightEnv.m_UnitsAmbientColor=RGBColor(0.4f,0.4f,0.4f);
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX]; g_Renderer.SetLightEnv(&g_LightEnv);
if (MPatch->m_AlphaMap) // load terrain
{ Handle ht = tex_load("terrain.raw");
g_TransTexCounter++; if(ht > 0)
if (g_TransTexCounter >= NUM_ALPHA_MAPS) {
g_TransTexCounter = 0; const u8* p;
int w;
MPatch->m_AlphaMap = AlphaMaps[g_TransTexCounter]; int h;
}
tex_info(ht, &w, &h, NULL, NULL, (void **)&p);
break;
}*/ printf("terrain.raw: %dx%d\n", w, h);
} u16 *p16=new u16[w*h];
} u16 *p16p=p16;
while (p16p < p16+(w*h))
return false; *p16p++ = (*p++) << 8;
}
g_Terrain.Resize(20);
g_Terrain.SetHeightMap(p16);
delete[] p16;
void InitScene ()
{ tex_free(ht);
// setup default lighting environment }
g_LightEnv.m_SunColor=RGBColor(1,1,1);
g_LightEnv.m_Rotation=DEGTORAD(270); // get default texture to apply to terrain
g_LightEnv.m_Elevation=DEGTORAD(45); CTextureEntry* texture=0;
g_LightEnv.m_TerrainAmbientColor=RGBColor(0,0,0); for (uint ii=0;ii<g_TexMan.m_TerrainTextures.size();ii++) {
g_LightEnv.m_UnitsAmbientColor=RGBColor(0.4f,0.4f,0.4f); if (g_TexMan.m_TerrainTextures[ii].m_Textures.size()) {
g_Renderer.SetLightEnv(&g_LightEnv); texture=g_TexMan.m_TerrainTextures[ii].m_Textures[0];
break;
// load terrain }
Handle ht = tex_load("terrain.raw"); }
if(ht > 0)
{
const u8* p; // cover entire terrain with default texture
int w; u32 patchesPerSide=g_Terrain.GetPatchesPerSide();
int h; for (uint pj=0; pj<patchesPerSide; pj++) {
for (uint pi=0; pi<patchesPerSide; pi++) {
tex_info(ht, &w, &h, NULL, NULL, (void **)&p);
CPatch* patch=g_Terrain.GetPatch(pi,pj);
printf("terrain.raw: %dx%d\n", w, h);
for (int j=0;j<16;j++) {
u16 *p16=new u16[w*h]; for (int i=0;i<16;i++) {
u16 *p16p=p16; patch->m_MiniPatches[j][i].Tex1=texture ? texture->m_Handle :0;
while (p16p < p16+(w*h)) }
*p16p++ = (*p++) << 8; }
}
g_Terrain.Resize(20); }
g_Terrain.SetHeightMap(p16);
g_Camera.SetProjection (1, 1000, DEGTORAD(20));
delete[] p16; g_Camera.m_Orientation.SetXRotation(DEGTORAD(30));
g_Camera.m_Orientation.RotateY(DEGTORAD(-45));
tex_free(ht);
} g_Camera.m_Orientation.Translate (100, 150, -100);
// get default texture to apply to terrain SelPX = SelPY = SelTX = SelTY = 0;
// CTextureEntry* texture=0; }
// if (g_TexMan.m_TerrainTextures.size()>0) {
// if (g_TexMan.m_TerrainTextures[0].m_Textures.size()) { void InitResources()
// texture=g_TexMan.m_TerrainTextures[0].m_Textures[0]; {
// } #ifndef _WIN32
// } g_TexMan.AddTextureType("grass");
g_TexMan.AddTexture("Base1.tga", 0);
CTextureEntry* texture=0; #else
for (uint ii=0;ii<g_TexMan.m_TerrainTextures.size();ii++) { g_TexMan.LoadTerrainTextures();
if (g_TexMan.m_TerrainTextures[ii].m_Textures.size()) { g_ObjMan.LoadObjects();
texture=g_TexMan.m_TerrainTextures[ii].m_Textures[0]; #endif
break;
} const char* fns[CRenderer::NumAlphaMaps] = {
} "art/textures/terrain/alphamaps/special/blendcircle.png",
"art/textures/terrain/alphamaps/special/blendlshape.png",
"art/textures/terrain/alphamaps/special/blendedge.png",
// cover entire terrain with default texture "art/textures/terrain/alphamaps/special/blendedgecorner.png",
u32 patchesPerSide=g_Terrain.GetPatchesPerSide(); "art/textures/terrain/alphamaps/special/blendedgetwocorners.png",
for (uint pj=0; pj<patchesPerSide; pj++) { "art/textures/terrain/alphamaps/special/blendfourcorners.png",
for (uint pi=0; pi<patchesPerSide; pi++) { "art/textures/terrain/alphamaps/special/blendtwooppositecorners.png",
"art/textures/terrain/alphamaps/special/blendlshapecorner.png",
CPatch* patch=g_Terrain.GetPatch(pi,pj); "art/textures/terrain/alphamaps/special/blendtwocorners.png",
"art/textures/terrain/alphamaps/special/blendcorner.png",
for (int j=0;j<16;j++) { "art/textures/terrain/alphamaps/special/blendtwoedges.png",
for (int i=0;i<16;i++) { "art/textures/terrain/alphamaps/special/blendthreecorners.png",
patch->m_MiniPatches[j][i].Tex1=texture ? texture->m_Handle :0; "art/textures/terrain/alphamaps/special/blendushape.png",
} "art/textures/terrain/alphamaps/special/blendbad.png"
} };
}
} g_Renderer.LoadAlphaMaps(fns);
}
g_Camera.SetProjection (1, 1000, DEGTORAD(20));
g_Camera.m_Orientation.SetXRotation(DEGTORAD(30));
g_Camera.m_Orientation.RotateY(DEGTORAD(-45));
g_Camera.m_Orientation.Translate (100, 150, -100);
SelPX = SelPY = SelTX = SelTY = 0;
}
void InitResources()
{
#ifndef _WIN32
g_TexMan.AddTextureType("grass");
g_TexMan.AddTexture("Base1.tga", 0);
#else
g_TexMan.LoadTerrainTextures();
#endif
const char* fns[CRenderer::NumAlphaMaps] = {
"art/textures/terrain/alphamaps/special/blendcircle.png",
"art/textures/terrain/alphamaps/special/blendlshape.png",
"art/textures/terrain/alphamaps/special/blendedge.png",
"art/textures/terrain/alphamaps/special/blendedgecorner.png",
"art/textures/terrain/alphamaps/special/blendedgetwocorners.png",
"art/textures/terrain/alphamaps/special/blendfourcorners.png",
"art/textures/terrain/alphamaps/special/blendtwooppositecorners.png",
"art/textures/terrain/alphamaps/special/blendlshapecorner.png",
"art/textures/terrain/alphamaps/special/blendtwocorners.png",
"art/textures/terrain/alphamaps/special/blendcorner.png",
"art/textures/terrain/alphamaps/special/blendtwoedges.png",
"art/textures/terrain/alphamaps/special/blendthreecorners.png",
"art/textures/terrain/alphamaps/special/blendushape.png",
"art/textures/terrain/alphamaps/special/blendbad.png"
};
assert(g_Renderer.LoadAlphaMaps(fns));
}