From 2cbc27174c8e19396cf753d8bc7dac3186ac4724 Mon Sep 17 00:00:00 2001 From: notpete Date: Sat, 29 May 2004 20:53:40 +0000 Subject: [PATCH] Moved from terrain directory. This was SVN commit r304. --- source/maths/Bound.cpp | 162 ++++++++ source/maths/Bound.h | 55 +++ source/maths/Matrix3D.cpp | 540 ++++++++++++++++++++++++ source/maths/Matrix3D.h | 123 ++++++ source/maths/Plane.cpp | 138 ++++++ source/maths/Plane.h | 58 +++ source/maths/Quaternion.cpp | 202 +++++++++ source/maths/Quaternion.h | 47 +++ source/maths/Vector3D.cpp | 153 +++++++ source/maths/Vector3D.h | 67 +++ source/maths/Vector4D.h | 110 +++++ source/renderer/AlphaMapCalculator.cpp | 303 ++++++++++++++ source/renderer/AlphaMapCalculator.h | 31 ++ source/renderer/BlendShapes.h | 142 +++++++ source/renderer/PatchRData.cpp | 553 +++++++++++++++++++++++++ source/renderer/PatchRData.h | 91 ++++ source/renderer/SHCoeffs.cpp | 77 ++++ source/renderer/SHCoeffs.h | 36 ++ 18 files changed, 2888 insertions(+) create mode 100755 source/maths/Bound.cpp create mode 100755 source/maths/Bound.h create mode 100755 source/maths/Matrix3D.cpp create mode 100755 source/maths/Matrix3D.h create mode 100755 source/maths/Plane.cpp create mode 100755 source/maths/Plane.h create mode 100755 source/maths/Quaternion.cpp create mode 100755 source/maths/Quaternion.h create mode 100755 source/maths/Vector3D.cpp create mode 100755 source/maths/Vector3D.h create mode 100755 source/maths/Vector4D.h create mode 100755 source/renderer/AlphaMapCalculator.cpp create mode 100755 source/renderer/AlphaMapCalculator.h create mode 100755 source/renderer/BlendShapes.h create mode 100755 source/renderer/PatchRData.cpp create mode 100755 source/renderer/PatchRData.h create mode 100755 source/renderer/SHCoeffs.cpp create mode 100755 source/renderer/SHCoeffs.h diff --git a/source/maths/Bound.cpp b/source/maths/Bound.cpp new file mode 100755 index 0000000000..73aa735b69 --- /dev/null +++ b/source/maths/Bound.cpp @@ -0,0 +1,162 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Name: Bound.cpp +// Author: Rich Cross +// Contact: rich@wildfiregames.com +// +/////////////////////////////////////////////////////////////////////////////// + + +// necessary includes +#include +#include +#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[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[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[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[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 (t1tnear) + tnear = t1; + if (t2tfar || tfar<0) + return false; + } + + if (dir[2]==0 && (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 (t1tnear) + tnear = t1; + if (t2tfar || 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 +#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 diff --git a/source/maths/Plane.cpp b/source/maths/Plane.cpp new file mode 100755 index 0000000000..8496255ca8 --- /dev/null +++ b/source/maths/Plane.cpp @@ -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 +// 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; +} diff --git a/source/maths/Plane.h b/source/maths/Plane.h new file mode 100755 index 0000000000..bf00cef8c2 --- /dev/null +++ b/source/maths/Plane.h @@ -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 +// 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 diff --git a/source/maths/Quaternion.cpp b/source/maths/Quaternion.cpp new file mode 100755 index 0000000000..19ee1781d1 --- /dev/null +++ b/source/maths/Quaternion.cpp @@ -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; +} diff --git a/source/maths/Quaternion.h b/source/maths/Quaternion.h new file mode 100755 index 0000000000..260b27c879 --- /dev/null +++ b/source/maths/Quaternion.h @@ -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 diff --git a/source/maths/Vector3D.cpp b/source/maths/Vector3D.cpp new file mode 100755 index 0000000000..2f3a3b2ca3 --- /dev/null +++ b/source/maths/Vector3D.cpp @@ -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; +} diff --git a/source/maths/Vector3D.h b/source/maths/Vector3D.h new file mode 100755 index 0000000000..8a68a1f6bd --- /dev/null +++ b/source/maths/Vector3D.h @@ -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 +#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 diff --git a/source/maths/Vector4D.h b/source/maths/Vector4D.h new file mode 100755 index 0000000000..081dc225e6 --- /dev/null +++ b/source/maths/Vector4D.h @@ -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 + +/////////////////////////////////////////////////////////////////////////////// +// 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 diff --git a/source/renderer/AlphaMapCalculator.cpp b/source/renderer/AlphaMapCalculator.cpp new file mode 100755 index 0000000000..071b2d4935 --- /dev/null +++ b/source/renderer/AlphaMapCalculator.cpp @@ -0,0 +1,303 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Name: AlphaMapCalculator.cpp +// Author: Rich Cross +// Contact: rich@wildfiregames.com +// +/////////////////////////////////////////////////////////////////////////////// + +#include "AlphaMapCalculator.h" +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// 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 +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 +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 +int LookupBlend(int tableSize,const S* table,const T& shape,unsigned int& flags) +{ + // iterate through known blend shapes + for (int b=0;b +#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 diff --git a/source/renderer/BlendShapes.h b/source/renderer/BlendShapes.h new file mode 100755 index 0000000000..b5f6daa686 --- /dev/null +++ b/source/renderer/BlendShapes.h @@ -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 diff --git a/source/renderer/PatchRData.cpp b/source/renderer/PatchRData.cpp new file mode 100755 index 0000000000..608eb64bba --- /dev/null +++ b/source/renderer/PatchRData.cpp @@ -0,0 +1,553 @@ +#pragma warning(disable:4786) + +#include +#include +#include +#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 splats; + // set of textures used for splats + std::set splatTextures; + + // for each tile in patch .. + for (int j=0;jm_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 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::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 textures; + Handle texgrid[PATCH_SIZE][PATCH_SIZE]; + for (int j=0;jm_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;imax) 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; jCalcPosition(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 +#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 m_Indices; + // list of base splats to apply to this patch + std::vector m_Splats; + // vertices to use for blending transition texture passes + std::vector m_BlendVertices; + // indices into blend vertices for the blend splats + std::vector m_BlendIndices; + // splats used in blend pass + std::vector m_BlendSplats; +}; + + +#endif diff --git a/source/renderer/SHCoeffs.cpp b/source/renderer/SHCoeffs.cpp new file mode 100755 index 0000000000..108db82bd1 --- /dev/null +++ b/source/renderer/SHCoeffs.cpp @@ -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 +} diff --git a/source/renderer/SHCoeffs.h b/source/renderer/SHCoeffs.h new file mode 100755 index 0000000000..a71621bd74 --- /dev/null +++ b/source/renderer/SHCoeffs.h @@ -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