New terrain files from ScEd 0.0.5.2

This was SVN commit r201.
This commit is contained in:
Simon Brenner 2004-04-13 11:09:36 +00:00
parent 6b7eb9b9d8
commit 6abf0e5b5d
19 changed files with 2498 additions and 0 deletions

308
source/terrain/AABBTree.h Executable file
View File

@ -0,0 +1,308 @@
#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

@ -0,0 +1,272 @@
#include "AlphaMapCalculator.h"
#include <string.h>
#include <stdio.h>
namespace CAlphaMapCalculator {
struct Blend4 {
Blend4(BlendShape4 shape,int alphamap) : m_Shape(shape), m_AlphaMap(alphamap) {}
BlendShape4 m_Shape;
int m_AlphaMap;
};
struct Blend8 {
Blend8(BlendShape8 shape,int alphamap) : m_Shape(shape), m_AlphaMap(alphamap) {}
BlendShape8 m_Shape;
int m_AlphaMap;
};
Blend4 Blends1Neighbour[] =
{
Blend4(BlendShape4(1,0,0,0), 12) // u shape blend
};
Blend4 Blends2Neighbour[] =
{
Blend4(BlendShape4(0,1,1,0), 7), // l shaped corner blend
Blend4(BlendShape4(1,0,1,0), 10) // two edges blend
};
Blend8 Blends2Neighbour8[] =
{
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)
};
Blend4 Blends3Neighbour[] =
{
Blend4(BlendShape4(1,1,1,0), 4) // l shaped corner blend
};
Blend8 Blends3Neighbour8[] =
{
Blend8(BlendShape8(1,1,0,0,1,0,0,0), 10),
Blend8(BlendShape8(1,1,0,0,0,0,0,1), 12),
Blend8(BlendShape8(1,1,1,0,0,0,0,0), 1),
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),
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,0,0,1,0,1,0,0), 12),
Blend8(BlendShape8(0,1,0,1,0,1,0,0), 0)
};
Blend8 Blends4Neighbour8[] =
{
Blend8(BlendShape8(1,1,0,0,1,0,0,1), 10),
Blend8(BlendShape8(1,1,0,1,1,0,0,0), 10),
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),
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(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,0,1,0,1,0,0), 12),
Blend8(BlendShape8(0,1,0,1,0,1,0,1), 0)
};
Blend8 Blends5Neighbour8[] =
{
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),
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,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)
};
Blend8 Blends6Neighbour8[] =
{
Blend8(BlendShape8(1,1,1,1,1,1,0,0), 2),
Blend8(BlendShape8(1,1,1,1,1,0,1,0), 8),
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),
Blend8(BlendShape8(1,1,0,1,1,1,0,1), 10)
};
Blend8 Blends7Neighbour8[] =
{
Blend8(BlendShape8(1,1,1,1,1,1,0,1), 2),
Blend8(BlendShape8(1,1,1,1,1,1,1,0), 9)
};
template<class T>
bool MatchBlendShapeRotated(const T& templateshape,const T& shape,unsigned int& flipflags)
{
// try to match shapes by testing the template shape in normal, and flipped u and v configurations
// test unrotated shape
if (shape==templateshape) {
return true;
}
T tstShape;
templateshape.FlipU(tstShape);
if (shape==tstShape) {
flipflags|=0x02;
return true;
}
templateshape.FlipV(tstShape);
if (shape==tstShape) {
flipflags|=0x01;
return true;
}
return false;
}
template<class T>
int MatchBlendShape(const T& templateshape,const T& shape,unsigned int& flipflags)
{
// try matching unrotated shape first
if (MatchBlendShapeRotated(templateshape,shape,flipflags)) {
return true;
}
// now try iterating through rotations of 90,180,270 degrees
T tstShape;
templateshape.Rotate90(tstShape);
if (MatchBlendShapeRotated(tstShape,shape,flipflags)) {
flipflags|=flipflags ? 0x10 : 0x04;
return true;
}
templateshape.Rotate180(tstShape);
if (MatchBlendShapeRotated(tstShape,shape,flipflags)) {
flipflags|=0x08;
return true;
}
templateshape.Rotate270(tstShape);
if (MatchBlendShapeRotated(tstShape,shape,flipflags)) {
flipflags|=flipflags ? 0x04 : 0x10;
return true;
}
/*
FlipBlendU(templateshape,tstShape);
if (shape==tstShape) {
flipflags|=0x01;
return true;
}
FlipBlendV(templateshape,tstShape);
if (shape==tstShape) {
flipflags|=0x02;
return true;
}
*/
return false;
}
template<class S,class T>
int LookupBlend(int tableSize,const S* table,const T& shape,unsigned int& flipflags)
{
// iterate through known blend shapes
for (int b=0;b<tableSize;b++) {
const S& blend=table[b];
if (MatchBlendShape(blend.m_Shape,shape,flipflags)) {
return blend.m_AlphaMap;
}
}
// eh? 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;
}
int Calculate(BlendShape8 shape,unsigned int& flipflags)
{
// assume we're not going to require flipping
flipflags=0;
// count number of neighbours
int count=0;
for (int i=0;i<8;i++) {
if (shape[i]) count++;
}
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;
} else {
if (count<=4) {
// check if we can consider this a BlendShape4 - ie are any of the diagonals (NE,SE,SW,NW) set?
if (!shape[1] && !shape[3] && !shape[5] && !shape[7]) {
// ok, build a BlendShape4 and use that
BlendShape4 shape4;
shape4[0]=shape[0];
shape4[1]=shape[2];
shape4[2]=shape[4];
shape4[3]=shape[6];
switch (count) {
case 1:
return LookupBlend(sizeof(Blends1Neighbour)/sizeof(Blend4),Blends1Neighbour,shape4,flipflags);
case 2:
return LookupBlend(sizeof(Blends2Neighbour)/sizeof(Blend4),Blends2Neighbour,shape4,flipflags);
case 3:
return LookupBlend(sizeof(Blends3Neighbour)/sizeof(Blend4),Blends3Neighbour,shape4,flipflags);
case 4:
// N,S,E,W have same texture, NE,SE,SW,NW don't; use a blend 4 corners
return 5;
}
}
}
// we've got this far, so now we've got to consider the remaining choices, all containing diagonal elements
switch (count) {
case 1:
// trivial case - just return a circle blend
return 0;
case 2:
return LookupBlend(sizeof(Blends2Neighbour8)/sizeof(Blend8),Blends2Neighbour8,shape,flipflags);
case 3:
return LookupBlend(sizeof(Blends3Neighbour8)/sizeof(Blend8),Blends3Neighbour8,shape,flipflags);
case 4:
return LookupBlend(sizeof(Blends4Neighbour8)/sizeof(Blend8),Blends4Neighbour8,shape,flipflags);
case 5:
return LookupBlend(sizeof(Blends5Neighbour8)/sizeof(Blend8),Blends5Neighbour8,shape,flipflags);
case 6:
return LookupBlend(sizeof(Blends6Neighbour8)/sizeof(Blend8),Blends6Neighbour8,shape,flipflags);
case 7:
return LookupBlend(sizeof(Blends7Neighbour8)/sizeof(Blend8),Blends7Neighbour8,shape,flipflags);
}
}
// 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

