//////////////////////////////////////////////////////////// // edmath.h // // Basic 3D math header file for EDrive, a multiplatform driving simulator. // // Copyright 2004 by Evan Alexander Weaver // // Despite the copyright, this is free software. See edrive.cpp for details. // // Date last modified: 31 May 2004 #ifndef _edrive_edmath_h_ #define _edrive_edmath_h_ #include #include "platform.h" #define PI 3.14159265359 // classes for vector (a triple used to store a point or vector) and // matrix (4x4 used for transformations) // #if ED_DIRECTX_9_GRAPHICS //************************************************ #include // DirectX 9 D3DX library already has vector and matrix classes typedef D3DXMATRIX matrix; typedef D3DXVECTOR3 vector; #else //******************************************************************** //////////////////////////////////////////////////////////////////////// // vector class - stores a point or a vector // class vector { public: float x; float y; float z; vector() { x = y = z = 0; } vector(float x1, float y1, float z1) { x = x1, y = y1; z = z1; } }; // add two vectors inline vector operator+(const vector &a, const vector &b) { return vector(a.x + b.x, a.y + b.y, a.z + b.z); } // subtract two vectors inline vector operator-(const vector &a, const vector &b) { return vector(a.x - b.x, a.y - b.y, a.z - b.z); } inline vector operator-(const vector &a) { return vector(-a.x, -a.y, -a.z); } // scale inline vector operator*(float a, const vector &b) { return vector(a*b.x, a*b.y, a*b.z); } inline vector operator*(const vector &b, float a) { return vector(a*b.x, a*b.y, a*b.z); } //////////////////////////////////////////////////////////////////////// // matrix class - stores a 4x4 matrix in "column major" form, the way // OpenGL likes it // class matrix { public: float data[16]; private: void set(float x11, float x12, float x13, float x14, float x21, float x22, float x23, float x24, float x31, float x32, float x33, float x34, float x41, float x42, float x43, float x44) { data[0] = x11; data[1] = x21; data[2] = x31; data[3] = x41; data[4] = x12; data[5] = x22; data[6] = x32; data[7] = x42; data[8] = x13; data[9] = x23; data[10] = x33; data[11] = x43; data[12] = x14; data[13] = x24; data[14] = x34; data[15] = x44; } public: matrix() {set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);} matrix(float x) {set(x, 0, 0, 0, 0, x, 0, 0, 0, 0, x, 0, 0, 0, 0, 1);} matrix(const vector &v) {set(v.x, 0, 0, 0, 0, v.y, 0, 0, 0, 0, v.z, 0, 0, 0, 0, 1);} matrix(float x11, float x12, float x13, float x14, float x21, float x22, float x23, float x24, float x31, float x32, float x33, float x34, float x41, float x42, float x43, float x44) { set(x11, x12, x13, x14, x21, x22, x23, x24, x31, x32, x33, x34, x41, x42, x43, x44); } }; // 4x4 matrix multiplication inline matrix operator*(const matrix &a, const matrix &b) { return matrix( a.data[0]*b.data[0] + a.data[4]*b.data[1] + a.data[8]*b.data[2] + a.data[12]*b.data[3], a.data[0]*b.data[4] + a.data[4]*b.data[5] + a.data[8]*b.data[6] + a.data[12]*b.data[7], a.data[0]*b.data[8] + a.data[4]*b.data[9] + a.data[8]*b.data[10] + a.data[12]*b.data[11], a.data[0]*b.data[12] + a.data[4]*b.data[13] + a.data[8]*b.data[14] + a.data[12]*b.data[15], a.data[1]*b.data[0] + a.data[5]*b.data[1] + a.data[9]*b.data[2] + a.data[13]*b.data[3], a.data[1]*b.data[4] + a.data[5]*b.data[5] + a.data[9]*b.data[6] + a.data[13]*b.data[7], a.data[1]*b.data[8] + a.data[5]*b.data[9] + a.data[9]*b.data[10] + a.data[13]*b.data[11], a.data[1]*b.data[12] + a.data[5]*b.data[13] + a.data[9]*b.data[14] + a.data[13]*b.data[15], a.data[2]*b.data[0] + a.data[6]*b.data[1] + a.data[10]*b.data[2] + a.data[14]*b.data[3], a.data[2]*b.data[4] + a.data[6]*b.data[5] + a.data[10]*b.data[6] + a.data[14]*b.data[7], a.data[2]*b.data[8] + a.data[6]*b.data[9] + a.data[10]*b.data[10] + a.data[14]*b.data[11], a.data[2]*b.data[12] + a.data[6]*b.data[13] + a.data[10]*b.data[14] + a.data[14]*b.data[15], a.data[3]*b.data[0] + a.data[7]*b.data[1] + a.data[11]*b.data[2] + a.data[15]*b.data[3], a.data[3]*b.data[4] + a.data[7]*b.data[5] + a.data[11]*b.data[6] + a.data[15]*b.data[7], a.data[3]*b.data[8] + a.data[7]*b.data[9] + a.data[11]*b.data[10] + a.data[15]*b.data[11], a.data[3]*b.data[12] + a.data[7]*b.data[13] + a.data[11]*b.data[14] + a.data[15]*b.data[15]); } // 4x4 by 4x1 matrix multiplication inline vector operator*(const matrix &b, const vector &a) { return vector( a.x * b.data[0] + a.y * b.data[4] + a.z * b.data[8] + b.data[12], a.x * b.data[1] + a.y * b.data[5] + a.z * b.data[9] + b.data[13], a.x * b.data[2] + a.y * b.data[6] + a.z * b.data[10] + b.data[14]); } // 1x4 by 4x4 matrix multiplication inline vector operator*(const vector &a, const matrix &b) { return vector( a.x * b.data[0] + a.y * b.data[1] + a.z * b.data[2] + b.data[3], a.x * b.data[4] + a.y * b.data[5] + a.z * b.data[6] + b.data[7], a.x * b.data[8] + a.y * b.data[9] + a.z * b.data[10] + b.data[11]); } #endif //******************************************************************* // Return the cross product of two vectors (perpendicular or "normal") // inline vector cross(const vector &a, const vector &b) { #if ED_DIRECTX_9_GRAPHICS //******************************************** vector rc; D3DXVec3Cross(&rc, &a, &b); return rc; #else //**************************************************************** return vector(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); #endif //*************************************************************** } // Return the normal pointing to the right of the plane determined by two // vectors. In a LHS like DirectX, this is simply the cross product, but in // a RHS like OpenGL it is the negative of the cross product. // inline vector right(const vector &a, const vector &b) { #if ED_OPENGL //******************************************************** return cross(b, a); #else //**************************************************************** return cross(a, b); #endif //*************************************************************** } // Return the dot product of two vectors. If both these vectors happen to be // normalized (length 1), then this is the cosine of the angle between them. // inline float dot(const vector &a, const vector &b) { #if ED_DIRECTX_9_GRAPHICS //******************************************** return D3DXVec3Dot(&a, &b); #else //**************************************************************** return a.x * b.x + a.y * b.y + a.z * b.z; #endif //*************************************************************** } // Return the square of the length of a vector, which is faster than computing // the length and works just as well in certain situations. // inline float length2(const vector &v) { #if ED_DIRECTX_9_GRAPHICS //******************************************** return D3DXVec3LengthSq(&v); #else //**************************************************************** return v.x * v.x + v.y * v.y + v.z * v.z; #endif //*************************************************************** } // Return the length of a vector // inline float length(const vector &v) { #if ED_DIRECTX_9_GRAPHICS //******************************************** return D3DXVec3Length(&v); #else //**************************************************************** return sqrt(length2(v)); #endif //*************************************************************** } // Normalize a vector (i.e. make it length 1) and return a reference to it. // inline vector &normalize(vector &v) { #if ED_DIRECTX_9_GRAPHICS //******************************************** vector newvec; D3DXVec3Normalize(&newvec, &v); return v = newvec; #else //**************************************************************** double len = length(v); if (len != 0) { v.x /= len; v.y /= len; v.z /= len; } return v; #endif //*************************************************************** } // NEEDS CONVERSION TO RH COORDS // return a viewmatrix for view from "viewpoint", looking in the // direction "direction", where "up" points up. //inline matrix viewmatrix(const vector &viewpoint, // const vector &direction, const vector &up) //{ // vector n = direction; // normalized direction // vector u = up * normalize(n); // normalized right // vector v = n * normalize(u); // normalized up // normalize(v); // return matrix( // u.x, v.x, n.x, 0, // u.y, v.y, n.y, 0, // u.z, v.z, n.z, 0, // -dot(u, viewpoint), -dot(v, viewpoint), -dot(n, viewpoint), 1); //} // NEEDS CONVERSION TO RH COORDS // return the projection matrix where "nearz" and "farz" are the near // and far clipping planes, and "fovh" and "fovv" are the horizontal // and vertical field-of-view angles in radians //inline matrix projectionmatrix(float nearz, float farz, // float fovh, float fovv) //{ // float q = farz / (farz - nearz); // float coth = 1/tan(fovh * 0.5), // cotv = 1/tan(fovv * 0.5); // // return matrix( coth, 0, 0, 0, // 0, cotv, 0, 0, // 0, 0, q, -q*nearz, // 0, 0, 1, 0); //} // Return the matrix for rotation about each axis // inline matrix matrotationx(float rad) { #if ED_DIRECTX_9_GRAPHICS //******************************************** matrix m; D3DXMatrixRotationX(&m, rad); return m; #else //**************************************************************** float s = sin(-rad), c = cos(-rad); return matrix( 1, 0, 0, 0, 0, c,-s, 0, 0, s, c, 0, 0, 0, 0, 1); #endif //*************************************************************** } inline matrix matrotationy(float rad) { #if ED_DIRECTX_9_GRAPHICS //******************************************** matrix m; D3DXMatrixRotationY(&m, rad); return m; #else //**************************************************************** float s = sin(-rad), c = cos(-rad); return matrix( c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1); #endif //*************************************************************** } inline matrix matrotationz(float rad) { #if ED_DIRECTX_9_GRAPHICS //******************************************** matrix m; D3DXMatrixRotationZ(&m, rad); return m; #else //**************************************************************** float s = sin(-rad), c = cos(-rad); return matrix( c,-s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); #endif //*************************************************************** } // Return matrix for rotation around an arbitrary axis // inline matrix matrotaxis(float rad, const vector &v1) { #if ED_DIRECTX_9_GRAPHICS //******************************************** matrix m; D3DXMatrixRotationAxis(&m, &v1, rad); return m; #else //**************************************************************** float s = sin(-rad), c = cos(-rad), cc; vector v = v1; cc = 1 - c; normalize(v); return matrix( cc*v.x*v.x + c, cc*v.x*v.y - s*v.z, cc*v.x*v.z + s*v.y, 0, cc*v.x*v.y + s*v.z, cc*v.y*v.y + c, cc*v.y*v.z - s*v.x, 0, cc*v.x*v.z - s*v.y, cc*v.y*v.z + s*v.x, cc*v.z*v.z + c, 0, 0, 0, 0, 1); #endif //*************************************************************** } // Return a translation matrix // inline matrix mattranslate(float x, float y, float z) { #if ED_DIRECTX_9_GRAPHICS //******************************************** matrix m; D3DXMatrixTranslation(&m, x, y, z); return m; #else //**************************************************************** return matrix( 1, 0, 0, -x, 0, 1, 0, -y, 0, 0, 1, -z, 0, 0, 0, 1); #endif //*************************************************************** } inline matrix mattranslate(const vector &v) { return mattranslate(v.x, v.y, v.z); } // Return a scaling matrix inline matrix matscale(float x, float y, float z) { #if ED_DIRECTX_9_GRAPHICS //******************************************** matrix m; D3DXMatrixScaling(&m, x, y, z); return m; #else //**************************************************************** return matrix( x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1); #endif //*************************************************************** } inline matrix matscale(const vector &v) { return matscale(v.x, v.y, v.z); } // Silly macro to wrap around Z coordinates so that the same source coordinates // can be used whether we are working in a left handed system like DirectX // or a right handed system like OpenGL. In EDrive, source coordinates are // created for a left handed system. // #if ED_DIRECTX_9_GRAPHICS //************************************************ #define Z(x) (x) #else //******************************************************************** #define Z(x) (-(x)) #endif //******************************************************************* #endif