Moved from terrain directory.
This was SVN commit r304.
This commit is contained in:
parent
e5108b095f
commit
2cbc27174c
162
source/maths/Bound.cpp
Executable file
162
source/maths/Bound.cpp
Executable file
@ -0,0 +1,162 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: Bound.cpp
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// necessary includes
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
#include "Bound.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// operator+=: extend this bound to include given bound
|
||||
CBound& CBound::operator+=(const CBound& b)
|
||||
{
|
||||
for (int i=0;i<3;++i) {
|
||||
if (b[0][i]<m_Data[0][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;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// operator+=: extend this bound to include given point
|
||||
CBound& CBound::operator+=(const CVector3D& pt)
|
||||
{
|
||||
for (int i=0;i<3;++i) {
|
||||
if (pt[i]<m_Data[0][i])
|
||||
m_Data[0][i]=pt[i];
|
||||
else if (pt[i]>m_Data[1][i])
|
||||
m_Data[1][i]=pt[i];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RayIntersect: intersect ray with this bound; return true
|
||||
// if ray hits (and store entry and exit times), or false
|
||||
// otherwise
|
||||
// note: incoming ray direction must be normalised
|
||||
bool CBound::RayIntersect(const CVector3D& origin,const CVector3D& dir,
|
||||
float& tmin,float& tmax) const
|
||||
{
|
||||
float t1,t2;
|
||||
float tnear,tfar;
|
||||
|
||||
if (dir[0]==0) {
|
||||
if (origin[0]<m_Data[0][0] || origin[0]>m_Data[1][0])
|
||||
return false;
|
||||
else {
|
||||
tnear=(float) FLT_MIN;
|
||||
tfar=(float) FLT_MAX;
|
||||
}
|
||||
} else {
|
||||
t1=(m_Data[0][0]-origin[0])/dir[0];
|
||||
t2=(m_Data[1][0]-origin[0])/dir[0];
|
||||
|
||||
if (dir[0]<0) {
|
||||
tnear = t2;
|
||||
tfar = t1;
|
||||
} else {
|
||||
tnear = t1;
|
||||
tfar = t2;
|
||||
}
|
||||
|
||||
if (tfar<0)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dir[1]==0 && (origin[1]<m_Data[0][1] || origin[1]>m_Data[1][1]))
|
||||
return false;
|
||||
else {
|
||||
t1=(m_Data[0][1]-origin[1])/dir[1];
|
||||
t2=(m_Data[1][1]-origin[1])/dir[1];
|
||||
|
||||
if (dir[1]<0) {
|
||||
if (t2>tnear)
|
||||
tnear = t2;
|
||||
if (t1<tfar)
|
||||
tfar = t1;
|
||||
} else {
|
||||
if (t1>tnear)
|
||||
tnear = t1;
|
||||
if (t2<tfar)
|
||||
tfar = t2;
|
||||
}
|
||||
|
||||
if (tnear>tfar || tfar<0)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dir[2]==0 && (origin[2]<m_Data[0][2] || origin[2]>m_Data[1][2]))
|
||||
return false;
|
||||
else {
|
||||
t1=(m_Data[0][2]-origin[2])/dir[2];
|
||||
t2=(m_Data[1][2]-origin[2])/dir[2];
|
||||
|
||||
if (dir[2]<0) {
|
||||
if (t2>tnear)
|
||||
tnear = t2;
|
||||
if (t1<tfar)
|
||||
tfar = t1;
|
||||
} else {
|
||||
if (t1>tnear)
|
||||
tnear = t1;
|
||||
if (t2<tfar)
|
||||
tfar = t2;
|
||||
}
|
||||
|
||||
if (tnear>tfar || tfar<0)
|
||||
return false;
|
||||
}
|
||||
|
||||
tmin=tnear;
|
||||
tmax=tfar;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SetEmpty: initialise this bound as empty
|
||||
void CBound::SetEmpty()
|
||||
{
|
||||
m_Data[0]=CVector3D(FLT_MAX,FLT_MAX,FLT_MAX);
|
||||
m_Data[1]=CVector3D(FLT_MIN,FLT_MIN,FLT_MIN);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Transform: transform this bound by given matrix; return transformed bound
|
||||
// in 'result' parameter - slightly modified version of code in Graphic Gems
|
||||
// (can't remember which one it was, though)
|
||||
void CBound::Transform(const CMatrix3D& m,CBound& result) const
|
||||
{
|
||||
assert(this!=&result);
|
||||
|
||||
for (int i=0;i<3;++i) {
|
||||
// handle translation
|
||||
result[0][i]=result[1][i]=m(i,3);
|
||||
|
||||
// Now find the extreme points by considering the product of the
|
||||
// min and max with each component of matrix
|
||||
for(int j=0;j<3;j++) {
|
||||
float a=m(j,i)*m_Data[0][j];
|
||||
float b=m(j,i)*m_Data[1][j];
|
||||
|
||||
if (a<b) {
|
||||
result[0][i]+=a;
|
||||
result[1][i]+=b;
|
||||
} else {
|
||||
result[0][i]+=b;
|
||||
result[1][i]+=a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
55
source/maths/Bound.h
Executable file
55
source/maths/Bound.h
Executable file
@ -0,0 +1,55 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: Bound.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _BOUND_H
|
||||
#define _BOUND_H
|
||||
|
||||
// necessary includes
|
||||
#include "Vector3D.h"
|
||||
#include "Matrix3D.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CBound: basic axis aligned bounding box class
|
||||
class CBound
|
||||
{
|
||||
public:
|
||||
CBound() {}
|
||||
CBound(const CVector3D& min,const CVector3D& max) {
|
||||
m_Data[0]=min; m_Data[1]=max;
|
||||
}
|
||||
|
||||
void Transform(const CMatrix3D& m,CBound& result) const;
|
||||
|
||||
CVector3D& operator[](int index) { return m_Data[index]; }
|
||||
const CVector3D& operator[](int index) const { return m_Data[index]; }
|
||||
|
||||
void SetEmpty();
|
||||
|
||||
CBound& operator+=(const CBound& b);
|
||||
CBound& operator+=(const CVector3D& pt);
|
||||
|
||||
bool RayIntersect(const CVector3D& origin,const CVector3D& dir,float& tmin,float& tmax) const;
|
||||
|
||||
// return the volume of this bounding box
|
||||
float GetVolume() const {
|
||||
CVector3D v=m_Data[1]-m_Data[0];
|
||||
return v.X*v.Y*v.Z;
|
||||
}
|
||||
|
||||
// return the centre of this bounding box
|
||||
void GetCentre(CVector3D& centre) const {
|
||||
centre=(m_Data[0]+m_Data[1])*0.5f;
|
||||
}
|
||||
|
||||
private:
|
||||
CVector3D m_Data[2];
|
||||
};
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#endif
|
540
source/maths/Matrix3D.cpp
Executable file
540
source/maths/Matrix3D.cpp
Executable file
@ -0,0 +1,540 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Matrix3D.Cpp
|
||||
// Last Update: 31/1/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: A Matrix class used for holding and
|
||||
// manipulating transformation info.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
|
||||
#include "Matrix3D.h"
|
||||
#include "Quaternion.h"
|
||||
|
||||
CMatrix3D::CMatrix3D ()
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
_11=a11;
|
||||
_12=a12;
|
||||
_13=a13;
|
||||
_14=a14;
|
||||
|
||||
_21=a21;
|
||||
_22=a22;
|
||||
_23=a23;
|
||||
_24=a24;
|
||||
|
||||
_31=a31;
|
||||
_32=a32;
|
||||
_33=a33;
|
||||
_34=a34;
|
||||
|
||||
_41=a41;
|
||||
_42=a42;
|
||||
_43=a43;
|
||||
_44=a44;
|
||||
}
|
||||
|
||||
//Matrix multiplication
|
||||
CMatrix3D CMatrix3D::operator*(const CMatrix3D& matrix) const
|
||||
{
|
||||
CMatrix3D Temp;
|
||||
|
||||
Temp._11 = _11*matrix._11 +
|
||||
_12*matrix._21 +
|
||||
_13*matrix._31 +
|
||||
_14*matrix._41;
|
||||
|
||||
Temp._12 = _11*matrix._12 +
|
||||
_12*matrix._22 +
|
||||
_13*matrix._32 +
|
||||
_14*matrix._42;
|
||||
|
||||
Temp._13 = _11*matrix._13 +
|
||||
_12*matrix._23 +
|
||||
_13*matrix._33 +
|
||||
_14*matrix._43;
|
||||
|
||||
Temp._14 = _11*matrix._14 +
|
||||
_12*matrix._24 +
|
||||
_13*matrix._34 +
|
||||
_14*matrix._44;
|
||||
|
||||
Temp._21 = _21*matrix._11 +
|
||||
_22*matrix._21 +
|
||||
_23*matrix._31 +
|
||||
_24*matrix._41;
|
||||
|
||||
Temp._22 = _21*matrix._12 +
|
||||
_22*matrix._22 +
|
||||
_23*matrix._32 +
|
||||
_24*matrix._42;
|
||||
|
||||
Temp._23 = _21*matrix._13 +
|
||||
_22*matrix._23 +
|
||||
_23*matrix._33 +
|
||||
_24*matrix._43;
|
||||
|
||||
Temp._24 = _21*matrix._14 +
|
||||
_22*matrix._24 +
|
||||
_23*matrix._34 +
|
||||
_24*matrix._44;
|
||||
|
||||
Temp._31 = _31*matrix._11 +
|
||||
_32*matrix._21 +
|
||||
_33*matrix._31 +
|
||||
_34*matrix._41;
|
||||
|
||||
Temp._32 = _31*matrix._12 +
|
||||
_32*matrix._22 +
|
||||
_33*matrix._32 +
|
||||
_34*matrix._42;
|
||||
|
||||
Temp._33 = _31*matrix._13 +
|
||||
_32*matrix._23 +
|
||||
_33*matrix._33 +
|
||||
_34*matrix._43;
|
||||
|
||||
Temp._34 = _31*matrix._14 +
|
||||
_32*matrix._24 +
|
||||
_33*matrix._34 +
|
||||
_34*matrix._44;
|
||||
|
||||
Temp._41 = _41*matrix._11 +
|
||||
_42*matrix._21 +
|
||||
_43*matrix._31 +
|
||||
_44*matrix._41;
|
||||
|
||||
Temp._42 = _41*matrix._12 +
|
||||
_42*matrix._22 +
|
||||
_43*matrix._32 +
|
||||
_44*matrix._42;
|
||||
|
||||
Temp._43 = _41*matrix._13 +
|
||||
_42*matrix._23 +
|
||||
_43*matrix._33 +
|
||||
_44*matrix._43;
|
||||
|
||||
Temp._44 = _41*matrix._14 +
|
||||
_42*matrix._24 +
|
||||
_43*matrix._34 +
|
||||
_44*matrix._44;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//Matrix multiplication/assignment
|
||||
CMatrix3D& CMatrix3D::operator*=(const CMatrix3D& matrix)
|
||||
{
|
||||
Concatenate(matrix);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//Matrix scaling
|
||||
CMatrix3D CMatrix3D::operator*(float f) const
|
||||
{
|
||||
CMatrix3D tmp;
|
||||
for (int i=0;i<16;i++) {
|
||||
tmp._data[i]=_data[i]*f;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//Matrix scaling/assignment
|
||||
CMatrix3D& CMatrix3D::operator*=(float f)
|
||||
{
|
||||
for (int i=0;i<16;i++) {
|
||||
_data[i]*=f;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//Matrix addition
|
||||
CMatrix3D CMatrix3D::operator+(const CMatrix3D& m) const
|
||||
{
|
||||
CMatrix3D tmp;
|
||||
for (int i=0;i<16;i++) {
|
||||
tmp._data[i]=_data[i]+m._data[i];
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//Matrix addition/assignment
|
||||
CMatrix3D& CMatrix3D::operator+=(const CMatrix3D& m)
|
||||
{
|
||||
for (int i=0;i<16;i++) {
|
||||
_data[i]+=m._data[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//Sets the identity matrix
|
||||
void CMatrix3D::SetIdentity ()
|
||||
{
|
||||
_11=1.0f; _12=0.0f; _13=0.0f; _14=0.0f;
|
||||
_21=0.0f; _22=1.0f; _23=0.0f; _24=0.0f;
|
||||
_31=0.0f; _32=0.0f; _33=1.0f; _34=0.0f;
|
||||
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
|
||||
}
|
||||
|
||||
//Sets the zero matrix
|
||||
void CMatrix3D::SetZero ()
|
||||
{
|
||||
_11=0.0f; _12=0.0f; _13=0.0f; _14=0.0f;
|
||||
_21=0.0f; _22=0.0f; _23=0.0f; _24=0.0f;
|
||||
_31=0.0f; _32=0.0f; _33=0.0f; _34=0.0f;
|
||||
_41=0.0f; _42=0.0f; _43=0.0f; _44=0.0f;
|
||||
}
|
||||
|
||||
//The following clear the matrix and set the
|
||||
//rotation of each of the 3 axes
|
||||
|
||||
void CMatrix3D::SetXRotation (float angle)
|
||||
{
|
||||
float Cos = cosf (angle);
|
||||
float Sin = sinf (angle);
|
||||
|
||||
_11=1.0f; _12=0.0f; _13=0.0f; _14=0.0f;
|
||||
_21=0.0f; _22=Cos; _23=-Sin; _24=0.0f;
|
||||
_31=0.0f; _32=Sin; _33=Cos; _34=0.0f;
|
||||
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
|
||||
}
|
||||
|
||||
void CMatrix3D::SetYRotation (float angle)
|
||||
{
|
||||
float Cos = cosf (angle);
|
||||
float Sin = sinf (angle);
|
||||
|
||||
_11=Cos; _12=0.0f; _13=Sin; _14=0.0f;
|
||||
_21=0.0f; _22=1.0f; _23=0.0f; _24=0.0f;
|
||||
_31=-Sin; _32=0.0f; _33=Cos; _34=0.0f;
|
||||
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
|
||||
}
|
||||
|
||||
void CMatrix3D::SetZRotation (float angle)
|
||||
{
|
||||
float Cos = cosf (angle);
|
||||
float Sin = sinf (angle);
|
||||
|
||||
_11=Cos; _12=-Sin; _13=0.0f; _14=0.0f;
|
||||
_21=Sin; _22=Cos; _23=0.0f; _24=0.0f;
|
||||
_31=0.0f; _32=0.0f; _33=1.0f; _34=0.0f;
|
||||
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
|
||||
}
|
||||
|
||||
//The following apply a rotation to the matrix
|
||||
//about each of the axes;
|
||||
|
||||
void CMatrix3D::RotateX (float angle)
|
||||
{
|
||||
CMatrix3D Temp;
|
||||
Temp.SetXRotation (angle);
|
||||
Concatenate(Temp);
|
||||
}
|
||||
|
||||
void CMatrix3D::RotateY (float angle)
|
||||
{
|
||||
CMatrix3D Temp;
|
||||
Temp.SetYRotation (angle);
|
||||
Concatenate(Temp);
|
||||
}
|
||||
|
||||
void CMatrix3D::RotateZ (float angle)
|
||||
{
|
||||
CMatrix3D Temp;
|
||||
Temp.SetZRotation(angle);
|
||||
Concatenate(Temp);
|
||||
}
|
||||
|
||||
//Sets the translation of the matrix
|
||||
void CMatrix3D::SetTranslation (float x, float y, float z)
|
||||
{
|
||||
_11=1.0f; _12=0.0f; _13=0.0f; _14=x;
|
||||
_21=0.0f; _22=1.0f; _23=0.0f; _24=y;
|
||||
_31=0.0f; _32=0.0f; _33=1.0f; _34=z;
|
||||
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
|
||||
}
|
||||
|
||||
void CMatrix3D::SetTranslation(const CVector3D& vector)
|
||||
{
|
||||
SetTranslation(vector.X, vector.Y, vector.Z);
|
||||
}
|
||||
|
||||
//Applies a translation to the matrix
|
||||
void CMatrix3D::Translate(float x, float y, float z)
|
||||
{
|
||||
CMatrix3D Temp;
|
||||
Temp.SetTranslation(x,y,z);
|
||||
Concatenate(Temp);
|
||||
}
|
||||
|
||||
void CMatrix3D::Translate(const CVector3D &vector)
|
||||
{
|
||||
Translate(vector.X,vector.Y,vector.Z);
|
||||
}
|
||||
|
||||
void CMatrix3D::Concatenate(const CMatrix3D& m)
|
||||
{
|
||||
(*this)=m*(*this);
|
||||
}
|
||||
|
||||
CVector3D CMatrix3D::GetTranslation() const
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = _14;
|
||||
Temp.Y = _24;
|
||||
Temp.Z = _34;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//Clears and sets the scaling of the matrix
|
||||
void CMatrix3D::SetScaling (float x_scale, float y_scale, float z_scale)
|
||||
{
|
||||
_11=x_scale; _12=0.0f; _13=0.0f; _14=0.0f;
|
||||
_21=0.0f; _22=y_scale; _23=0.0f; _24=0.0f;
|
||||
_31=0.0f; _32=0.0f; _33=z_scale; _34=0.0f;
|
||||
_41=0.0f; _42=0.0f; _43=0.0f; _44=1.0f;
|
||||
}
|
||||
|
||||
//Scales the matrix
|
||||
void CMatrix3D::Scale (float x_scale, float y_scale, float z_scale)
|
||||
{
|
||||
CMatrix3D Temp;
|
||||
Temp.SetScaling(x_scale,y_scale,z_scale);
|
||||
Concatenate(Temp);
|
||||
}
|
||||
|
||||
//Returns the transpose of the matrix. For orthonormal
|
||||
//matrices, this is the same is the inverse matrix
|
||||
void CMatrix3D::GetTranspose(CMatrix3D& result) const
|
||||
{
|
||||
result._11 = _11;
|
||||
result._21 = _12;
|
||||
result._31 = _13;
|
||||
result._41 = _14;
|
||||
|
||||
result._12 = _21;
|
||||
result._22 = _22;
|
||||
result._32 = _23;
|
||||
result._42 = _24;
|
||||
|
||||
result._13 = _31;
|
||||
result._23 = _32;
|
||||
result._33 = _33;
|
||||
result._43 = _34;
|
||||
|
||||
result._14 = _41;
|
||||
result._24 = _42;
|
||||
result._34 = _43;
|
||||
result._44 = _44;
|
||||
}
|
||||
|
||||
|
||||
//Get a vector which points to the left of the matrix
|
||||
CVector3D CMatrix3D::GetLeft () const
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = -_11;
|
||||
Temp.Y = -_21;
|
||||
Temp.Z = -_31;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//Get a vector which points up from the matrix
|
||||
CVector3D CMatrix3D::GetUp () const
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = _12;
|
||||
Temp.Y = _22;
|
||||
Temp.Z = _32;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//Get a vector which points to front of the matrix
|
||||
CVector3D CMatrix3D::GetIn () const
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = _13;
|
||||
Temp.Y = _23;
|
||||
Temp.Z = _33;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
|
||||
//Transform a vector by this matrix
|
||||
CVector3D CMatrix3D::Transform (const CVector3D &vector) const
|
||||
{
|
||||
CVector3D result;
|
||||
Transform(vector,result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void CMatrix3D::Transform(const CVector3D& vector,CVector3D& result) const
|
||||
{
|
||||
result.X = _11*vector.X + _12*vector.Y + _13*vector.Z + _14;
|
||||
result.Y = _21*vector.X + _22*vector.Y + _23*vector.Z + _24;
|
||||
result.Z = _31*vector.X + _32*vector.Y + _33*vector.Z + _34;
|
||||
}
|
||||
|
||||
//Transform a vector by this matrix
|
||||
CVector4D CMatrix3D::Transform(const CVector4D &vector) const
|
||||
{
|
||||
CVector4D result;
|
||||
Transform(vector,result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void CMatrix3D::Transform(const CVector4D& vector,CVector4D& result) const
|
||||
{
|
||||
result[0] = _11*vector[0] + _12*vector[1] + _13*vector[2] + _14*vector[3];
|
||||
result[1] = _21*vector[0] + _22*vector[1] + _23*vector[2] + _24*vector[3];
|
||||
result[2] = _31*vector[0] + _32*vector[1] + _33*vector[2] + _34*vector[3];
|
||||
result[3] = _41*vector[0] + _42*vector[1] + _43*vector[2] + _44*vector[3];
|
||||
}
|
||||
|
||||
//Only rotate (not translate) a vector by this matrix
|
||||
CVector3D CMatrix3D::Rotate(const CVector3D& vector) const
|
||||
{
|
||||
CVector3D result;
|
||||
Rotate(vector,result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void CMatrix3D::Rotate(const CVector3D& vector,CVector3D& result) const
|
||||
{
|
||||
result.X = _11*vector.X + _12*vector.Y + _13*vector.Z;
|
||||
result.Y = _21*vector.X + _22*vector.Y + _23*vector.Z;
|
||||
result.Z = _31*vector.X + _32*vector.Y + _33*vector.Z;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RotateTransposed: rotate a vector by the transpose of this matrix
|
||||
CVector3D CMatrix3D::RotateTransposed(const CVector3D& vector) const
|
||||
{
|
||||
CVector3D result;
|
||||
RotateTransposed(vector,result);
|
||||
return result;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RotateTransposed: rotate a vector by the transpose of this matrix
|
||||
void CMatrix3D::RotateTransposed(const CVector3D& vector,CVector3D& result) const
|
||||
{
|
||||
result.X = _11*vector.X + _21*vector.Y + _31*vector.Z;
|
||||
result.Y = _12*vector.X + _22*vector.Y + _32*vector.Z;
|
||||
result.Z = _13*vector.X + _23*vector.Y + _33*vector.Z;
|
||||
}
|
||||
|
||||
|
||||
void CMatrix3D::GetInverse(CMatrix3D& dst) const
|
||||
{
|
||||
float tmp[12]; // temp array for pairs
|
||||
float src[16]; // array of transpose source matrix
|
||||
float det; // determinant
|
||||
|
||||
// transpose matrix
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
src[i] = _data[i*4];
|
||||
src[i + 4] = _data[i*4 + 1];
|
||||
src[i + 8] = _data[i*4 + 2];
|
||||
src[i + 12] = _data[i*4 + 3];
|
||||
}
|
||||
|
||||
// calculate pairs for first 8 elements (cofactors)
|
||||
tmp[0] = src[10] * src[15];
|
||||
tmp[1] = src[11] * src[14];
|
||||
tmp[2] = src[9] * src[15];
|
||||
tmp[3] = src[11] * src[13];
|
||||
tmp[4] = src[9] * src[14];
|
||||
tmp[5] = src[10] * src[13];
|
||||
tmp[6] = src[8] * src[15];
|
||||
tmp[7] = src[11] * src[12];
|
||||
tmp[8] = src[8] * src[14];
|
||||
tmp[9] = src[10] * src[12];
|
||||
tmp[10] = src[8] * src[13];
|
||||
tmp[11] = src[9] * src[12];
|
||||
|
||||
// calculate first 8 elements (cofactors)
|
||||
dst._data[0] = tmp[0]*src[5] + tmp[3]*src[6] + tmp[4]*src[7];
|
||||
dst._data[0] -= tmp[1]*src[5] + tmp[2]*src[6] + tmp[5]*src[7];
|
||||
dst._data[1] = tmp[1]*src[4] + tmp[6]*src[6] + tmp[9]*src[7];
|
||||
dst._data[1] -= tmp[0]*src[4] + tmp[7]*src[6] + tmp[8]*src[7];
|
||||
dst._data[2] = tmp[2]*src[4] + tmp[7]*src[5] + tmp[10]*src[7];
|
||||
dst._data[2] -= tmp[3]*src[4] + tmp[6]*src[5] + tmp[11]*src[7];
|
||||
dst._data[3] = tmp[5]*src[4] + tmp[8]*src[5] + tmp[11]*src[6];
|
||||
dst._data[3] -= tmp[4]*src[4] + tmp[9]*src[5] + tmp[10]*src[6];
|
||||
dst._data[4] = tmp[1]*src[1] + tmp[2]*src[2] + tmp[5]*src[3];
|
||||
dst._data[4] -= tmp[0]*src[1] + tmp[3]*src[2] + tmp[4]*src[3];
|
||||
dst._data[5] = tmp[0]*src[0] + tmp[7]*src[2] + tmp[8]*src[3];
|
||||
dst._data[5] -= tmp[1]*src[0] + tmp[6]*src[2] + tmp[9]*src[3];
|
||||
dst._data[6] = tmp[3]*src[0] + tmp[6]*src[1] + tmp[11]*src[3];
|
||||
dst._data[6] -= tmp[2]*src[0] + tmp[7]*src[1] + tmp[10]*src[3];
|
||||
dst._data[7] = tmp[4]*src[0] + tmp[9]*src[1] + tmp[10]*src[2];
|
||||
dst._data[7] -= tmp[5]*src[0] + tmp[8]*src[1] + tmp[11]*src[2];
|
||||
|
||||
// calculate pairs for second 8 elements (cofactors)
|
||||
tmp[0] = src[2]*src[7];
|
||||
tmp[1] = src[3]*src[6];
|
||||
tmp[2] = src[1]*src[7];
|
||||
tmp[3] = src[3]*src[5];
|
||||
tmp[4] = src[1]*src[6];
|
||||
tmp[5] = src[2]*src[5];
|
||||
tmp[6] = src[0]*src[7];
|
||||
tmp[7] = src[3]*src[4];
|
||||
tmp[8] = src[0]*src[6];
|
||||
tmp[9] = src[2]*src[4];
|
||||
tmp[10] = src[0]*src[5];
|
||||
tmp[11] = src[1]*src[4];
|
||||
|
||||
// calculate second 8 elements (cofactors)
|
||||
dst._data[8] = tmp[0]*src[13] + tmp[3]*src[14] + tmp[4]*src[15];
|
||||
dst._data[8] -= tmp[1]*src[13] + tmp[2]*src[14] + tmp[5]*src[15];
|
||||
dst._data[9] = tmp[1]*src[12] + tmp[6]*src[14] + tmp[9]*src[15];
|
||||
dst._data[9] -= tmp[0]*src[12] + tmp[7]*src[14] + tmp[8]*src[15];
|
||||
dst._data[10] = tmp[2]*src[12] + tmp[7]*src[13] + tmp[10]*src[15];
|
||||
dst._data[10]-= tmp[3]*src[12] + tmp[6]*src[13] + tmp[11]*src[15];
|
||||
dst._data[11] = tmp[5]*src[12] + tmp[8]*src[13] + tmp[11]*src[14];
|
||||
dst._data[11]-= tmp[4]*src[12] + tmp[9]*src[13] + tmp[10]*src[14];
|
||||
dst._data[12] = tmp[2]*src[10] + tmp[5]*src[11] + tmp[1]*src[9];
|
||||
dst._data[12]-= tmp[4]*src[11] + tmp[0]*src[9] + tmp[3]*src[10];
|
||||
dst._data[13] = tmp[8]*src[11] + tmp[0]*src[8] + tmp[7]*src[10];
|
||||
dst._data[13]-= tmp[6]*src[10] + tmp[9]*src[11] + tmp[1]*src[8];
|
||||
dst._data[14] = tmp[6]*src[9] + tmp[11]*src[11] + tmp[3]*src[8];
|
||||
dst._data[14]-= tmp[10]*src[11] + tmp[2]*src[8] + tmp[7]*src[9];
|
||||
dst._data[15] = tmp[10]*src[10] + tmp[4]*src[8] + tmp[9]*src[9];
|
||||
dst._data[15]-= tmp[8]*src[9] + tmp[11]*src[10] + tmp[5]*src[8];
|
||||
|
||||
// calculate matrix inverse
|
||||
det=src[0]*dst._data[0]+src[1]*dst._data[1]+src[2]*dst._data[2]+src[3]*dst._data[3];
|
||||
det = 1/det;
|
||||
for ( int j = 0; j < 16; j++) {
|
||||
dst._data[j] *= det;
|
||||
}
|
||||
}
|
||||
|
||||
void CMatrix3D::Rotate(const CQuaternion& quat)
|
||||
{
|
||||
CMatrix3D rotationMatrix=quat.ToMatrix();
|
||||
Concatenate(rotationMatrix);
|
||||
}
|
||||
|
||||
void CMatrix3D::SetRotation(const CQuaternion& quat)
|
||||
{
|
||||
quat.ToMatrix(*this);
|
||||
}
|
||||
|
||||
|
123
source/maths/Matrix3D.h
Executable file
123
source/maths/Matrix3D.h
Executable file
@ -0,0 +1,123 @@
|
||||
#ifndef __MATRIX3D_H
|
||||
#define __MATRIX3D_H
|
||||
|
||||
#include <math.h>
|
||||
#include "Vector3D.h"
|
||||
#include "Vector4D.h"
|
||||
|
||||
class CQuaternion;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// CMatrix3D: a 4x4 matrix class for common operations in 3D
|
||||
class CMatrix3D
|
||||
{
|
||||
public:
|
||||
// the matrix data itself - accessible as either longhand names
|
||||
// or via a flat array
|
||||
union {
|
||||
struct {
|
||||
float _11, _21, _31, _41;
|
||||
float _12, _22, _32, _42;
|
||||
float _13, _23, _33, _43;
|
||||
float _14, _24, _34, _44;
|
||||
};
|
||||
float _data[16];
|
||||
};
|
||||
|
||||
public:
|
||||
// constructors
|
||||
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);
|
||||
|
||||
// accessors to individual elements of matrix
|
||||
float& operator()(int col,int row) {
|
||||
return _data[row*4+col];
|
||||
}
|
||||
const float& operator()(int col,int row) const {
|
||||
return _data[row*4+col];
|
||||
}
|
||||
|
||||
// matrix multiplication
|
||||
CMatrix3D operator*(const CMatrix3D &matrix) const;
|
||||
// matrix multiplication/assignment
|
||||
CMatrix3D& operator*=(const CMatrix3D &matrix);
|
||||
// matrix scaling
|
||||
CMatrix3D operator*(float f) const;
|
||||
// matrix scaling/assignment
|
||||
CMatrix3D& operator*=(float f);
|
||||
// matrix addition
|
||||
CMatrix3D operator+(const CMatrix3D &matrix) const;
|
||||
// matrix addition/assignment
|
||||
CMatrix3D& operator+=(const CMatrix3D &matrix);
|
||||
|
||||
// set this matrix to the identity matrix
|
||||
void SetIdentity();
|
||||
// set this matrix to the zero matrix
|
||||
void SetZero();
|
||||
|
||||
// concatenate arbitrary matrix onto this matrix
|
||||
void Concatenate(const CMatrix3D& m);
|
||||
|
||||
// set this matrix to a rotation matrix for a rotation about X axis of given angle
|
||||
void SetXRotation(float angle);
|
||||
// set this matrix to a rotation matrix for a rotation about Y axis of given angle
|
||||
void SetYRotation(float angle);
|
||||
// set this matrix to a rotation matrix for a rotation about Z axis of given angle
|
||||
void SetZRotation(float angle);
|
||||
// set this matrix to a rotation described by given quaternion
|
||||
void SetRotation(const CQuaternion& quat);
|
||||
|
||||
// concatentate a rotation about the X axis onto this matrix
|
||||
void RotateX(float angle);
|
||||
// concatentate a rotation about the Y axis onto this matrix
|
||||
void RotateY(float angle);
|
||||
// concatentate a rotation about the Z axis onto this matrix
|
||||
void RotateZ(float angle);
|
||||
// concatentate a rotation described by given quaternion
|
||||
void Rotate(const CQuaternion& quat);
|
||||
|
||||
// set this matrix to given translation
|
||||
void SetTranslation(float x, float y, float z);
|
||||
void SetTranslation(const CVector3D& vector);
|
||||
|
||||
// concatenate given translation onto this matrix
|
||||
void Translate(float x, float y, float z);
|
||||
void Translate(const CVector3D& vector);
|
||||
|
||||
// set this matrix to the given scaling matrix
|
||||
void SetScaling(float x_scale, float y_scale, float z_scale);
|
||||
|
||||
// concatentate given scaling matrix onto this matrix
|
||||
void Scale(float x_scale, float y_scale, float z_scale);
|
||||
|
||||
// calculate the inverse of this matrix, store in dst
|
||||
void GetInverse(CMatrix3D& dst) const;
|
||||
|
||||
// calculate the transpose of this matrix, store in dst
|
||||
void GetTranspose(CMatrix3D& dst) const;
|
||||
|
||||
// return the translation component of this matrix
|
||||
CVector3D GetTranslation() const;
|
||||
// return left vector, derived from rotation
|
||||
CVector3D GetLeft() const;
|
||||
// return up vector, derived from rotation
|
||||
CVector3D GetUp() const;
|
||||
// return forward vector, derived from rotation
|
||||
CVector3D GetIn() const;
|
||||
|
||||
// transform a 3D vector by this matrix
|
||||
void Transform(const CVector3D &vector,CVector3D& result) const;
|
||||
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
|
138
source/maths/Plane.cpp
Executable file
138
source/maths/Plane.cpp
Executable file
@ -0,0 +1,138 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Plane.Cpp
|
||||
// Last Update: 17/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: A Plane in R3 and several utility methods.
|
||||
// Note that the format used for the plane
|
||||
// equation is Ax + By + Cz + D = 0, where
|
||||
// <A,B,C> is the normal vector.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#include "Plane.h"
|
||||
|
||||
CPlane::CPlane ()
|
||||
{
|
||||
m_Norm.Clear ();
|
||||
m_Dist = 0.0f;
|
||||
}
|
||||
|
||||
//sets the plane equation from 3 points on that plane
|
||||
void CPlane::Set (CVector3D &p1, CVector3D &p2, CVector3D &p3)
|
||||
{
|
||||
CVector3D D1, D2;
|
||||
CVector3D Norm;
|
||||
|
||||
//calculate two vectors on the surface of the plane
|
||||
D1 = p2-p1;
|
||||
D2 = p3-p1;
|
||||
|
||||
//cross multiply gives normal
|
||||
Norm = D2.Cross(D1);
|
||||
|
||||
Set (Norm, p1);
|
||||
}
|
||||
|
||||
//sets the plane equation from a normal and a point on
|
||||
//that plane
|
||||
void CPlane::Set (CVector3D &norm, CVector3D &point)
|
||||
{
|
||||
m_Norm = norm;
|
||||
|
||||
m_Dist = - (norm.X * point.X +
|
||||
norm.Y * point.Y +
|
||||
norm.Z * point.Z);
|
||||
|
||||
// Normalize ();
|
||||
}
|
||||
|
||||
//normalizes the plane equation
|
||||
void CPlane::Normalize ()
|
||||
{
|
||||
float Scale;
|
||||
|
||||
Scale = 1.0f/m_Norm.GetLength ();
|
||||
|
||||
m_Norm.X *= Scale;
|
||||
m_Norm.Y *= Scale;
|
||||
m_Norm.Z *= Scale;
|
||||
m_Dist *= Scale;
|
||||
}
|
||||
|
||||
//returns the side of the plane on which this point
|
||||
//lies.
|
||||
PLANESIDE CPlane::ClassifyPoint (const CVector3D &point) const
|
||||
{
|
||||
float Dist;
|
||||
|
||||
Dist = m_Norm.X * point.X +
|
||||
m_Norm.Y * point.Y +
|
||||
m_Norm.Z * point.Z +
|
||||
m_Dist;
|
||||
|
||||
if (Dist > 0.0f)
|
||||
return PS_FRONT;
|
||||
else if (Dist < 0.0f)
|
||||
return PS_BACK;
|
||||
|
||||
return PS_ON;
|
||||
}
|
||||
|
||||
//solves the plane equation for a particular point
|
||||
float CPlane::DistanceToPlane (const CVector3D &point) const
|
||||
{
|
||||
float Dist;
|
||||
|
||||
Dist = m_Norm.X * point.X +
|
||||
m_Norm.Y * point.Y +
|
||||
m_Norm.Z * point.Z +
|
||||
m_Dist;
|
||||
|
||||
return Dist;
|
||||
}
|
||||
|
||||
//calculates the intersection point of a line with this
|
||||
//plane. Returns false if there is no intersection
|
||||
bool CPlane::FindLineSegIntersection (CVector3D &start, CVector3D &end, CVector3D *intsect)
|
||||
{
|
||||
PLANESIDE StartS, EndS;
|
||||
CVector3D Dir;
|
||||
float Length;
|
||||
|
||||
//work out where each point is
|
||||
StartS = ClassifyPoint (start);
|
||||
EndS = ClassifyPoint (end);
|
||||
|
||||
//if they are not on opposite sides of the plane return false
|
||||
if (StartS == EndS)
|
||||
return false;
|
||||
|
||||
//work out a normalized vector in the direction start to end
|
||||
Dir = end - start;
|
||||
Dir.Normalize ();
|
||||
|
||||
//a bit of algebra to work out how much we need to scale
|
||||
//this direction vector to get to the plane
|
||||
Length = -m_Norm.Dot(start)/m_Norm.Dot(Dir);
|
||||
|
||||
//scale it by this amount
|
||||
Dir *= Length;
|
||||
|
||||
//workout actual position vector of impact
|
||||
*intsect = start + Dir;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPlane::FindRayIntersection (CVector3D &start, CVector3D &direction, CVector3D *intsect)
|
||||
{
|
||||
float dot = m_Norm.Dot (direction);
|
||||
if (dot == 0.0f)
|
||||
return false;
|
||||
|
||||
CVector3D a;
|
||||
*intsect = start - (direction * (DistanceToPlane (start)/dot));
|
||||
return true;
|
||||
}
|
58
source/maths/Plane.h
Executable file
58
source/maths/Plane.h
Executable file
@ -0,0 +1,58 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Plane.h
|
||||
// Last Update: 17/2/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: A Plane in R3 and several utility methods.
|
||||
// Note that the format used for the plane
|
||||
// equation is Ax + By + Cz + D = 0, where
|
||||
// <A,B,C> is the normal vector.
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef PLANE_H
|
||||
#define PLANE_H
|
||||
|
||||
#include "Vector3D.h"
|
||||
|
||||
enum PLANESIDE
|
||||
{
|
||||
PS_FRONT,
|
||||
PS_BACK,
|
||||
PS_ON
|
||||
};
|
||||
|
||||
class CPlane
|
||||
{
|
||||
public:
|
||||
CPlane ();
|
||||
|
||||
//sets the plane equation from 3 points on that plane
|
||||
void Set (CVector3D &p1, CVector3D &p2, CVector3D &p3);
|
||||
|
||||
//sets the plane equation from a normal and a point on
|
||||
//that plane
|
||||
void Set (CVector3D &norm, CVector3D &point);
|
||||
|
||||
//normalizes the plane equation
|
||||
void Normalize ();
|
||||
|
||||
//returns the side of the plane on which this point
|
||||
//lies.
|
||||
PLANESIDE ClassifyPoint (const CVector3D &point) const;
|
||||
|
||||
//solves the plane equation for a particular point
|
||||
float DistanceToPlane (const CVector3D &point) const;
|
||||
|
||||
//calculates the intersection point of a line with this
|
||||
//plane. Returns false if there is no intersection
|
||||
bool FindLineSegIntersection (CVector3D &start, CVector3D &end, CVector3D *intsect);
|
||||
bool FindRayIntersection (CVector3D &start, CVector3D &direction, CVector3D *intsect);
|
||||
|
||||
public:
|
||||
CVector3D m_Norm; //normal vector of the plane
|
||||
float m_Dist; //Plane distance (ie D in the plane eq.)
|
||||
};
|
||||
|
||||
#endif
|
202
source/maths/Quaternion.cpp
Executable file
202
source/maths/Quaternion.cpp
Executable file
@ -0,0 +1,202 @@
|
||||
/************************************************************
|
||||
*
|
||||
* File Name: Quaternion.Cpp
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
************************************************************/
|
||||
|
||||
#include "Quaternion.h"
|
||||
|
||||
const float EPSILON=0.0001f;
|
||||
|
||||
|
||||
CQuaternion::CQuaternion()
|
||||
{
|
||||
m_V.Clear ();
|
||||
m_W = 0;
|
||||
}
|
||||
|
||||
//quaternion addition
|
||||
CQuaternion CQuaternion::operator + (CQuaternion &quat)
|
||||
{
|
||||
CQuaternion Temp;
|
||||
|
||||
Temp.m_W = m_W + quat.m_W;
|
||||
Temp.m_V = m_V + quat.m_V;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//quaternion addition/assignment
|
||||
CQuaternion &CQuaternion::operator += (CQuaternion &quat)
|
||||
{
|
||||
m_W += quat.m_W;
|
||||
m_V += quat.m_V;
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
//quaternion multiplication
|
||||
CQuaternion CQuaternion::operator * (CQuaternion &quat)
|
||||
{
|
||||
CQuaternion Temp;
|
||||
|
||||
Temp.m_W = (m_W * quat.m_W) - (m_V.Dot(quat.m_V));
|
||||
Temp.m_V = (m_V.Cross(quat.m_V)) + (quat.m_V * m_W) + (m_V * quat.m_W);
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//quaternion multiplication/assignment
|
||||
CQuaternion &CQuaternion::operator *= (CQuaternion &quat)
|
||||
{
|
||||
(*this) = (*this) * quat;
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
|
||||
void CQuaternion::FromEularAngles (float x, float y, float z)
|
||||
{
|
||||
float cr, cp, cy;
|
||||
float sr, sp, sy;
|
||||
|
||||
CQuaternion QRoll, QPitch, QYaw;
|
||||
|
||||
cr = cosf(x * 0.5f);
|
||||
cp = cosf(y * 0.5f);
|
||||
cy = cosf(z * 0.5f);
|
||||
|
||||
sr = sinf(x * 0.5f);
|
||||
sp = sinf(y * 0.5f);
|
||||
sy = sinf(z * 0.5f);
|
||||
|
||||
QRoll.m_V.Set (sr,0,0);
|
||||
QRoll.m_W = cr;
|
||||
|
||||
QPitch.m_V.Set (0,sp,0);
|
||||
QPitch.m_W = cp;
|
||||
|
||||
QYaw.m_V.Set (0,0,sy);
|
||||
QYaw.m_W = cy;
|
||||
|
||||
(*this) = QYaw * QPitch * QRoll;
|
||||
}
|
||||
|
||||
CMatrix3D CQuaternion::ToMatrix () const
|
||||
{
|
||||
CMatrix3D result;
|
||||
ToMatrix(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void CQuaternion::ToMatrix(CMatrix3D& result) const
|
||||
{
|
||||
float x2, y2, z2;
|
||||
float wx, wy, wz, xx, xy, xz, yy, yz, zz;
|
||||
|
||||
// calculate coefficients
|
||||
x2 = m_V.X + m_V.X;
|
||||
y2 = m_V.Y + m_V.Y;
|
||||
z2 = m_V.Z + m_V.Z;
|
||||
|
||||
xx = m_V.X * x2;
|
||||
xy = m_V.X * y2;
|
||||
xz = m_V.X * z2;
|
||||
|
||||
yy = m_V.Y * y2;
|
||||
yz = m_V.Y * z2;
|
||||
|
||||
zz = m_V.Z * z2;
|
||||
|
||||
wx = m_W * x2;
|
||||
wy = m_W * y2;
|
||||
wz = m_W * z2;
|
||||
|
||||
result._11 = 1.0f - (yy + zz);
|
||||
result._12 = xy - wz;
|
||||
result._13 = xz + wy;
|
||||
result._14 = 0;
|
||||
|
||||
result._21 = xy + wz;
|
||||
result._22 = 1.0f - (xx + zz);
|
||||
result._23 = yz - wx;
|
||||
result._24 = 0;
|
||||
|
||||
result._31 = xz - wy;
|
||||
result._32 = yz + wx;
|
||||
result._33 = 1.0f - (xx + yy);
|
||||
result._34 = 0;
|
||||
|
||||
result._41 = 0;
|
||||
result._42 = 0;
|
||||
result._43 = 0;
|
||||
result._44 = 1;
|
||||
}
|
||||
|
||||
void CQuaternion::Slerp(const CQuaternion& from,const CQuaternion& to, float ratio)
|
||||
{
|
||||
float to1[4];
|
||||
float omega, cosom, sinom, scale0, scale1;
|
||||
|
||||
// calc cosine
|
||||
cosom = from.m_V.X * to.m_V.X +
|
||||
from.m_V.Y * to.m_V.Y +
|
||||
from.m_V.Z * to.m_V.Z +
|
||||
from.m_W * to.m_W;
|
||||
|
||||
|
||||
// adjust signs (if necessary)
|
||||
if (cosom < 0.0)
|
||||
{
|
||||
cosom = -cosom;
|
||||
to1[0] = -to.m_V.X;
|
||||
to1[1] = -to.m_V.Y;
|
||||
to1[2] = -to.m_V.Z;
|
||||
to1[3] = -to.m_W;
|
||||
}
|
||||
else
|
||||
{
|
||||
to1[0] = to.m_V.X;
|
||||
to1[1] = to.m_V.Y;
|
||||
to1[2] = to.m_V.Z;
|
||||
to1[3] = to.m_W;
|
||||
}
|
||||
|
||||
// calculate coefficients
|
||||
if ((1.0f - cosom) > EPSILON)
|
||||
{
|
||||
// standard case (slerp)
|
||||
omega = acosf(cosom);
|
||||
sinom = sinf(omega);
|
||||
scale0 = sinf((1.0f - ratio) * omega) / sinom;
|
||||
scale1 = sinf(ratio * omega) / sinom;
|
||||
}
|
||||
else
|
||||
{
|
||||
// "from" and "to" quaternions are very close
|
||||
// ... so we can do a linear interpolation
|
||||
scale0 = 1.0f - ratio;
|
||||
scale1 = ratio;
|
||||
}
|
||||
|
||||
// calculate final values
|
||||
m_V.X = scale0 * from.m_V.X + scale1 * to1[0];
|
||||
m_V.Y = scale0 * from.m_V.Y + scale1 * to1[1];
|
||||
m_V.Z = scale0 * from.m_V.Z + scale1 * to1[2];
|
||||
m_W = scale0 * from.m_W + scale1 * to1[3];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FromAxisAngle: create a quaternion from axis/angle representation of a rotation
|
||||
void CQuaternion::FromAxisAngle(const CVector3D& axis,float angle)
|
||||
{
|
||||
float sinHalfTheta=(float) sin(angle/2);
|
||||
float cosHalfTheta=(float) cos(angle/2);
|
||||
|
||||
m_V.X=axis.X*sinHalfTheta;
|
||||
m_V.Y=axis.Y*sinHalfTheta;
|
||||
m_V.Z=axis.Z*sinHalfTheta;
|
||||
m_W=cosHalfTheta;
|
||||
}
|
47
source/maths/Quaternion.h
Executable file
47
source/maths/Quaternion.h
Executable file
@ -0,0 +1,47 @@
|
||||
/************************************************************
|
||||
*
|
||||
* File Name: Quaternion.H
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
************************************************************/
|
||||
|
||||
#ifndef QUATERNION_H
|
||||
#define QUATERNION_H
|
||||
|
||||
#include "Matrix3D.h"
|
||||
|
||||
class CQuaternion
|
||||
{
|
||||
public:
|
||||
CVector3D m_V;
|
||||
float m_W;
|
||||
|
||||
public:
|
||||
CQuaternion();
|
||||
|
||||
//quaternion addition
|
||||
CQuaternion operator + (CQuaternion &quat);
|
||||
//quaternion addition/assignment
|
||||
CQuaternion &operator += (CQuaternion &quat);
|
||||
|
||||
//quaternion multiplication
|
||||
CQuaternion operator * (CQuaternion &quat);
|
||||
//quaternion multiplication/assignment
|
||||
CQuaternion &operator *= (CQuaternion &quat);
|
||||
|
||||
void FromEularAngles (float x, float y, float z);
|
||||
|
||||
//convert the quaternion to matrix
|
||||
CMatrix3D ToMatrix() const;
|
||||
void ToMatrix(CMatrix3D& result) const;
|
||||
|
||||
//sphere interpolation
|
||||
void Slerp(const CQuaternion& from,const CQuaternion& to, float ratio);
|
||||
|
||||
// create a quaternion from axis/angle representation of a rotation
|
||||
void FromAxisAngle(const CVector3D& axis,float angle);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
153
source/maths/Vector3D.cpp
Executable file
153
source/maths/Vector3D.cpp
Executable file
@ -0,0 +1,153 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Vector3D.Cpp
|
||||
// Last Update: 28/1/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: Provides an interface for a vector in R3 and
|
||||
// allows vector and scalar operations on it
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#include "Vector3D.h"
|
||||
|
||||
CVector3D::CVector3D (float x, float y, float z)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
}
|
||||
|
||||
int CVector3D::operator ! () const
|
||||
{
|
||||
if (X != 0.0f ||
|
||||
Y != 0.0f ||
|
||||
Z != 0.0f)
|
||||
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//vector addition
|
||||
CVector3D CVector3D::operator + (const CVector3D &vector) const
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = X + vector.X;
|
||||
Temp.Y = Y + vector.Y;
|
||||
Temp.Z = Z + vector.Z;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//vector addition/assignment
|
||||
CVector3D &CVector3D::operator += (const CVector3D &vector)
|
||||
{
|
||||
X += vector.X;
|
||||
Y += vector.Y;
|
||||
Z += vector.Z;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//vector subtraction
|
||||
CVector3D CVector3D::operator - (const CVector3D &vector) const
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = X - vector.X;
|
||||
Temp.Y = Y - vector.Y;
|
||||
Temp.Z = Z - vector.Z;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//vector negation
|
||||
CVector3D CVector3D::operator-() const
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = -X;
|
||||
Temp.Y = -Y;
|
||||
Temp.Z = -Z;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
//vector subtrcation/assignment
|
||||
CVector3D &CVector3D::operator -= (const CVector3D &vector)
|
||||
{
|
||||
X -= vector.X;
|
||||
Y -= vector.Y;
|
||||
Z -= vector.Z;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//scalar multiplication
|
||||
CVector3D CVector3D::operator * (float value) const
|
||||
{
|
||||
CVector3D Temp;
|
||||
|
||||
Temp.X = X * value;
|
||||
Temp.Y = Y * value;
|
||||
Temp.Z = Z * value;
|
||||
|
||||
return Temp;
|
||||
}
|
||||
|
||||
//scalar multiplication/assignment
|
||||
CVector3D& CVector3D::operator *= (float value)
|
||||
{
|
||||
X *= value;
|
||||
Y *= value;
|
||||
Z *= value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void CVector3D::Set (float x, float y, float z)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
}
|
||||
|
||||
void CVector3D::Clear ()
|
||||
{
|
||||
X = Y = Z = 0.0f;
|
||||
}
|
||||
|
||||
//Dot product
|
||||
float CVector3D::Dot (const CVector3D &vector) const
|
||||
{
|
||||
return ( X * vector.X +
|
||||
Y * vector.Y +
|
||||
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;
|
||||
}
|
67
source/maths/Vector3D.h
Executable file
67
source/maths/Vector3D.h
Executable file
@ -0,0 +1,67 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: Vector3D.H
|
||||
// Last Update: 28/1/02
|
||||
// Author: Poya Manouchehri
|
||||
//
|
||||
// Description: Provides an interface for a vector in R3 and
|
||||
// allows vector and scalar operations on it
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef VECTOR3D_H
|
||||
#define VECTOR3D_H
|
||||
|
||||
#include <math.h>
|
||||
#include "res/res.h"
|
||||
#include "MathUtil.h"
|
||||
|
||||
class CVector3D
|
||||
{
|
||||
public:
|
||||
float X, Y, Z;
|
||||
|
||||
public:
|
||||
CVector3D () { }
|
||||
CVector3D (float x, float y, float z);
|
||||
|
||||
int operator ! () const ;
|
||||
|
||||
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/assignment
|
||||
CVector3D &operator += (const CVector3D &vector);
|
||||
|
||||
//vector subtraction
|
||||
CVector3D operator - (const CVector3D &vector) const ;
|
||||
//vector subtraction/assignment
|
||||
CVector3D &operator -= (const CVector3D &vector);
|
||||
|
||||
//scalar multiplication
|
||||
CVector3D operator * (float value) const ;
|
||||
//scalar multiplication/assignment
|
||||
CVector3D& operator *= (float value);
|
||||
|
||||
// negation
|
||||
CVector3D operator-() const;
|
||||
|
||||
public:
|
||||
void Set (float x, float y, float z);
|
||||
void Clear ();
|
||||
|
||||
//Dot product
|
||||
float Dot (const CVector3D &vector) const;
|
||||
//Cross product
|
||||
CVector3D Cross (const CVector3D &vector) const;
|
||||
|
||||
//Returns length of the vector
|
||||
float GetLength () const;
|
||||
void Normalize ();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
110
source/maths/Vector4D.h
Executable file
110
source/maths/Vector4D.h
Executable file
@ -0,0 +1,110 @@
|
||||
//***********************************************************
|
||||
//
|
||||
// Name: CVector4D.h
|
||||
// Last Update: 02/11/03
|
||||
// Author: Rich Cross
|
||||
//
|
||||
// Description: Provides an interface for a vector in R4 and
|
||||
// allows vector and scalar operations on it
|
||||
//
|
||||
//***********************************************************
|
||||
|
||||
#ifndef _VECTOR4D_H
|
||||
#define _VECTOR4D_H
|
||||
|
||||
|
||||
#include <math.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CVector4D:
|
||||
class CVector4D
|
||||
{
|
||||
public:
|
||||
CVector4D() {}
|
||||
CVector4D(const float f[4]) { m_X=f[0]; m_Y=f[1]; m_Z=f[2]; m_W=f[3]; }
|
||||
CVector4D(float x,float y,float z,float w) { m_X=x; m_Y=y; m_Z=z; m_W=w; }
|
||||
CVector4D(const CVector4D& p) { m_X=p.m_X; m_Y=p.m_Y; m_Z=p.m_Z; m_W=p.m_W; }
|
||||
|
||||
operator float*() {
|
||||
return &m_X;
|
||||
}
|
||||
|
||||
operator const float*() const {
|
||||
return &m_X;
|
||||
}
|
||||
|
||||
CVector4D operator-() const {
|
||||
return CVector4D(-m_X,-m_Y,-m_Z,-m_W);
|
||||
}
|
||||
|
||||
CVector4D operator+(const CVector4D& t) const {
|
||||
return CVector4D(m_X+t.m_X,m_Y+t.m_Y,m_Z+t.m_Z,m_W+t.m_W);
|
||||
}
|
||||
|
||||
CVector4D operator-(const CVector4D& t) const {
|
||||
return CVector4D(m_X-t.m_X,m_Y-t.m_Y,m_Z-t.m_Z,m_W-t.m_W);
|
||||
}
|
||||
|
||||
CVector4D operator*(const CVector4D& t) const {
|
||||
return CVector4D(m_X*t.m_X,m_Y*t.m_Y,m_Z*t.m_Z,m_W*t.m_W);
|
||||
}
|
||||
|
||||
CVector4D operator*(float f) const {
|
||||
return CVector4D(m_X*f,m_Y*f,m_Z*f,m_W*f);
|
||||
}
|
||||
|
||||
CVector4D operator/(float f) const {
|
||||
float inv=1.0f/f;
|
||||
return CVector4D(m_X*inv,m_Y*inv,m_Z*inv,m_W*inv);
|
||||
}
|
||||
|
||||
CVector4D& operator+=(const CVector4D& t) {
|
||||
m_X+=t.m_X; m_Y+=t.m_Y; m_Z+=t.m_Z; m_W+=t.m_W;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CVector4D& operator-=(const CVector4D& t) {
|
||||
m_X-=t.m_X; m_Y-=t.m_Y; m_Z-=t.m_Z; m_W-=t.m_W;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CVector4D& operator*=(const CVector4D& t) {
|
||||
m_X*=t.m_X; m_Y*=t.m_Y; m_Z*=t.m_Z; m_W*=t.m_W;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CVector4D& operator*=(float f) {
|
||||
m_X*=f; m_Y*=f; m_Z*=f; m_W*=f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CVector4D& operator/=(float f) {
|
||||
float invf=1.0f/f;
|
||||
m_X*=invf; m_Y*=invf; m_Z*=invf; m_W*=invf;
|
||||
return *this;
|
||||
}
|
||||
|
||||
float dot(const CVector4D& a) const {
|
||||
return m_X*a.m_X+m_Y*a.m_Y+m_Z*a.m_Z+m_W*a.m_W;
|
||||
}
|
||||
|
||||
float lengthSquared() const {
|
||||
return SQR(m_X)+SQR(m_Y)+SQR(m_Z)+SQR(m_W);
|
||||
}
|
||||
|
||||
float length() const {
|
||||
return (float) sqrt(lengthSquared());
|
||||
}
|
||||
|
||||
void normalize() {
|
||||
float mag=length();
|
||||
m_X/=mag; m_Y/=mag; m_Z/=mag; m_W/=mag;
|
||||
}
|
||||
|
||||
public:
|
||||
float m_X,m_Y,m_Z,m_W;
|
||||
};
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#endif
|
303
source/renderer/AlphaMapCalculator.cpp
Executable file
303
source/renderer/AlphaMapCalculator.cpp
Executable file
@ -0,0 +1,303 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: AlphaMapCalculator.cpp
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "AlphaMapCalculator.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CAlphaMapCalculator: functionality for calculating which alpha blend map
|
||||
// fits a given shape
|
||||
namespace CAlphaMapCalculator {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Blend4: structure mapping a blend shape for N,E,S,W to a particular map
|
||||
struct Blend4 {
|
||||
Blend4(BlendShape4 shape,int alphamap) : m_Shape(shape), m_AlphaMap(alphamap) {}
|
||||
|
||||
BlendShape4 m_Shape;
|
||||
int m_AlphaMap;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Blend8: structure mapping a blend shape for N,NE,E,SE,S,SW,W,NW to a
|
||||
// particular map
|
||||
struct Blend8 {
|
||||
Blend8(BlendShape8 shape,int alphamap) : m_Shape(shape), m_AlphaMap(alphamap) {}
|
||||
|
||||
BlendShape8 m_Shape;
|
||||
int m_AlphaMap;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Data tables for mapping between shapes and blend maps
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const Blend4 Blends1Neighbour[] =
|
||||
{
|
||||
Blend4(BlendShape4(1,0,0,0), 12)
|
||||
};
|
||||
|
||||
|
||||
const Blend4 Blends2Neighbour[] =
|
||||
{
|
||||
Blend4(BlendShape4(0,1,1,0), 7),
|
||||
Blend4(BlendShape4(1,0,1,0), 10)
|
||||
};
|
||||
|
||||
const Blend8 Blends2Neighbour8[] =
|
||||
{
|
||||
Blend8(BlendShape8(1,1,0,0,0,0,0,0), 12),
|
||||
Blend8(BlendShape8(1,0,0,0,0,1,0,0), 12),
|
||||
Blend8(BlendShape8(0,1,0,1,0,0,0,0), 0) ,
|
||||
Blend8(BlendShape8(0,1,0,0,0,1,0,0), 0)
|
||||
};
|
||||
|
||||
const Blend4 Blends3Neighbour[] =
|
||||
{
|
||||
Blend4(BlendShape4(1,1,1,0), 4)
|
||||
};
|
||||
|
||||
const 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)
|
||||
};
|
||||
|
||||
const 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)
|
||||
};
|
||||
|
||||
const 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)
|
||||
};
|
||||
|
||||
const 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)
|
||||
};
|
||||
|
||||
const Blend8 Blends7Neighbour8[] =
|
||||
{
|
||||
Blend8(BlendShape8(1,1,1,1,1,1,0,1), 2),
|
||||
Blend8(BlendShape8(1,1,1,1,1,1,1,0), 9)
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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>
|
||||
bool MatchBlendShapeFlipped(const T& templateshape,const T& shape,unsigned int& flags)
|
||||
{
|
||||
// test unrotated shape
|
||||
if (shape==templateshape) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// test against shape flipped in U
|
||||
T tstShape;
|
||||
templateshape.FlipU(tstShape);
|
||||
if (shape==tstShape) {
|
||||
flags|=BLENDMAP_FLIPU;
|
||||
return true;
|
||||
}
|
||||
|
||||
// test against shape flipped in V
|
||||
templateshape.FlipV(tstShape);
|
||||
if (shape==tstShape) {
|
||||
flags|=BLENDMAP_FLIPV;
|
||||
return true;
|
||||
}
|
||||
|
||||
// no joy; no match by flipping
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MatchBlendShape: try and find a matching blendmap, and the required flip/
|
||||
// rotation flags, to fit the given shape to the template
|
||||
template<class T>
|
||||
int MatchBlendShape(const T& templateshape,const T& shape,unsigned int& flags)
|
||||
{
|
||||
// try matching unrotated shape first using just flipping
|
||||
if (MatchBlendShapeFlipped(templateshape,shape,flags)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// now try iterating through rotations of 90,180,270 degrees
|
||||
T tstShape;
|
||||
templateshape.Rotate90(tstShape);
|
||||
if (MatchBlendShapeFlipped(tstShape,shape,flags)) {
|
||||
// update flags - note if we've flipped in u or v, we need to rotate in
|
||||
// the opposite direction
|
||||
flags|=flags ? BLENDMAP_ROTATE270 : BLENDMAP_ROTATE90;
|
||||
return true;
|
||||
}
|
||||
|
||||
templateshape.Rotate180(tstShape);
|
||||
if (MatchBlendShapeFlipped(tstShape,shape,flags)) {
|
||||
flags|=BLENDMAP_ROTATE180;
|
||||
return true;
|
||||
}
|
||||
|
||||
templateshape.Rotate270(tstShape);
|
||||
if (MatchBlendShapeFlipped(tstShape,shape,flags)) {
|
||||
// update flags - note if we've flipped in u or v, we need to rotate in
|
||||
// the opposite direction
|
||||
flags|=flags ? BLENDMAP_ROTATE90 : BLENDMAP_ROTATE270;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// LookupBlend: find and return the blendmap fitting the given shape by
|
||||
// iterating through the given data table and testing each shape in flipped and
|
||||
// rotated forms until a match is found
|
||||
template<class S,class T>
|
||||
int LookupBlend(int tableSize,const S* table,const T& shape,unsigned int& flags)
|
||||
{
|
||||
// iterate through known blend shapes
|
||||
for (int b=0;b<tableSize;b++) {
|
||||
const S& blend=table[b];
|
||||
if (MatchBlendShape(blend.m_Shape,shape,flags)) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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)
|
||||
{
|
||||
// assume we're not going to require flipping or rotating
|
||||
flags=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,flags);
|
||||
|
||||
case 2:
|
||||
return LookupBlend(sizeof(Blends2Neighbour)/sizeof(Blend4),Blends2Neighbour,shape4,flags);
|
||||
|
||||
case 3:
|
||||
return LookupBlend(sizeof(Blends3Neighbour)/sizeof(Blend4),Blends3Neighbour,shape4,flags);
|
||||
|
||||
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,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
|
31
source/renderer/AlphaMapCalculator.h
Executable file
31
source/renderer/AlphaMapCalculator.h
Executable file
@ -0,0 +1,31 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: AlphaMapCalculator.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _ALPHAMAPCALCULATOR_H
|
||||
#define _ALPHAMAPCALCULATOR_H
|
||||
|
||||
#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
|
142
source/renderer/BlendShapes.h
Executable file
142
source/renderer/BlendShapes.h
Executable file
@ -0,0 +1,142 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: BlendShapes.h
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@wildfiregames.com
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#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[2];
|
||||
dst[1]=m_Data[1];
|
||||
dst[2]=m_Data[0];
|
||||
dst[3]=m_Data[3];
|
||||
}
|
||||
|
||||
void FlipV(BlendShape4& dst) const {
|
||||
dst[0]=m_Data[0];
|
||||
dst[1]=m_Data[3];
|
||||
dst[2]=m_Data[2];
|
||||
dst[3]=m_Data[1];
|
||||
}
|
||||
|
||||
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[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];
|
||||
}
|
||||
|
||||
void FlipV(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];
|
||||
}
|
||||
|
||||
private:
|
||||
int m_Data[8];
|
||||
};
|
||||
|
||||
#endif
|
553
source/renderer/PatchRData.cpp
Executable file
553
source/renderer/PatchRData.cpp
Executable file
@ -0,0 +1,553 @@
|
||||
#pragma warning(disable:4786)
|
||||
|
||||
#include <assert.h>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include "res/tex.h"
|
||||
#include "Renderer.h"
|
||||
#include "PatchRData.h"
|
||||
#include "AlphaMapCalculator.h"
|
||||
|
||||
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);
|
||||
Build();
|
||||
}
|
||||
|
||||
CPatchRData::~CPatchRData()
|
||||
{
|
||||
delete[] m_Vertices;
|
||||
if (m_VBBase) glDeleteBuffersARB(1,(GLuint*) &m_VBBase);
|
||||
if (m_VBBlends) glDeleteBuffersARB(1,(GLuint*) &m_VBBlends);
|
||||
}
|
||||
|
||||
|
||||
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 & BLENDMAP_FLIPU) {
|
||||
// flip u
|
||||
float t=u0;
|
||||
u0=u1;
|
||||
u1=t;
|
||||
}
|
||||
|
||||
if (alphamapflags & BLENDMAP_FLIPV) {
|
||||
// flip v
|
||||
float t=v0;
|
||||
v0=v1;
|
||||
v1=t;
|
||||
}
|
||||
|
||||
int base=0;
|
||||
if (alphamapflags & BLENDMAP_ROTATE90) {
|
||||
// rotate 1
|
||||
base=1;
|
||||
} else if (alphamapflags & BLENDMAP_ROTATE180) {
|
||||
// rotate 2
|
||||
base=2;
|
||||
} else if (alphamapflags & BLENDMAP_ROTATE270) {
|
||||
// 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),&m_BlendVertices[0],GL_STATIC_DRAW_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();
|
||||
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_VBBase);
|
||||
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB,0,vsize*vsize*sizeof(SBaseVertex),m_Vertices);
|
||||
}
|
||||
}
|
||||
|
||||
void CPatchRData::Build()
|
||||
{
|
||||
BuildVertices();
|
||||
BuildIndices();
|
||||
BuildBlends();
|
||||
}
|
||||
|
||||
void CPatchRData::Update()
|
||||
{
|
||||
if (m_UpdateFlags!=0) {
|
||||
// TODO,RC 11/04/04 - need to only rebuild necessary bits of renderdata rather
|
||||
// than everything; it's complicated slightly because the blends are dependent
|
||||
// on both vertex and index 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];
|
||||
g_Renderer.BindTexture(0,tex_id(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::RenderStreams(u32 streamflags)
|
||||
{
|
||||
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));
|
||||
if (streamflags & STREAM_UV0) glTexCoordPointer(2,GL_FLOAT,sizeof(SBaseVertex),base+offsetof(SBaseVertex,m_UVs));
|
||||
else if (streamflags & STREAM_POSTOUV0) glTexCoordPointer(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]));
|
||||
|
||||
for (uint i=0;i<m_BlendSplats.size();i++) {
|
||||
SSplat& splat=m_BlendSplats[i];
|
||||
g_Renderer.BindTexture(0,tex_id(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;
|
||||
}
|
91
source/renderer/PatchRData.h
Executable file
91
source/renderer/PatchRData.h
Executable file
@ -0,0 +1,91 @@
|
||||
#ifndef _PATCHRDATA_H
|
||||
#define _PATCHRDATA_H
|
||||
|
||||
#include <vector>
|
||||
#include "res/res.h"
|
||||
#include "Color.h"
|
||||
#include "Vector3D.h"
|
||||
#include "RenderableObject.h"
|
||||
|
||||
class CPatch;
|
||||
|
||||
class CPatchRData : public CRenderData
|
||||
{
|
||||
public:
|
||||
CPatchRData(CPatch* patch);
|
||||
~CPatchRData();
|
||||
|
||||
void Update();
|
||||
void RenderBase();
|
||||
void RenderBlends();
|
||||
void RenderOutline();
|
||||
void RenderStreams(u32 streamflags);
|
||||
|
||||
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
|
77
source/renderer/SHCoeffs.cpp
Executable file
77
source/renderer/SHCoeffs.cpp
Executable file
@ -0,0 +1,77 @@
|
||||
//----------------------------------------------------------------
|
||||
//
|
||||
// Name: SHCoeffs.h
|
||||
// Last Update: 25/11/03
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@0ad.wildfiregames.com
|
||||
//
|
||||
// Description: implementation of 9 component spherical harmonic
|
||||
// lighting
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#include "SHCoeffs.h"
|
||||
|
||||
CSHCoeffs::CSHCoeffs()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void CSHCoeffs::Clear()
|
||||
{
|
||||
for (int i=0;i<9;i++) {
|
||||
_data[i].Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void CSHCoeffs::AddAmbientLight(const RGBColor& color)
|
||||
{
|
||||
_data[0]+=color;
|
||||
}
|
||||
|
||||
void CSHCoeffs::AddDirectionalLight(const CVector3D& lightDir,const RGBColor& lightColor)
|
||||
{
|
||||
CVector3D dirToLight(-lightDir.X,-lightDir.Y,-lightDir.Z);
|
||||
|
||||
const float normalisation = PI*16/17;
|
||||
const float c1 = SQR(0.282095f) * normalisation * 1.0f;
|
||||
const float c2 = SQR(0.488603f) * normalisation * (2.0f/3.0f);
|
||||
const float c3 = SQR(1.092548f) * normalisation * (1.0f/4.0f);
|
||||
const float c4 = SQR(0.315392f) * normalisation * (1.0f/4.0f);
|
||||
const float c5 = SQR(0.546274f) * normalisation * (1.0f/4.0f);
|
||||
|
||||
_data[0]+=lightColor*c1;
|
||||
_data[1]+=lightColor*c2*dirToLight.X;
|
||||
_data[2]+=lightColor*c2*dirToLight.Y;
|
||||
_data[3]+=lightColor*c2*dirToLight.Z;
|
||||
_data[4]+=lightColor*c3*dirToLight.X*dirToLight.Z;
|
||||
_data[5]+=lightColor*c3*dirToLight.Z*dirToLight.Y;
|
||||
_data[6]+=lightColor*c3*dirToLight.Y*dirToLight.X;
|
||||
_data[7]+=lightColor*c4*(3.0f*SQR(dirToLight.Z)-1.0f);
|
||||
_data[8]+=lightColor*c5*(SQR(dirToLight.X)-SQR(dirToLight.Y));
|
||||
}
|
||||
|
||||
void CSHCoeffs::Evaluate(const CVector3D& normal,RGBColor& color) const
|
||||
{
|
||||
#if 1
|
||||
float c4=normal.X*normal.Z;
|
||||
float c5=normal.Z*normal.Y;
|
||||
float c6=normal.Y*normal.X;
|
||||
float c7=(3*SQR(normal.Z)-1.0f);
|
||||
float c8=(SQR(normal.X)-SQR(normal.Y));
|
||||
|
||||
for (int i=0;i<3;i++) {
|
||||
color[i]=_data[0][i];
|
||||
color[i]+=_data[1][i]*normal.X;
|
||||
color[i]+=_data[2][i]*normal.Y;
|
||||
color[i]+=_data[3][i]*normal.Z;
|
||||
color[i]+=_data[4][i]*c4;
|
||||
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
|
||||
}
|
36
source/renderer/SHCoeffs.h
Executable file
36
source/renderer/SHCoeffs.h
Executable file
@ -0,0 +1,36 @@
|
||||
//----------------------------------------------------------------
|
||||
//
|
||||
// Name: SHCoeffs.h
|
||||
// Last Update: 25/11/03
|
||||
// Author: Rich Cross
|
||||
// Contact: rich@0ad.wildfiregames.com
|
||||
//
|
||||
// Description: implementation of 9 component spherical harmonic
|
||||
// lighting
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#ifndef __SHCOEFFS_H
|
||||
#define __SHCOEFFS_H
|
||||
|
||||
#include "Color.h"
|
||||
|
||||
class CSHCoeffs
|
||||
{
|
||||
public:
|
||||
CSHCoeffs();
|
||||
|
||||
void Clear();
|
||||
|
||||
void AddAmbientLight(const RGBColor& color);
|
||||
void AddDirectionalLight(const CVector3D& lightDir,const RGBColor& lightColor);
|
||||
|
||||
void Evaluate(const CVector3D& normal,RGBColor& color) const;
|
||||
|
||||
const RGBColor* GetCoefficients() const { return _data; }
|
||||
|
||||
private:
|
||||
RGBColor _data[9];
|
||||
};
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user