@ -0,0 +1,11 @@
#ifndef _ALPHAMAPCALCULATOR_H
#define _ALPHAMAPCALCULATOR_H
#include <string.h>
#include "BlendShapes.h"
namespace CAlphaMapCalculator {
int Calculate(BlendShape8 shape,unsigned int& flipflags);
}
#endif

134
source/terrain/BlendShapes.h Executable file
View File

@ -0,0 +1,134 @@
#ifndef _BLENDSHAPES_H
#define _BLENDSHAPES_H
struct BlendShape4
{
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;
}
int& operator[](int index) { return m_Data[index]; }
const int& operator[](int index) const { return m_Data[index]; }
bool operator==(const BlendShape4& lhs) const {
return memcmp(m_Data,lhs.m_Data,sizeof(BlendShape4))==0;
}
void Rotate90(BlendShape4& dst) const {
dst[0]=m_Data[3];
dst[1]=m_Data[0];
dst[2]=m_Data[1];
dst[3]=m_Data[2];
}
void Rotate180(BlendShape4& dst) const {
dst[0]=m_Data[2];
dst[1]=m_Data[3];
dst[2]=m_Data[0];
dst[3]=m_Data[1];
}
void Rotate270(BlendShape4& dst) const {
dst[0]=m_Data[1];
dst[1]=m_Data[2];
dst[2]=m_Data[3];
dst[3]=m_Data[0];
}
void FlipU(BlendShape4& dst) const {
dst[0]=m_Data[0];
dst[1]=m_Data[3];
dst[2]=m_Data[2];
dst[3]=m_Data[1];
}
void FlipV(BlendShape4& dst) const {
dst[0]=m_Data[2];
dst[1]=m_Data[1];
dst[2]=m_Data[0];
dst[3]=m_Data[3];
}
private:
int m_Data[4];
};
struct BlendShape8
{
public:
BlendShape8() {}
BlendShape8(int a,int b,int c,int d,int e,int f,int g,int h) {
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;
}
int& operator[](int index) { return m_Data[index]; }
const int& operator[](int index) const { return m_Data[index]; }
bool operator==(const BlendShape8& lhs) const {
return memcmp(m_Data,lhs.m_Data,sizeof(BlendShape8))==0;
}
void Rotate90(BlendShape8& dst) const {
dst[0]=m_Data[6];
dst[1]=m_Data[7];
dst[2]=m_Data[0];
dst[3]=m_Data[1];
dst[4]=m_Data[2];
dst[5]=m_Data[3];
dst[6]=m_Data[4];
dst[7]=m_Data[5];
}
void Rotate180(BlendShape8& dst) const {
dst[0]=m_Data[4];
dst[1]=m_Data[5];
dst[2]=m_Data[6];
dst[3]=m_Data[7];
dst[4]=m_Data[0];
dst[5]=m_Data[1];
dst[6]=m_Data[2];
dst[7]=m_Data[3];
}
void Rotate270(BlendShape8& dst) const {
dst[0]=m_Data[2];
dst[1]=m_Data[3];
dst[2]=m_Data[4];
dst[3]=m_Data[5];
dst[4]=m_Data[6];
dst[5]=m_Data[7];
dst[6]=m_Data[0];
dst[7]=m_Data[1];
}
void FlipU(BlendShape8& dst) const {
dst[0]=m_Data[0];
dst[1]=m_Data[7];
dst[2]=m_Data[6];
dst[3]=m_Data[5];
dst[4]=m_Data[4];
dst[5]=m_Data[3];
dst[6]=m_Data[2];
dst[7]=m_Data[1];
}
void FlipV(BlendShape8& dst) const {
dst[0]=m_Data[4];
dst[1]=m_Data[3];
dst[2]=m_Data[2];
dst[3]=m_Data[1];
dst[4]=m_Data[0];
dst[5]=m_Data[7];
dst[6]=m_Data[6];
dst[7]=m_Data[5];
}
private:
int m_Data[8];
};
#endif

156
source/terrain/HBV.h Executable file
View File

@ -0,0 +1,156 @@
// 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

271
source/terrain/ModelRData.cpp Executable file
View File

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

53
source/terrain/ModelRData.h Executable file
View File

@ -0,0 +1,53 @@
#ifndef _MODELRDATA_H
#define _MODELRDATA_H
#include <vector>
#include "res/res.h"
#include "Vector3D.h"
#include "RenderableObject.h"
class CModel;
class CModelRData : public CRenderData
{
public:
CModelRData(CModel* model);
~CModelRData();
void Update();
void Render(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
// object to camera space transform; return sqrd distance to centre of nearest triangle
float BackToFrontIndexSort(CMatrix3D& objToCam);
private:
// build this renderdata object
void Build();
void BuildVertices();
void BuildIndices();
struct SVertex {
// vertex position
CVector3D m_Position;
// vertex uvs for base texture
float m_UVs[2];
// vertex color
SColor4ub m_Color;
};
// owner model
CModel* m_Model;
// handle to models vertex buffer
u32 m_VB;
// model render vertices
SVertex* m_Vertices;
// model render indices
u16* m_Indices;
};
#endif

579
source/terrain/PatchRData.cpp Executable file
View File

@ -0,0 +1,579 @@
#pragma warning(disable:4786)
#include <assert.h>
#include <set>
#include <algorithm>
#include "res/tex.h"
#include "Renderer.h"
#include "PatchRData.h"
#include "AlphaMapCalculator.h"
extern CRenderer g_Renderer;
const int BlendOffsets[8][2] = {
{ 0, -1 },
{ -1, -1 },
{ -1, 0 },
{ -1, 1 },
{ 0, 1 },
{ 1, 1 },
{ 1, 0 },
{ 1, -1 }
};
CPatchRData::CPatchRData(CPatch* patch) : m_Patch(patch), m_Vertices(0), m_VBBase(0), m_VBBlends(0)
{
assert(patch);
// set patches renderdata pointer to point to this object
m_Patch->m_RenderData=this;
// build all data now
Build();
}
CPatchRData::~CPatchRData()
{
delete[] m_Vertices;
}
static Handle GetTerrainTileTexture(CTerrain* terrain,int gx,int gz)
{
CMiniPatch* mp=terrain->GetTile(gx,gz);
return mp ? mp->Tex1 : 0;
}
bool QueryAdjacency(int x,int y,Handle h,Handle* texgrid)
{
for (int j=y-1;j<=y+1;j++) {
for (int i=x-1;i<=x+1;i++) {
if (i<0 || i>PATCH_SIZE+1 || j<0 || j>PATCH_SIZE+1) {
continue;
}
if (texgrid[j*(PATCH_SIZE+2)+i]==h) {
return true;
}
}
}
return false;
}
struct STmpSplat {
Handle m_Texture;
u16 m_Indices[4];
};
void CPatchRData::BuildBlends()
{
m_BlendIndices.clear();
m_BlendSplats.clear();
m_BlendVertices.clear();
// get index of this patch
int px=m_Patch->m_X;
int pz=m_Patch->m_Z;
CTerrain* terrain=m_Patch->m_Parent;
// temporary list of splats
std::vector<STmpSplat> splats;
// set of textures used for splats
std::set<Handle> splatTextures;
// for each tile in patch ..
for (int j=0;j<PATCH_SIZE;j++) {
for (int i=0;i<PATCH_SIZE;i++) {
u32 gx,gz;
CMiniPatch* mp=&m_Patch->m_MiniPatches[j][i];
mp->GetTileIndex(gx,gz);
// build list of textures of higher priority than current tile that are used by neighbouring tiles
std::vector<STex> neighbourTextures;
for (int m=-1;m<=1;m++) {
for (int k=-1;k<=1;k++) {
CMiniPatch* nmp=terrain->GetTile(gx+k,gz+m);
if (nmp) {
if (nmp->Tex1Priority>mp->Tex1Priority || (nmp->Tex1Priority==mp->Tex1Priority && nmp->Tex1>mp->Tex1)) {
STex tex;
tex.m_Handle=nmp->Tex1;
tex.m_Priority=nmp->Tex1Priority;
if (std::find(neighbourTextures.begin(),neighbourTextures.end(),tex)==neighbourTextures.end()) {
neighbourTextures.push_back(tex);
}
}
}
}
}
if (neighbourTextures.size()>0) {
u32 count=neighbourTextures.size();
// sort textures from lowest to highest priority
std::sort(neighbourTextures.begin(),neighbourTextures.end());
// for each of the neighbouring textures ..
for (uint k=0;k<neighbourTextures.size();++k) {
// now build the grid of blends dependent on whether the tile adjacent to the current tile
// uses the current neighbour texture
BlendShape8 shape;
for (int m=0;m<8;m++) {
int ox=gx+BlendOffsets[m][1];
int oz=gz+BlendOffsets[m][0];
// get texture on adjacent tile
Handle atex=GetTerrainTileTexture(terrain,ox,oz);
// fill 0/1 into shape array
shape[m]=(atex==neighbourTextures[k].m_Handle) ? 0 : 1;
}
// calculate the required alphamap and the required rotation of the alphamap from blendshape
unsigned int alphamapflags;
int alphamap=CAlphaMapCalculator::Calculate(shape,alphamapflags);
// now actually render the blend tile (if we need one)
if (alphamap!=-1) {
float u0=g_Renderer.m_AlphaMapCoords[alphamap].u0;
float u1=g_Renderer.m_AlphaMapCoords[alphamap].u1;
float v0=g_Renderer.m_AlphaMapCoords[alphamap].v0;
float v1=g_Renderer.m_AlphaMapCoords[alphamap].v1;
if (alphamapflags & 0x01) {
// flip u
float t=u0;
u0=u1;
u1=t;
}
if (alphamapflags & 0x02) {
// flip v
float t=v0;
v0=v1;
v1=t;
}
int base=0;
if (alphamapflags & 0x04) {
// rotate 1
base=1;
} else if (alphamapflags & 0x08) {
// rotate 2
base=2;
} else if (alphamapflags & 0x10) {
// rotate 3
base=3;
}
SBlendVertex vtx[4];
vtx[(base+0)%4].m_AlphaUVs[0]=u0;
vtx[(base+0)%4].m_AlphaUVs[1]=v0;
vtx[(base+1)%4].m_AlphaUVs[0]=u1;
vtx[(base+1)%4].m_AlphaUVs[1]=v0;
vtx[(base+2)%4].m_AlphaUVs[0]=u1;
vtx[(base+2)%4].m_AlphaUVs[1]=v1;
vtx[(base+3)%4].m_AlphaUVs[0]=u0;
vtx[(base+3)%4].m_AlphaUVs[1]=v1;
int vsize=PATCH_SIZE+1;
SBlendVertex dst;
int vindex=m_BlendVertices.size();
const SBaseVertex& vtx0=m_Vertices[(j*vsize)+i];
dst.m_UVs[0]=i*0.125f;
dst.m_UVs[1]=j*0.125f;
dst.m_AlphaUVs[0]=vtx[0].m_AlphaUVs[0];
dst.m_AlphaUVs[1]=vtx[0].m_AlphaUVs[1];
dst.m_Color=vtx0.m_Color;
dst.m_Position=vtx0.m_Position;
m_BlendVertices.push_back(dst);
const SBaseVertex& vtx1=m_Vertices[(j*vsize)+i+1];
dst.m_UVs[0]=(i+1)*0.125f;
dst.m_UVs[1]=j*0.125f;
dst.m_AlphaUVs[0]=vtx[1].m_AlphaUVs[0];
dst.m_AlphaUVs[1]=vtx[1].m_AlphaUVs[1];
dst.m_Color=vtx1.m_Color;
dst.m_Position=vtx1.m_Position;
m_BlendVertices.push_back(dst);
const SBaseVertex& vtx2=m_Vertices[((j+1)*vsize)+i+1];
dst.m_UVs[0]=(i+1)*0.125f;
dst.m_UVs[1]=(j+1)*0.125f;
dst.m_AlphaUVs[0]=vtx[2].m_AlphaUVs[0];
dst.m_AlphaUVs[1]=vtx[2].m_AlphaUVs[1];
dst.m_Color=vtx2.m_Color;
dst.m_Position=vtx2.m_Position;
m_BlendVertices.push_back(dst);
const SBaseVertex& vtx3=m_Vertices[((j+1)*vsize)+i];
dst.m_UVs[0]=i*0.125f;
dst.m_UVs[1]=(j+1)*0.125f;
dst.m_AlphaUVs[0]=vtx[3].m_AlphaUVs[0];
dst.m_AlphaUVs[1]=vtx[3].m_AlphaUVs[1];
dst.m_Color=vtx3.m_Color;
dst.m_Position=vtx3.m_Position;
m_BlendVertices.push_back(dst);
// build a splat for this quad
STmpSplat splat;
splat.m_Texture=neighbourTextures[k].m_Handle;
splat.m_Indices[0]=vindex;
splat.m_Indices[1]=vindex+1;
splat.m_Indices[2]=vindex+2;
splat.m_Indices[3]=vindex+3;
splats.push_back(splat);
// add this texture to set of unique splat textures
splatTextures.insert(splat.m_Texture);
}
}
}
}
}
// now build outgoing splats
m_BlendSplats.resize(splatTextures.size());
int splatCount=0;
std::set<Handle>::iterator iter=splatTextures.begin();
for (;iter!=splatTextures.end();++iter) {
Handle tex=*iter;
SSplat& splat=m_BlendSplats[splatCount];
splat.m_IndexStart=m_BlendIndices.size();
splat.m_Texture=tex;
for (uint k=0;k<splats.size();k++) {
if (splats[k].m_Texture==tex) {
m_BlendIndices.push_back(splats[k].m_Indices[0]);
m_BlendIndices.push_back(splats[k].m_Indices[1]);
m_BlendIndices.push_back(splats[k].m_Indices[2]);
m_BlendIndices.push_back(splats[k].m_Indices[3]);
splat.m_IndexCount+=4;
}
}
splatCount++;
}
if (g_Renderer.m_Caps.m_VBO) {
if (m_VBBlends) {
// destroy old buffer
glDeleteBuffersARB(1,(GLuint*) &m_VBBlends);
} else {
// generate buffer index
glGenBuffersARB(1,(GLuint*) &m_VBBlends);
}
// create new buffer
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VBBlends);
glBufferDataARB(GL_ARRAY_BUFFER_ARB,m_BlendVertices.size()*sizeof(SBlendVertex),0,GL_STATIC_DRAW_ARB);
u8* vertices=(u8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB,GL_WRITE_ONLY_ARB);
memcpy(vertices,&m_BlendVertices[0],sizeof(SBlendVertex)*m_BlendVertices.size());
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
}
}
void CPatchRData::BuildIndices()
{
// number of vertices in each direction in each patch
int vsize=PATCH_SIZE+1;
// release existing indices and bins
m_Indices.clear();
m_Splats.clear();
// build grid of textures on this patch and boundaries of adjacent patches
std::vector<Handle> textures;
Handle texgrid[PATCH_SIZE][PATCH_SIZE];
for (int j=0;j<PATCH_SIZE;j++) {
for (int i=0;i<PATCH_SIZE;i++) {
Handle h=m_Patch->m_MiniPatches[j][i].Tex1;
texgrid[j][i]=h;
if (std::find(textures.begin(),textures.end(),h)==textures.end()) {
textures.push_back(h);
}
}
}
// now build base splats from interior textures
m_Splats.resize(textures.size());
for (uint i=0;i<m_Splats.size();i++) {
Handle h=textures[i];
SSplat& splat=m_Splats[i];
splat.m_Texture=h;
splat.m_IndexStart=m_Indices.size();
for (int j=0;j<PATCH_SIZE;j++) {
for (int i=0;i<PATCH_SIZE;i++) {
if (texgrid[j][i]==h){
m_Indices.push_back(((j+0)*vsize+(i+0)));
m_Indices.push_back(((j+0)*vsize+(i+1)));
m_Indices.push_back(((j+1)*vsize+(i+1)));
m_Indices.push_back(((j+1)*vsize+(i+0)));
}
}
}
splat.m_IndexCount=m_Indices.size()-splat.m_IndexStart;
}
}
inline int clamp(int x,int min,int max)
{
if (x<min) return min;
else if (x>max) return max;
else return x;
}
static SColor4ub ConvertColor(const RGBColor& src)
{
SColor4ub result;
result.R=clamp(int(src.X*255),0,255);
result.G=clamp(int(src.Y*255),0,255);
result.B=clamp(int(src.Z*255),0,255);
result.A=0xff;
return result;
}
static void BuildHeightmapNormals(int size,u16 *heightmap,CVector3D* normals)
{
int x, y;
int sm=size-1;
for(y = 0;y < size; y++)
for(x = 0; x < size; x++) {
// Access current normalmap grid point
CVector3D* N = &normals[y*size+x];
// Compute normal by using the height differential
u16 h1=(x==sm) ? heightmap[y*size+x] : heightmap[y*size+x+1];
u16 h2=(y==sm) ? heightmap[y*size+x] : heightmap[(y+1)*size+x];
u16 h3=(x==0) ? heightmap[y*size+x] : heightmap[y*size+x-1];
u16 h4=(y==0) ? heightmap[y*size+x] : heightmap[(y-1)*size+x+1];
N->X = (h3-h1)*HEIGHT_SCALE;
N->Y = CELL_SIZE;
N->Z = (h4-h2)*HEIGHT_SCALE;
// Normalize it
float len=N->GetLength();
if (len>0) {
(*N)*=1.0f/len;
} else {
*N=CVector3D(0,0,0);
}
}
}
void CPatchRData::BuildVertices()
{
// number of vertices in each direction in each patch
int vsize=PATCH_SIZE+1;
if (!m_Vertices) {
m_Vertices=new SBaseVertex[vsize*vsize];
}
SBaseVertex* vertices=m_Vertices;
// get index of this patch
u32 px=m_Patch->m_X;
u32 pz=m_Patch->m_Z;
CTerrain* terrain=m_Patch->m_Parent;
u32 mapSize=terrain->GetVerticesPerSide();
// CVector3D* normals=new CVector3D[mapSize*mapSize];
// BuildHeightmapNormals(mapSize,terrain->GetHeightMap(),normals);
// build vertices
for (int j=0; j<vsize; j++)
{
for (int i=0; i<vsize; i++)
{
int ix=px*16+i;
int iz=pz*16+j;
CVector3D pos,normal;
terrain->CalcPosition(ix,iz,pos);
// normal=normals[iz*mapSize+ix];
terrain->CalcNormal(ix,iz,normal);
RGBColor c;
g_Renderer.m_SHCoeffsTerrain.Evaluate(normal,c);
int v=(j*vsize)+i;
vertices[v].m_UVs[0]=i*0.125f;
vertices[v].m_UVs[1]=j*0.125f;
vertices[v].m_Color=ConvertColor(c);
vertices[v].m_Position=pos;
}
}
if (g_Renderer.m_Caps.m_VBO) {
if (!m_VBBase) {
glGenBuffersARB(1,(GLuint*) &m_VBBase);
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VBBase);
glBufferDataARB(GL_ARRAY_BUFFER_ARB,vsize*vsize*sizeof(SBaseVertex),0,GL_STATIC_DRAW_ARB);
} else {
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VBBase);
}
u8* vertices=(u8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB,GL_WRITE_ONLY_ARB);
memcpy(vertices,m_Vertices,sizeof(SBaseVertex)*vsize*vsize);
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
}
// delete[] normals;
}
void CPatchRData::Build()
{
BuildVertices();
BuildIndices();
BuildBlends();
}
void CPatchRData::Update()
{
if (m_UpdateFlags!=0) {
// renderdata changed : rebuild necessary portions
/*
if (data->m_UpdateFlags & RENDERDATA_UPDATE_VERTICES) {
BuildPatchVertices(patch,data);
}
if (data->m_UpdateFlags & RENDERDATA_UPDATE_INDICES) {
BuildPatchIndices(patch,data);
BuildPatchBlends(patch,data);
}
*/
BuildVertices();
BuildIndices();
BuildBlends();
m_UpdateFlags=0;
}
}
void CPatchRData::RenderBase()
{
assert(m_UpdateFlags==0);
u8* base;
if (g_Renderer.m_Caps.m_VBO) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VBBase);
base=0;
} else {
base=(u8*) &m_Vertices[0];
}
// setup data pointers
u32 stride=sizeof(SBaseVertex);
glVertexPointer(3,GL_FLOAT,stride,base+offsetof(SBaseVertex,m_Position));
glColorPointer(4,GL_UNSIGNED_BYTE,stride,base+offsetof(SBaseVertex,m_Color));
glTexCoordPointer(2,GL_FLOAT,stride,base+offsetof(SBaseVertex,m_UVs[0]));
// render each splat
for (uint i=0;i<m_Splats.size();i++) {
SSplat& splat=m_Splats[i];
tex_bind(splat.m_Texture);
glDrawElements(GL_QUADS,splat.m_IndexCount,GL_UNSIGNED_SHORT,&m_Indices[splat.m_IndexStart]);
// bump stats
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_TerrainTris+=splat.m_IndexCount/2;
}
}
void CPatchRData::RenderWireframe()
{
assert(m_UpdateFlags==0);
u8* base;
if (g_Renderer.m_Caps.m_VBO) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VBBase);
base=0;
} else {
base=(u8*) &m_Vertices[0];
}
// setup data pointers
glVertexPointer(3,GL_FLOAT,sizeof(SBaseVertex),base+offsetof(SBaseVertex,m_Position));
// render all base splats at once
glDrawElements(GL_QUADS,m_Indices.size(),GL_UNSIGNED_SHORT,&m_Indices[0]);
// bump stats
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_TerrainTris+=m_Indices.size()/2;
}
void CPatchRData::RenderBlends()
{
assert(m_UpdateFlags==0);
if (m_BlendVertices.size()==0) return;
u8* base;
if (g_Renderer.m_Caps.m_VBO) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VBBlends);
base=0;
} else {
base=(u8*) &m_BlendVertices[0];
}
// setup data pointers
u32 stride=sizeof(SBlendVertex);
glVertexPointer(3,GL_FLOAT,stride,base+offsetof(SBlendVertex,m_Position));
glColorPointer(4,GL_UNSIGNED_BYTE,stride,base+offsetof(SBlendVertex,m_Color));
glClientActiveTexture(GL_TEXTURE0_ARB);
glTexCoordPointer(2,GL_FLOAT,stride,base+offsetof(SBlendVertex,m_UVs[0]));
glClientActiveTexture(GL_TEXTURE1_ARB);
glTexCoordPointer(2,GL_FLOAT,stride,base+offsetof(SBlendVertex,m_AlphaUVs[0]));
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
for (uint i=0;i<m_BlendSplats.size();i++) {
SSplat& splat=m_BlendSplats[i];
tex_bind(splat.m_Texture);
glDrawElements(GL_QUADS,splat.m_IndexCount,GL_UNSIGNED_SHORT,&m_BlendIndices[splat.m_IndexStart]);
// bump stats
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_BlendSplats++;
g_Renderer.m_Stats.m_TerrainTris+=splat.m_IndexCount/2;
}
}
void CPatchRData::RenderOutline()
{
const u16 EdgeIndices[PATCH_SIZE*4] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
33, 50, 67, 84, 101, 118, 135, 152, 169, 186, 203, 220, 237, 254, 271, 288,
287, 286, 285, 284, 283, 282, 281, 280, 279, 278, 277, 276, 275, 274, 273, 272,
255, 238, 221, 204, 187, 170, 153, 136, 119, 102, 85, 68, 51, 34, 17, 0
};
u8* base;
if (g_Renderer.m_Caps.m_VBO) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VBBase);
base=0;
} else {
base=(u8*) &m_Vertices[0];
}
// setup data pointers
glVertexPointer(3,GL_FLOAT,sizeof(SBaseVertex),base+offsetof(SBaseVertex,m_Position));
// render outline as line loop
u32 numIndices=sizeof(EdgeIndices)/sizeof(u16);
glDrawElements(GL_LINE_LOOP,numIndices,GL_UNSIGNED_SHORT,EdgeIndices);
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_TerrainTris+=numIndices/2;
}

89
source/terrain/PatchRData.h Executable file
View File

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

View File

@ -0,0 +1,52 @@
#ifndef _RENDERABLEOBJECT_H
#define _RENDERABLEOBJECT_H
#include "res/res.h"
#include "types.h"
#include "terrain/Bound.h"
#include "terrain/Matrix3D.h"
// dirty flags
#define RENDERDATA_UPDATE_VERTICES (1<<1)
#define RENDERDATA_UPDATE_INDICES (1<<2)
class CRenderData
{
public:
CRenderData() : m_UpdateFlags(0) {}
virtual ~CRenderData() {}
u32 m_UpdateFlags;
};
class CRenderableObject
{
public:
CRenderableObject() : m_RenderData(0) {
m_Transform.SetIdentity();
}
virtual ~CRenderableObject() { delete m_RenderData; }
void SetTransform(const CMatrix3D& transform) {
m_Transform=transform;
CalcBounds();
}
const CMatrix3D& GetTransform() const { return m_Transform; }
// CalcBounds: calculate (and store in m_Bounds) the world space bounds of this object
virtual void CalcBounds() = 0;
const CBound& GetBounds() const { return m_Bounds; }
// object renderdata
CRenderData* m_RenderData;
protected:
// object bounds
CBound m_Bounds;
// local->world space transform
CMatrix3D m_Transform;
};
#endif

24
source/terrain/TextureEntry.h Executable file
View File

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

214
source/terrain/TextureManager.cpp Executable file
View File

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

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

@ -0,0 +1,45 @@
#ifndef _TEXTUREMANAGER_H
#define _TEXTUREMANAGER_H
#include <vector>
#include "TextureEntry.h"
#include "CStr.h"
class CTextureManager
{
public:
struct STextureType
{
// name of this texture type (derived from directory name)
CStr m_Name;
// index in parent array
int m_Index;
// list of textures of this type (found from the texture directory)
std::vector<CTextureEntry*> m_Textures;
};
public:
CTextureManager();
void LoadTerrainTextures();
void AddTextureType(const char* name);
CTextureEntry* FindTexture(const char* filename);
CTextureEntry* FindTexture(Handle handle);
CTextureEntry* AddTexture(const char* filename,int type);
void DeleteTexture(CTextureEntry* entry);
std::vector<STextureType> m_TerrainTextures;
private:
void LoadTerrainTextures(int terraintype,const char* fileext);
void BuildTerrainTypes();
};
extern CTextureManager g_TexMan;
#endif

View File

@ -0,0 +1,138 @@
#include <algorithm>
#include "Renderer.h"
#include "TransparencyRenderer.h"
#include "terrain/Model.h"
#include "terrain/Visual.h"
extern CRenderer g_Renderer;
CTransparencyRenderer g_TransparencyRenderer;
struct SortObjectsByDist {
typedef CTransparencyRenderer::SObject SortObj;
bool operator()(const SortObj& lhs,const SortObj& rhs) {
return lhs.m_Dist>rhs.m_Dist? true : false;
}
};
void CTransparencyRenderer::Render()
{
// 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) {
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
// switch on client states
glEnableClientState(GL_VERTEX_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);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_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);
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);
uint i;
for (i=0;i<m_Objects.size();++i) {
CVisual* visual=m_Objects[i].m_Visual;
CModelRData* modeldata=(CModelRData*) visual->m_Model->m_RenderData;
modeldata->Render(visual->GetTransform(),true);
}
glDepthMask(0);
glAlphaFunc(GL_LEQUAL,0.975f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
for (i=0;i<m_Objects.size();++i) {
CVisual* visual=m_Objects[i].m_Visual;
CModelRData* modeldata=(CModelRData*) visual->m_Model->m_RenderData;
modeldata->Render(visual->GetTransform(),true);
}
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glDepthMask(1);
// switch off client states
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (g_Renderer.m_ModelRenderMode==WIREFRAME) {
// switch wireframe off again
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
} else if (g_Renderer.m_ModelRenderMode==EDGED_FACES) {
// edged faces: need to make a second pass over the data:
// first switch on wireframe
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
// setup some renderstate ..
glDepthMask(0);
g_Renderer.SetTexture(0,0);
glColor4f(1,1,1,0.75f);
glLineWidth(1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
// .. and some client states
glEnableClientState(GL_VERTEX_ARRAY);
// render each model
for (uint i=0;i<m_Objects.size();++i) {
CVisual* visual=m_Objects[i].m_Visual;
CModelRData* modeldata=(CModelRData*) visual->m_Model->m_RenderData;
modeldata->RenderWireframe(visual->GetTransform(),true);
}
// .. and switch off the client states
glDisableClientState(GL_VERTEX_ARRAY);
// .. and restore the renderstates
glDisable(GL_BLEND);
glDepthMask(1);
// restore fill mode, and we're done
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
}
// all transparent objects rendered; release them
m_Objects.clear();
}
void CTransparencyRenderer::Add(CVisual* visual)
{
// resize array, get last object in list
m_Objects.resize(m_Objects.size()+1);
SObject& obj=m_Objects.back();
obj.m_Visual=visual;
// build transform from object to camera space
CMatrix3D objToCam,invcam;
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
CModelRData* modeldata=(CModelRData*) visual->m_Model->m_RenderData;
obj.m_Dist=modeldata->BackToFrontIndexSort(objToCam);
}

View File

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

60
source/terrain/Triangle.cpp Executable file
View File

@ -0,0 +1,60 @@
#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;
}

24
source/terrain/Triangle.h Executable file
View File

@ -0,0 +1,24 @@
#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

19
source/terrain/Visual.cpp Executable file
View File

@ -0,0 +1,19 @@
#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);
}
}

18
source/terrain/Visual.h Executable file
View File

@ -0,0 +1,18 @@
#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