Matrix.h
上传用户:ghyvgy
上传日期:2009-05-26
资源大小:547k
文件大小:42k
源码类别:

其他游戏

开发平台:

Python

  1. /*
  2. s_p_oneil@hotmail.com
  3. Copyright (c) 2000, Sean O'Neil
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions are met:
  7. * Redistributions of source code must retain the above copyright notice,
  8.   this list of conditions and the following disclaimer.
  9. * Redistributions in binary form must reproduce the above copyright notice,
  10.   this list of conditions and the following disclaimer in the documentation
  11.   and/or other materials provided with the distribution.
  12. * Neither the name of this project nor the names of its contributors
  13.   may be used to endorse or promote products derived from this software
  14.   without specific prior written permission.
  15. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  19. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25. POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #ifndef __Matrix_h__
  28. #define __Matrix_h__
  29. #include "Noise.h" // Has some useful defines and inline functions
  30. class CMatrix;
  31. class CQuaternion;
  32. class C3DObject;
  33. /*******************************************************************************
  34. * Template Class: TVector
  35. ********************************************************************************
  36. * This template class implements a simple 3D vector with x, y, and z coordinates.
  37. * Several functions and operators are defined to make working with vectors easier,
  38. * and because it's templatized, any numeric type can be used with it. Macros are
  39. * defined for the most common types.
  40. *******************************************************************************/
  41. #define CVector TVector<float>
  42. #define CDoubleVector TVector<double>
  43. #define CIntVector TVector<int>
  44. #define CByteVector TVector<unsigned char>
  45. template <class T> class TVector
  46. {
  47. public:
  48. T x, y, z;
  49. // Constructors
  50. TVector() {}
  51. TVector(const T a, const T b, const T c) { x = a; y = b; z = c; }
  52. TVector(const T t) { *this = t; }
  53. TVector(const T *pt) { *this = pt; }
  54. TVector(const TVector<T> &v) { *this = v; }
  55. // Casting and unary operators
  56. operator TVector<float>() { return TVector<float>((float)x, (float)y, (float)z); }
  57. operator TVector<double>() { return TVector<double>((double)x, (double)y, (double)z); }
  58. operator T*() { return &x; }
  59. T &operator[](const int n) { return (&x)[n]; }
  60. operator const T*() const { return &x; }
  61. T operator[](const int n) const { return (&x)[n]; }
  62. TVector<T> operator-() const { return TVector<T>(-x, -y, -z); }
  63. // Equal and comparison operators
  64. void operator=(const T t) { x = y = z = t; }
  65. void operator=(const T *pt) { x = pt[0]; y = pt[1]; z = pt[2]; }
  66. void operator=(const TVector<T> &v) { x = v.x; y = v.y; z = v.z; }
  67. bool operator==(TVector<T> &v) const { return (Abs(x - v.x) <= (T)0.001f && Abs(y - v.y) <= 0.001f && Abs(z - v.z) <= 0.001f); }
  68. bool operator!=(TVector<T> &v) const { return !(*this == v); }
  69. // Arithmetic operators (vector with scalar)
  70. TVector<T> operator+(const T t) const { return TVector<T>(x+t, y+t, z+t); }
  71. TVector<T> operator-(const T t) const { return TVector<T>(x-t, y-t, z-t); }
  72. TVector<T> operator*(const T t) const { return TVector<T>(x*t, y*t, z*t); }
  73. TVector<T> operator/(const T t) const { return TVector<T>(x/t, y/t, z/t); }
  74. void operator+=(const T t) { x += t; y += t; z += t; }
  75. void operator-=(const T t) { x -= t; y -= t; z -= t; }
  76. void operator*=(const T t) { x *= t; y *= t; z *= t; }
  77. void operator/=(const T t) { x /= t; y /= t; z /= t; }
  78. // Arithmetic operators (vector with vector)
  79. TVector<T> operator+(const TVector<T> &v) const { return TVector<T>(x+v.x, y+v.y, z+v.z); }
  80. TVector<T> operator-(const TVector<T> &v) const { return TVector<T>(x-v.x, y-v.y, z-v.z); }
  81. TVector<T> operator*(const TVector<T> &v) const { return TVector<T>(x*v.x, y*v.y, z*v.z); }
  82. TVector<T> operator/(const TVector<T> &v) const { return TVector<T>(x/v.x, y/v.y, z/v.z); }
  83. void operator+=(const TVector<T> &v) { x += v.x; y += v.y; z += v.z; }
  84. void operator-=(const TVector<T> &v) { x -= v.x; y -= v.y; z -= v.z; }
  85. void operator*=(const TVector<T> &v) { x *= v.x; y *= v.y; z *= v.z; }
  86. void operator/=(const TVector<T> &v) { x /= v.x; y /= v.y; z /= v.z; }
  87. // Dot and cross product operators
  88. T operator|(const TVector<T> &v) const { return x*v.x + y*v.y + z*v.z; }
  89. TVector<T> operator^(const TVector<T> &v) const { return TVector<T>(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x); }
  90. void operator^=(const TVector<T> &v) { *this = *this ^ v; }
  91. // Magnitude/distance methods
  92. T MagnitudeSquared() const { return x*x + y*y + z*z; }
  93. T Magnitude() const { return (T)sqrt(MagnitudeSquared()); }
  94. T DistanceSquared(const TVector<T> &v) const{ return (*this - v).MagnitudeSquared(); }
  95. T Distance(const TVector<T> &v) const { return (*this - v).Magnitude(); }
  96. TVector<T> Midpoint(const TVector<T> &v) const { return CVector((*this - v) / 2 + v); }
  97. TVector<T> Average(const TVector<T> &v) const { return CVector((*this + v) / 2); }
  98. // Advanced methods (should only be used with float or double types)
  99. void Normalize() { *this /= Magnitude(); }
  100. double Angle(const TVector<T> &v) const { return acos(*this | v); }
  101. TVector<T> Reflect(const TVector<T> &n) const
  102. {
  103. T t = (T)Magnitude();
  104. TVector<T> v = *this / t;
  105. return (v - n * (2 * (v | n))) * t;
  106. }
  107. TVector<T> Rotate(const T tAngle, const CVector &n) const
  108. {
  109. T tCos = (T)cos(tAngle);
  110. T tSin = (T)sin(tAngle);
  111. return TVector<T>(*this * tCos + ((n * *this) * (1 - tCos)) * n + (*this ^ n) * tSin);
  112. }
  113. };
  114. // Returns the normal vector of two vectors (the normalized cross product)
  115. template <class T> inline TVector<T> NormalVector(const TVector<T> &v1, const TVector<T> &v2)
  116. {
  117. TVector<T> v = v1 ^ v2;
  118. v.Normalize();
  119. return v;
  120. }
  121. // Returns the normal vector of a triangle or 3 points on a plane (assumes counter-clockwise orientation)
  122. template <class T> inline TVector<T> NormalVector(const TVector<T> &p1, const TVector<T> &p2, const TVector<T> &p3)
  123. {
  124. return NormalVector(p2-p1, p3-p1);
  125. }
  126. // Returns the direction vector between two points
  127. template <class T> inline TVector<T> DirectionVector(const TVector<T> &p1, const TVector<T> &p2)
  128. {
  129. TVector<T> v = p2 - p1;
  130. v.Normalize();
  131. return v;
  132. }
  133. /*******************************************************************************
  134. * Template Class: TVector4
  135. ********************************************************************************
  136. * This template class implements a simple 4D vector with x, y, z, and w
  137. * coordinates. Like TVector, it is templatized and macros are defined for the
  138. * most common types.
  139. *******************************************************************************/
  140. #define CVector4 TVector4<float>
  141. #define CDoubleVector4 TVector4<double>
  142. #define CIntVector4 TVector4<int>
  143. #define CByteVector4 TVector4<unsigned char>
  144. template <class T> class TVector4
  145. {
  146. public:
  147. T x, y, z, w;
  148. // Constructors
  149. TVector4() {}
  150. TVector4(const T a, const T b, const T c, const T d) { x = a; y = b; z = c; w = d; }
  151. TVector4(const T t) { *this = t; }
  152. TVector4(const T *pt) { *this = pt; }
  153. TVector4(const TVector<T> &v) { *this = v; }
  154. TVector4(const TVector4<T> &v) { *this = v; }
  155. // Casting and unary operators
  156. operator T*() { return &x; }
  157. T &operator[](const int n) { return (&x)[n]; }
  158. operator const T*() const { return &x; }
  159. T operator[](const int n) const { return (&x)[n]; }
  160. TVector4<T> operator-() const { return TVector4<T>(-x, -y, -z, -w); }
  161. // Equal and comparison operators
  162. void operator=(const T t) { x = y = z = w = t; }
  163. void operator=(const T *pt) { x = pt[0]; y = pt[1]; z = pt[2]; w = pt[3]; }
  164. void operator=(const TVector<T> &v) { x = v.x; y = v.y; z = v.z; w = 0; }
  165. void operator=(const TVector4<T> &v) { x = v.x; y = v.y; z = v.z; w = v.w; }
  166. bool operator==(TVector4<T> &v) const { return (Abs(x - v.x) <= (T)DELTA && Abs(y - v.y) <= (T)DELTA && Abs(z - v.z) <= (T)DELTA && Abs(w - v.w) <= (T)DELTA); }
  167. bool operator!=(TVector4<T> &v) const { return !(*this == v); }
  168. // Arithmetic operators (vector with scalar)
  169. TVector4<T> operator+(const T t) const { return TVector4<T>(x+t, y+t, z+t, w+t); }
  170. TVector4<T> operator-(const T t) const { return TVector4<T>(x-t, y-t, z-t, w-t); }
  171. TVector4<T> operator*(const T t) const { return TVector4<T>(x*t, y*t, z*t, w*t); }
  172. TVector4<T> operator/(const T t) const { return TVector4<T>(x/t, y/t, z/t, w/t); }
  173. void operator+=(const T t) { x += t; y += t; z += t; w += t; }
  174. void operator-=(const T t) { x -= t; y -= t; z -= t; w -= t; }
  175. void operator*=(const T t) { x *= t; y *= t; z *= t; w *= t; }
  176. void operator/=(const T t) { x /= t; y /= t; z /= t; w /= t; }
  177. // Arithmetic operators (vector with vector)
  178. TVector4<T> operator+(const TVector4<T> &v) const { return TVector4<T>(x+v.x, y+v.y, z+v.z, w+v.w); }
  179. TVector4<T> operator-(const TVector4<T> &v) const { return TVector4<T>(x-v.x, y-v.y, z-v.z, w-v.w); }
  180. TVector4<T> operator*(const TVector4<T> &v) const { return TVector4<T>(x*v.x, y*v.y, z*v.z, w*v.w); }
  181. TVector4<T> operator/(const TVector4<T> &v) const { return TVector4<T>(x/v.x, y/v.y, z/v.z, w/v.w); }
  182. void operator+=(const TVector4<T> &v) { x += v.x; y += v.y; z += v.z; w += v.w; }
  183. void operator-=(const TVector4<T> &v) { x -= v.x; y -= v.y; z -= v.z; w -= v.w; }
  184. void operator*=(const TVector4<T> &v) { x *= v.x; y *= v.y; z *= v.z; w *= v.w; }
  185. void operator/=(const TVector4<T> &v) { x /= v.x; y /= v.y; z /= v.z; w /= v.w; }
  186. // Magnitude/normalize methods
  187. T MagnitudeSquared() const { return x*x + y*y + z*z + w*w; }
  188. T Magnitude() const { return (T)sqrt(MagnitudeSquared()); }
  189. void Normalize() { *this /= Magnitude(); }
  190. };
  191. /*******************************************************************************
  192. * Class: CQuaternion
  193. ********************************************************************************
  194. * This class implements a 4D quaternion. Several functions and operators are
  195. * defined to make working with quaternions easier. Quaternions are often used to
  196. * represent rotations, and have a number of advantages over other constructs.
  197. * Their main disadvantage is that they are unintuitive.
  198. *
  199. * Note: This class is not templatized because integral data types don't make sense
  200. *       and there's no need for double-precision.
  201. *******************************************************************************/
  202. class CQuaternion
  203. {
  204. public:
  205. float x, y, z, w;
  206. // Constructors
  207. CQuaternion() {}
  208. CQuaternion(const float a, const float b, const float c, const float d) { x = a; y = b; z = c; w = d; }
  209. CQuaternion(const CVector &v, const float f){ SetAxisAngle(v, f); }
  210. CQuaternion(const CVector &v) { *this = v; }
  211. CQuaternion(const CQuaternion &q) { *this = q; }
  212. CQuaternion(const CMatrix &m) { *this = m; }
  213. CQuaternion(const float *p) { *this = p; }
  214. // Casting and unary operators
  215. operator float*() { return &x; }
  216. float &operator[](const int n) { return (&x)[n]; }
  217. operator const float*() const { return &x; }
  218. float operator[](const int n) const { return (&x)[n]; }
  219. CQuaternion operator-() const { return CQuaternion(-x, -y, -z, -w); }
  220. // Equal and comparison operators
  221. void operator=(const CVector &v) { x = v.x; y = v.y; z = v.z; w = 0; }
  222. void operator=(const CQuaternion &q) { x = q.x; y = q.y; z = q.z; w = q.w; }
  223. void operator=(const CMatrix &m);
  224. void operator=(const float *p) { x = p[0]; y = p[1]; z = p[2]; w = p[3]; }
  225. // Arithmetic operators (quaternion and scalar)
  226. CQuaternion operator+(const float f) const { return CQuaternion(x+f, y+f, z+f, w+f); }
  227. CQuaternion operator-(const float f) const { return CQuaternion(x-f, y-f, z-f, w-f); }
  228. CQuaternion operator*(const float f) const { return CQuaternion(x*f, y*f, z*f, w*f); }
  229. CQuaternion operator/(const float f) const { return CQuaternion(x/f, y/f, z/f, w/f); }
  230. void operator+=(const float f) { x+=f; y+=f; z+=f; w+=f; }
  231. void operator-=(const float f) { x-=f; y-=f; z-=f; w-=f; }
  232. void operator*=(const float f) { x*=f; y*=f; z*=f; w*=f; }
  233. void operator/=(const float f) { x/=f; y/=f; z/=f; w/=f; }
  234. // Arithmetic operators (quaternion and quaternion)
  235. CQuaternion operator+(const CQuaternion &q) const { return CQuaternion(x+q.x, y+q.y, z+q.z, w+q.w); }
  236. CQuaternion operator-(const CQuaternion &q) const { return CQuaternion(x-q.x, y-q.y, z-q.z, w-q.w); }
  237. CQuaternion operator*(const CQuaternion &q) const; // Multiplying quaternions is a special operation
  238. void operator+=(const CQuaternion &q) { x+=q.x; y+=q.y; z+=q.z; w+=q.w; }
  239. void operator-=(const CQuaternion &q) { x-=q.x; y-=q.y; z-=q.z; w-=q.w; }
  240. void operator*=(const CQuaternion &q) { *this = *this * q; }
  241. // Magnitude/normalize methods
  242. float MagnitudeSquared() const { return x*x + y*y + z*z + w*w; }
  243. float Magnitude() const { return sqrtf(MagnitudeSquared()); }
  244. void Normalize() { *this /= Magnitude(); }
  245. // Advanced quaternion methods
  246. CQuaternion Conjugate() const { return CQuaternion(-x, -y, -z, w); }
  247. CQuaternion Inverse() const { return Conjugate() / MagnitudeSquared(); }
  248. CQuaternion UnitInverse() const { return Conjugate(); }
  249. CVector RotateVector(const CVector &v) const { return (*this * CQuaternion(v) * UnitInverse()); }
  250. void SetAxisAngle(const CVector &vAxis, const float fAngle)
  251. {
  252. // 4 muls, 2 trig function calls
  253. float f = fAngle * 0.5f;
  254. *this = vAxis * sinf(f);
  255. w = cosf(f);
  256. }
  257. void GetAxisAngle(CVector &vAxis, float &fAngle) const
  258. {
  259. // 4 muls, 1 div, 2 trig function calls
  260. fAngle = acosf(w);
  261. vAxis = *this / sinf(fAngle);
  262. fAngle *= 2.0f;
  263. }
  264. void Rotate(const CQuaternion &q) { *this = q * *this; }
  265. void Rotate(const CVector &vAxis, const float fAngle)
  266. {
  267. CQuaternion q;
  268. q.SetAxisAngle(vAxis, fAngle);
  269. Rotate(q);
  270. }
  271. CVector GetViewAxis() const
  272. {
  273. // 6 muls, 7 adds
  274. float x2 = x + x, y2 = y + y, z2 = z + z;
  275. float xx = x * x2, xz = x * z2;
  276. float yy = y * y2, yz = y * z2;
  277. float wx = w * x2, wy = w * y2;
  278. return -CVector(xz+wy, yz-wx, 1-(xx+yy));
  279. }
  280. CVector GetUpAxis() const
  281. {
  282. // 6 muls, 7 adds
  283. float x2 = x + x, y2 = y + y, z2 = z + z;
  284. float xx = x * x2, xy = x * y2;
  285. float yz = y * z2, zz = z * z2;
  286. float wx = w * x2, wz = w * z2;
  287. return CVector(xy-wz, 1-(xx+zz), yz+wx);
  288. }
  289. CVector GetRightAxis() const
  290. {
  291. // 6 muls, 7 adds
  292. float x2 = x + x, y2 = y + y, z2 = z + z;
  293. float xy = x * y2, xz = x * z2;
  294. float yy = y * y2, zz = z * z2;
  295. float wy = w * y2, wz = w * z2;
  296. return CVector(1-(yy+zz), xy+wz, xz-wy);
  297. }
  298. };
  299. extern CQuaternion Slerp(const CQuaternion &q1, const CQuaternion &q2, const float t);
  300. /*******************************************************************************
  301. * Class: CMatrix
  302. ********************************************************************************
  303. * This class implements a 4x4 matrix. Several functions and operators are
  304. * defined to make working with matrices easier. The values are kept in column-
  305. * major order to make it easier to use with OpenGL. For performance reasons,
  306. * most of the functions assume that all matrices are orthogonal, which means the
  307. * bottom row is [ 0 0 0 1 ]. Since I plan to use the GL_PROJECTION matrix to
  308. * handle the projection matrix, I should never need to use any other kind of
  309. * matrix, and I get a decent performance boost by ignoring the bottom row.
  310. *
  311. * Note: This class is not templatized because integral data types don't make sense
  312. *       and there's no need for double-precision.
  313. *******************************************************************************/
  314. class CMatrix
  315. {
  316. public:
  317. // This class uses column-major order, as used by OpenGL
  318. // Here are the ways in which the matrix values can be accessed:
  319. // | f11 f21 f31 f41 |   | f1[0] f1[4] f1[8]  f1[12] |   | f2[0][0] f2[1][0] f2[2][0] f2[3][0] |
  320. // | f12 f22 f32 f42 |   | f1[1] f1[5] f1[9]  f1[13] |   | f2[0][1] f2[1][1] f2[2][1] f2[3][1] |
  321. // | f13 f23 f33 f43 | = | f1[2] f1[6] f1[10] f1[14] | = | f2[0][2] f2[1][2] f2[2][2] f2[3][2] |
  322. // | f14 f24 f34 f44 |   | f1[3] f1[7] f1[11] f1[15] |   | f2[0][3] f2[1][3] f2[2][3] f2[3][3] |
  323. union
  324. {
  325. struct { float f11, f12, f13, f14, f21, f22, f23, f24, f31, f32, f33, f34, f41, f42, f43, f44; };
  326. float f1[16];
  327. float f2[4][4];
  328. };
  329. CMatrix() {}
  330. CMatrix(const float f) { *this = f; }
  331. CMatrix(const float *pf) { *this = pf; }
  332. CMatrix(const CQuaternion &q) { *this = q; }
  333. // Init functions
  334. void ZeroMatrix()
  335. {
  336. f11 = f12 = f13 = f14 = f21 = f22 = f23 = f24 = f31 = f32 = f33 = f34 = f41 = f42 = f43 = f44 = 0;
  337. }
  338. void IdentityMatrix()
  339. {
  340. f12 = f13 = f14 = f21 = f23 = f24 = f31 = f32 = f34 = f41 = f42 = f43 = 0;
  341. f11 = f22 = f33 = f44 = 1;
  342. }
  343. operator float*() { return f1; }
  344. float &operator[](const int n) { return f1[n]; }
  345. float &operator()(const int i, const int j) { return f2[i][j]; }
  346. operator const float*() const { return f1; }
  347. float operator[](const int n) const { return f1[n]; }
  348. float operator()(const int i, const int j) const{ return f2[i][j]; }
  349. void operator=(const float f) { for(register int i=0; i<16; i++) f1[i] = f; }
  350. void operator=(const float *pf) { for(register int i=0; i<16; i++) f1[i] = pf[i]; }
  351. void operator=(const CQuaternion &q);
  352. CMatrix operator*(const CMatrix &m) const;
  353. void operator*=(const CMatrix &m) { *this = *this * m; }
  354. CVector operator*(const CVector &v) const { return TransformVector(v); }
  355. CVector TransformVector(const CVector &v) const
  356. {
  357. // 9 muls, 9 adds
  358. // | f11 f21 f31 f41 |   | v.x |   | f11*v.x+f21*v.y+f31*v.z+f41 |
  359. // | f12 f22 f32 f42 |   | v.y |   | f12*v.x+f22*v.y+f32*v.z+f42 |
  360. // | f13 f23 f33 f43 | * | v.z | = | f13*v.x+f23*v.y+f33*v.z+f43 |
  361. // | 0   0   0   1   |   | 1   |   | 1                           |
  362. return CVector((f11*v.x+f21*v.y+f31*v.z+f41),
  363.    (f12*v.x+f22*v.y+f32*v.z+f42),
  364.    (f13*v.x+f23*v.y+f33*v.z+f43));
  365. }
  366. CVector TransformNormal(const CVector &v) const
  367. {
  368. // 9 muls, 6 adds
  369. // (Transpose rotation vectors, ignore position)
  370. // | f11 f12 f13 0 |   | v.x |   | f11*v.x+f12*v.y+f13*v.z |
  371. // | f21 f22 f23 0 |   | v.y |   | f21*v.x+f22*v.y+f23*v.z |
  372. // | f31 f32 f33 0 | * | v.z | = | f31*v.x+f32*v.y+f33*v.z |
  373. // | 0   0   0   1 |   | 1   |   | 1                       |
  374. return CVector((f11*v.x+f12*v.y+f13*v.z),
  375.    (f21*v.x+f22*v.y+f23*v.z),
  376.    (f31*v.x+f32*v.y+f33*v.z));
  377. }
  378. // Translate functions
  379. void TranslateMatrix(const float x, const float y, const float z)
  380. {
  381. // | 1  0  0  x |
  382. // | 0  1  0  y |
  383. // | 0  0  1  z |
  384. // | 0  0  0  1 |
  385. f12 = f13 = f14 = f21 = f23 = f24 = f31 = f32 = f34 = 0;
  386. f11 = f22 = f33 = f44 = 1;
  387. f41 = x; f42 = y; f43 = z;
  388. }
  389. void TranslateMatrix(const float *pf) { TranslateMatrix(pf[0], pf[1], pf[2]); }
  390. void Translate(const float x, const float y, const float z)
  391. {
  392. // 9 muls, 9 adds
  393. // | f11 f21 f31 f41 |   | 1  0  0  x |   | f11 f21 f31 f11*x+f21*y+f31*z+f41 |
  394. // | f12 f22 f32 f42 |   | 0  1  0  y |   | f12 f22 f32 f12*x+f22*y+f32*z+f42 |
  395. // | f13 f23 f33 f43 | * | 0  0  1  z | = | f13 f23 f33 f13*x+f23*y+f33*z+f43 |
  396. // | 0   0   0   1   |   | 0  0  0  1 |   | 0   0   0   1                     |
  397. f41 = f11*x+f21*y+f31*z+f41;
  398. f42 = f12*x+f22*y+f32*z+f42;
  399. f43 = f13*x+f23*y+f33*z+f43;
  400. }
  401. void Translate(const float *pf) { Translate(pf[0], pf[1], pf[2]); }
  402. // Scale functions
  403. void ScaleMatrix(const float x, const float y, const float z)
  404. {
  405. // | x  0  0  0 |
  406. // | 0  y  0  0 |
  407. // | 0  0  z  0 |
  408. // | 0  0  0  1 |
  409. f12 = f13 = f14 = f21 = f23 = f24 = f31 = f32 = f34 = f41 = f42 = f43 = 0;
  410. f11 = x; f22 = y; f33 = z; f44 = 1;
  411. }
  412. void ScaleMatrix(const float *pf) { ScaleMatrix(pf[0], pf[1], pf[2]); }
  413. void Scale(const float x, const float y, const float z)
  414. {
  415. // 9 muls
  416. // | f11 f21 f31 f41 |   | x  0  0  0 |   | f11*x f21*y f31*z f41 |
  417. // | f12 f22 f32 f42 |   | 0  y  0  0 |   | f12*x f22*y f32*z f42 |
  418. // | f13 f23 f33 f43 | * | 0  0  z  0 | = | f13*x f23*y f33*z f43 |
  419. // | 0   0   0   1   |   | 0  0  0  1 |   | 0     0     0     1   |
  420. f11 *= x; f21 *= y; f31 *= z;
  421. f12 *= x; f22 *= y; f32 *= z;
  422. f13 *= x; f23 *= y; f33 *= z;
  423. }
  424. void Scale(const float *pf) { Scale(pf[0], pf[1], pf[2]); }
  425. // Rotate functions
  426. void RotateXMatrix(const float fRadians)
  427. {
  428. // | 1 0    0     0 |
  429. // | 0 fCos -fSin 0 |
  430. // | 0 fSin fCos  0 |
  431. // | 0 0    0     1 |
  432. f12 = f13 = f14 = f21 = f24 = f31 = f34 = f41 = f42 = f43 = 0;
  433. f11 = f44 = 1;
  434. float fCos = cosf(fRadians);
  435. float fSin = sinf(fRadians);
  436. f22 = f33 = fCos;
  437. f23 = fSin;
  438. f32 = -fSin;
  439. }
  440. void RotateX(const float fRadians)
  441. {
  442. // 12 muls, 6 adds, 2 trig function calls
  443. // | f11 f21 f31 f41 |   | 1 0    0     0 |   | f11 f21*fCos+f31*fSin f31*fCos-f21*fSin f41 |
  444. // | f12 f22 f32 f42 |   | 0 fCos -fSin 0 |   | f12 f22*fCos+f32*fSin f32*fCos-f22*fSin f42 |
  445. // | f13 f23 f33 f43 | * | 0 fSin fCos  0 | = | f13 f23*fCos+f33*fSin f33*fCos-f23*fSin f43 |
  446. // | 0   0   0   1   |   | 0 0    0     1 |   | 0   0                 0                 1   |
  447. float fTemp, fCos, fSin;
  448. fCos = cosf(fRadians);
  449. fSin = sinf(fRadians);
  450. fTemp = f21*fCos+f31*fSin;
  451. f31 = f31*fCos-f21*fSin;
  452. f21 = fTemp;
  453. fTemp = f22*fCos+f32*fSin;
  454. f32 = f32*fCos-f22*fSin;
  455. f22 = fTemp;
  456. fTemp = f23*fCos+f33*fSin;
  457. f33 = f33*fCos-f23*fSin;
  458. f23 = fTemp;
  459. }
  460. void RotateYMatrix(const float fRadians)
  461. {
  462. // | fCos  0 fSin  0 |
  463. // | 0     1 0     0 |
  464. // | -fSin 0 fCos  0 |
  465. // | 0     0 0     1 |
  466. f12 = f14 = f21 = f23 = f24 = f32 = f34 = f41 = f42 = f43 = 0;
  467. f22 = f44 = 1;
  468. float fCos = cosf(fRadians);
  469. float fSin = sinf(fRadians);
  470. f11 = f33 = fCos;
  471. f13 = -fSin;
  472. f31 = fSin;
  473. }
  474. void RotateY(const float fRadians)
  475. {
  476. // 12 muls, 6 adds, 2 trig function calls
  477. // | f11 f21 f31 f41 |   | fCos  0 fSin  0 |   | f11*fCos-f31*fSin f21 f11*fSin+f31*fCos f41 |
  478. // | f12 f22 f32 f42 |   | 0     1 0     0 |   | f12*fCos-f32*fSin f22 f12*fSin+f32*fCos f42 |
  479. // | f13 f23 f33 f43 | * | -fSin 0 fCos  0 | = | f13*fCos-f33*fSin f23 f13*fSin+f33*fCos f43 |
  480. // | 0   0   0   1   |   | 0     0 0     1 |   | 0                 0   0                 1   |
  481. float fTemp, fCos, fSin;
  482. fCos = cosf(fRadians);
  483. fSin = sinf(fRadians);
  484. fTemp = f11*fCos-f31*fSin;
  485. f31 = f11*fSin+f31*fCos;
  486. f11 = fTemp;
  487. fTemp = f12*fCos-f32*fSin;
  488. f32 = f12*fSin+f32*fCos;
  489. f12 = fTemp;
  490. fTemp = f13*fCos-f33*fSin;
  491. f33 = f13*fSin+f33*fCos;
  492. f13 = fTemp;
  493. }
  494. void RotateZMatrix(const float fRadians)
  495. {
  496. // | fCos -fSin 0 0 |
  497. // | fSin fCos  0 0 |
  498. // | 0    0     1 0 |
  499. // | 0    0     0 1 |
  500. f13 = f14 = f23 = f24 = f31 = f32 = f34 = f41 = f42 = f43 = 0;
  501. f33 = f44 = 1;
  502. float fCos = cosf(fRadians);
  503. float fSin = sinf(fRadians);
  504. f11 = f22 = fCos;
  505. f12 = fSin;
  506. f21 = -fSin;
  507. }
  508. void RotateZ(const float fRadians)
  509. {
  510. // 12 muls, 6 adds, 2 trig function calls
  511. // | f11 f21 f31 f41 |   | fCos -fSin 0 0 |   | f11*fCos+f21*fSin f21*fCos-f11*fSin f31 f41 |
  512. // | f12 f22 f32 f42 |   | fSin fCos  0 0 |   | f12*fCos+f22*fSin f22*fCos-f12*fSin f32 f42 |
  513. // | f13 f23 f33 f43 | * | 0    0     1 0 | = | f13*fCos+f23*fSin f23*fCos-f13*fSin f33 f43 |
  514. // | 0   0   0   1   |   | 0    0     0 1 |   | 0                 0                 0   1   |
  515. float fTemp, fCos, fSin;
  516. fCos = cosf(fRadians);
  517. fSin = sinf(fRadians);
  518. fTemp = f11*fCos+f21*fSin;
  519. f21 = f21*fCos-f11*fSin;
  520. f11 = fTemp;
  521. fTemp = f12*fCos+f22*fSin;
  522. f22 = f22*fCos-f12*fSin;
  523. f12 = fTemp;
  524. fTemp = f13*fCos+f23*fSin;
  525. f23 = f23*fCos-f13*fSin;
  526. f13 = fTemp;
  527. }
  528. void RotateMatrix(const CVector &v, const float f)
  529. {
  530. // 15 muls, 10 adds, 2 trig function calls
  531. float fCos = cosf(f);
  532. CVector vCos = v * (1 - fCos);
  533. CVector vSin = v * sinf(f);
  534. f14 = f24 = f34 = f41 = f42 = f43 = 0;
  535. f44 = 1;
  536. f11 = (v.x * vCos.x) + fCos;
  537. f21 = (v.x * vCos.y) - (vSin.z);
  538. f31 = (v.x * vCos.z) + (vSin.y);
  539. f12 = (v.y * vCos.x) + (vSin.z);
  540. f22 = (v.y * vCos.y) + fCos;
  541. f32 = (v.y * vCos.z) - (vSin.x);
  542. f13 = (v.z * vCos.x) - (vSin.y);
  543. f32 = (v.z * vCos.y) + (vSin.x);
  544. f33 = (v.z * vCos.z) + fCos;
  545. }
  546. void Rotate(const CVector &v, const float f)
  547. {
  548. // 51 muls, 37 adds, 2 trig function calls
  549. CMatrix mat;
  550. mat.RotateMatrix(v, f);
  551. *this *= mat;
  552. }
  553. void ModelMatrix(const CQuaternion &q, const CVector &vFrom)
  554. {
  555. *this = q;
  556. f41 = vFrom.x;
  557. f42 = vFrom.y;
  558. f43 = vFrom.z;
  559. }
  560. void ModelMatrix(const CVector &vFrom, const CVector &vView, const CVector &vUp, const CVector &vRight)
  561. {
  562. f11 = vRight.x; f21 = vUp.x; f31 = -vView.x; f41 = vFrom.x;
  563. f12 = vRight.y; f22 = vUp.y; f32 = -vView.y; f42 = vFrom.y;
  564. f13 = vRight.z; f23 = vUp.z; f33 = -vView.z; f43 = vFrom.z;
  565. f14 = 0; f24 = 0; f34 = 0; f44 = 1;
  566. }
  567. void ModelMatrix(const CVector &vFrom, const CVector &vAt, const CVector &vUp)
  568. {
  569. CVector vView = vAt - vFrom;
  570. vView.Normalize();
  571. CVector vRight = vView ^ vUp;
  572. vRight.Normalize();
  573. CVector vTrueUp = vRight ^ vView;
  574. vTrueUp.Normalize();
  575. ModelMatrix(vFrom, vView, vTrueUp, vRight);
  576. }
  577. void ViewMatrix(const CQuaternion &q, const CVector &vFrom)
  578. {
  579. *this = q;
  580. Transpose();
  581. f41 = -(vFrom.x*f11 + vFrom.y*f21 + vFrom.z*f31);
  582. f42 = -(vFrom.x*f12 + vFrom.y*f22 + vFrom.z*f32);
  583. f43 = -(vFrom.x*f13 + vFrom.y*f23 + vFrom.z*f33);
  584. }
  585. void ViewMatrix(const CVector &vFrom, const CVector &vView, const CVector &vUp, const CVector &vRight)
  586. {
  587. // 9 muls, 9 adds
  588. f11 = vRight.x; f21 = vRight.y; f31 = vRight.z; f41 = -(vFrom | vRight);
  589. f12 = vUp.x; f22 = vUp.y; f32 = vUp.z; f42 = -(vFrom | vUp);
  590. f13 = -vView.x; f23 = -vView.y; f33 = -vView.z; f43 = -(vFrom | -vView);
  591. f14 = 0; f24 = 0; f34 = 0; f44 = 1;
  592. }
  593. void ViewMatrix(const CVector &vFrom, const CVector &vAt, const CVector &vUp)
  594. {
  595. CVector vView = vAt - vFrom;
  596. vView.Normalize();
  597. CVector vRight = vView ^ vUp;
  598. vRight.Normalize();
  599. CVector vTrueUp = vRight ^ vView;
  600. vTrueUp.Normalize();
  601. ViewMatrix(vFrom, vView, vTrueUp, vRight);
  602. }
  603. void ProjectionMatrix(const float fNear, const float fFar, const float fFOV, const float fAspect)
  604. {
  605. // 2 muls, 3 divs, 2 adds, 1 trig function call
  606. float h = 1.0f / tanf(DEGTORAD(fFOV * 0.5f));
  607. float Q = fFar / (fFar - fNear);
  608. f12 = f13 = f14 = f21 = f23 = f24 = f31 = f32 = f41 = f42 = f44 = 0;
  609. f11 = h / fAspect;
  610. f22 = h;
  611. f33 = Q;
  612. f34 = 1;
  613. f43 = -Q*fNear;
  614. }
  615. // For orthogonal matrices, I belive this also gives you the inverse.
  616. void Transpose()
  617. {
  618. float f;
  619. SWAP(f12, f21, f);
  620. SWAP(f13, f31, f);
  621. SWAP(f14, f41, f);
  622. SWAP(f23, f32, f);
  623. SWAP(f24, f42, f);
  624. SWAP(f34, f43, f);
  625. }
  626. };
  627. class CRay
  628. {
  629. public:
  630. CDoubleVector m_vOrigin;
  631. CDoubleVector m_vDirection;
  632. CRay() {}
  633. CRay(CDoubleVector p1, CDoubleVector p2) { Init(p1, p2); }
  634. void Init(CDoubleVector p1, CDoubleVector p2)
  635. {
  636. m_vOrigin = p1;
  637. m_vDirection = p2 - p1;
  638. m_vDirection.Normalize();
  639. }
  640. bool Intersect(CDoubleVector vCenter, double dRadius)
  641. {
  642. CDoubleVector vDir = vCenter - m_vOrigin;
  643. double v = m_vDirection | vDir;
  644. double b2 = (vDir|vDir) - v*v;
  645. double r2 = dRadius * dRadius;
  646. if(b2 > r2)
  647. return false;
  648. //vIntersection = m_vOrigin + m_vDirection * (v - sqrtf(r2 - b2));
  649. return true;
  650. }
  651. };
  652. /*******************************************************************************
  653. * Class: CLine
  654. ********************************************************************************
  655. * This class implements a 3-dimensional line. It is initialized with two points
  656. * on the line. It can be used to find the shortest distance between two lines or
  657. * between a point and a line, which can be useful for things like collision
  658. * detection.
  659. *******************************************************************************/
  660. class CLine
  661. {
  662. public:
  663. CVector m_vStart;
  664. CVector m_vDir;
  665. CLine() {}
  666. CLine(CVector &p1, CVector &p2) { Init(p1, p2); }
  667. void Init(CVector &p1, CVector &p2)
  668. {
  669. m_vStart = p1;
  670. m_vDir = p2 - p1;
  671. m_vDir.Normalize();
  672. }
  673. CVector ClosestPoint(CVector &p) { return m_vStart + (m_vDir * ((m_vDir | p) - (m_vDir | m_vStart))); }
  674. float Distance(CVector &p) { return p.Distance(ClosestPoint(p)); }
  675. float Distance(CLine &l)
  676. {
  677. CVector v = m_vDir ^ l.m_vDir;
  678. v.Normalize();
  679. return Abs((m_vStart - l.m_vStart) | v);
  680. }
  681. /*
  682. // Calculate the shortest distance between a point to a line
  683. (known) point p = p, or (px, py, pz)
  684. (known) point on line = a, or (ax, ay, az)
  685. (known) direction vector of line = n, or (nx, ny, nz)
  686. (unknown) point on line closest to p = P, or (Px, Py, Pz)
  687. // The vector from p to P must be perpendicular to n, which gives us:
  688. (px-Px, py-Py, pz-Pz) . (nx, ny, nz) = 0
  689. // To make sure P is actually on the line, it must also fit this line equation:
  690. (ax, ay, az) + k * (nx, ny, nz) = (Px, Py, Pz)
  691. // Expanding those equations gives us this:
  692. nx * (px - Px) + ny * (py - Py) + nz * (pz - Pz) = 0
  693. // and these:
  694. Px = ax + k * nx
  695. Py = ay + k * ny
  696. Pz = az + k * nz
  697. // Substituting and solving for k gives us:
  698. nx * (px - (ax + k * nx)) + ny * (py - (ay + k * ny)) + nz * (pz - (az + k * nz)) = 0
  699. nx*px - nx*ax - k*nx2 + ny*py - ny*ay - k*ny2 + nz*pz - nz*az - k*nz2 = 0
  700. k * (nx2 + ny2 + nz2) = nx*px - nx*ax + ny*py - ny*ay + nz*pz - nz*az
  701. k = (nx*px + ny*py + nz*pz - nx*ax - ny*ay - nz*az) / (nx2 + ny2 + nz2)
  702. k = (n.p - n.a) / (n.n)
  703. // If n is normalized then n.n will always equal 1, so...
  704. P = a + (n.p - n.a) * n
  705. distance = | P - p |
  706. */
  707. /*
  708. // Calculate the shortest distance between two lines (call them line A and line B)
  709. (known) point on A = AP, or (APx, APy, APz)
  710. (known) direction vector of A = AN, or (ANx, ANy, ANz)
  711. (known) point on B = BP, or (BPx, BPy, BPz)
  712. (known) direction vector of B = BN, or (BNx, BNy, BNz)
  713. (unknown) point on A closest to B = P1, or (P1x, P1y, P1z)
  714. (unknown) point on B closest to A = P2, or (P2x, P2y, P2z)
  715. // The vector from P1 to P2 is perpendicular to both lines:
  716. (P2x - P1x, P2y - P1y, P2z - P1z) . (ANx, ANy, ANz) = 0
  717. (P2x - P1x, P2y - P1y, P2z - P1z) . (BNx, BNy, BNz) = 0
  718. // To find P1 and P2, we need to find values k and l for the line equations:
  719. (APx, APy, APz) + k * (ANx, ANy, ANz) = (P1x, P1y, P1z)
  720. (BPx, BPy, BPz) + l * (BNx, BNy, BNz) = (P2x, P2y, P2z)
  721. // Expanding these equations gives us these:
  722. ANx * (P2x - P1x) + ANy * (P2y - P1y) + ANz * (P2z - P1z) = 0
  723. BNx * (P2x - P1x) + BNy * (P2y - P1y) + BNz * (P2z - P1z) = 0
  724. // And these:
  725. P1x = APx + k * ANx
  726. P1y = APy + k * ANy
  727. P1z = APz + k * ANz
  728. P2x = BPx + l * BNx
  729. P2y = BPy + l * BNy
  730. P2z = BPz + l * BNz
  731. // Substituting and solving for k and l gives us:
  732. ANx * ((BPx + l * BNx) - (APx + k * ANx)) + ANy * ((BPy + l * BNy) - (APy + k * ANy)) + ANz * ((BPz + l * BNz) - (APz + k * ANz)) = 0
  733. BNx * ((BPx + l * BNx) - (APx + k * ANx)) + BNy * ((BPy + l * BNy) - (APy + k * ANy)) + BNz * ((BPz + l * BNz) - (APz + k * ANz)) = 0
  734. (ANx*BPx + l*ANx*BNx - ANx*APx - k*ANx2) + (ANy*BPy + l*ANy*BNy - ANy*APy - k*ANy2) + (ANz*BPz + l*ANz*BNz - ANz*APz - k*ANz2) = 0
  735. (BNx*BPx + l*BNx2 - BNx*APx - k*ANx*BNx) + (BNy*BPy + l*BNy2 - BNy*APy - k*ANy*BNy) + (BNz*BPz + l*BNz2 - BNz*APz - k*ANz*BNz) = 0
  736. k = (ANx*BPx + l*ANx*BNx - ANx*APx + ANy*BPy + l*ANy*BNy - ANy*APy + ANz*BPz + l*ANz*BNz - ANz*APz) / (ANx2 + ANy2 + ANz2)
  737. k = (BNx*BPx + l*BNx2 - BNx*APx + BNy*BPy + l*BNy2 - BNy*APy + BNz*BPz + l*BNz2 - BNz*APz) / (ANx*BNx + ANy*BNy + ANz*BNz)
  738. (ANx*BNx + ANy*BNy + ANz*BNz) * (ANx*BPx + l*ANx*BNx - ANx*APx + ANy*BPy + l*ANy*BNy - ANy*APy + ANz*BPz + l*ANz*BNz - ANz*APz)  = (ANx2 + ANy2 + ANz2) * (BNx*BPx + l*BNx2 - BNx*APx + BNy*BPy + l*BNy2 - BNy*APy + BNz*BPz + l*BNz2 - BNz*APz)
  739. (ANx*BNx*ANy*BPy + ANx*BNx*l*ANy*BNy - ANx*BNx*ANy*APy + ANx*BNx*ANz*BPz + ANx*BNx*l*ANz*BNz - ANx*BNx*ANz*APz) + 
  740. (ANy*BNy*ANx*BPx + ANy*BNy*l*ANx*BNx - ANy*BNy*ANx*APx + ANy*BNy*ANz*BPz + ANy*BNy*l*ANz*BNz - ANy*BNy*ANz*APz) +
  741. (ANz*BNz*ANx*BPx + ANz*BNz*l*ANx*BNx - ANz*BNz*ANx*APx + ANz*BNz*ANy*BPy + ANz*BNz*l*ANy*BNy - ANz*BNz*ANy*APy) =
  742. (ANx2*BNy*BPy + ANx2*l*BNy2 - ANx2*BNy*APy + ANx2*BNz*BPz + ANx2*l*BNz2 - ANx2*BNz*APz) +
  743. (ANy2*BNx*BPx + ANy2*l*BNx2 - ANy2*BNx*APx + ANy2*BNz*BPz + ANy2*l*BNz2 - ANy2*BNz*APz) +
  744. (ANz2*BNx*BPx + ANz2*l*BNx2 - ANz2*BNx*APx + ANz2*BNy*BPy + ANz2*l*BNy2 - ANz2*BNy*APy)
  745. l * (2*ANx*BNx*ANy*BNy + 2*ANz*BNz*ANx*BNx + 2*ANy*BNy*ANz*BNz - ANx2*BNy2 - ANy2*BNx2 - ANz2*BNx2 - ANx2*BNz2 - ANy2*BNz2 - ANz2*BNy2) = 
  746. (ANx2*BNy*BPy - ANx2*BNy*APy + ANx2*BNz*BPz - ANx2*BNz*APz) +
  747. (ANy2*BNx*BPx - ANy2*BNx*APx + ANy2*BNz*BPz - ANy2*BNz*APz) +
  748. (ANz2*BNx*BPx - ANz2*BNx*APx + ANz2*BNy*BPy - ANz2*BNy*APy) +
  749. (-ANx*BNx*ANy*BPy + ANx*BNx*ANy*APy - ANx*BNx*ANz*BPz + ANx*BNx*ANz*APz) +
  750. (-ANy*BNy*ANx*BPx + ANy*BNy*ANx*APx - ANy*BNy*ANz*BPz + ANy*BNy*ANz*APz) +
  751. (-ANz*BNz*ANx*BPx + ANz*BNz*ANx*APx - ANz*BNz*ANy*BPy + ANz*BNz*ANy*APy)
  752. // Next think about using AN ^ BN to get the direction vector between P1 and P2
  753. // Normalize that vector and call it n
  754. // The distance between the two lines might be the absolute value of (P2-P1).n
  755. // That still doesn't tell us where the closest points on the line are, but it might help find them
  756. */
  757. };
  758. /*******************************************************************************
  759. * Class: CPlane
  760. ********************************************************************************
  761. * This class implements a 3-dimensional plane equation. It can be initialized
  762. * with 3 points on the plane or a normal and a point on the plane, and it can
  763. * be used to find the distance from a point to a plane. I plan to add more to
  764. * this class later to make it more useful.
  765. *******************************************************************************/
  766. class CPlane
  767. {
  768. public:
  769. CVector m_vNormal;
  770. float D;
  771. CPlane() {}
  772. void Init(CVector &p1, CVector &p2, CVector &p3)
  773. { // Initializes the plane based on three points in the plane
  774. Init(NormalVector(p1, p2, p3), p1);
  775. }
  776. void Init(CVector &vNormal, CVector &p)
  777. { // Initializes the plane based on a normal and a point in the plane
  778. m_vNormal = vNormal;
  779. D = -(p | m_vNormal);
  780. }
  781. bool operator==(CPlane &p) { return (Abs(D - p.D) <= DELTA && m_vNormal == p.m_vNormal); }
  782. bool operator!=(CPlane &p) { return !(*this == p); }
  783. float Distance(CVector &p)
  784. { // Returns the distance between the plane and point p
  785. return (m_vNormal | p) + D; // A positive, 0, or negative result indicates the point is in front of, on, or behind the plane
  786. }
  787. bool Intersection(CVector &vPos, CVector &vDir)
  788. { // Returns true if the line intersects the plane and changes vPos to the location of the intersection
  789. float f = m_vNormal | vDir;
  790. if(ABS(f) < DELTA)
  791. return false;
  792. vPos -= vDir * (Distance(vPos) / f);
  793. return true;
  794. }
  795. };
  796. /****************************************************************************
  797. * Class: C3DObject
  798. *****************************************************************************
  799. * This class represents a basic 3D object in the scene. It has a 3D position,
  800. * orientation, velocity, and a parent which provides its frame of reference
  801. * in the scene.
  802. * Note: This class is derived from CQuaternion so it will inherit useful
  803. *       functions like Rotate(), GetViewAxis(), GetUpAxis(), and GetRightAxis().
  804. ****************************************************************************/
  805. #define MIN_DISTANCE 0.01
  806. #define MAX_DISTANCE 1000.0 // Distance to desired far clipping plane
  807. #define MAX_DISCERNABLE 1000000.0 // Beyond this distance, everything is rendered at MAX_DISTANCE
  808. #define HALF_MAX (MAX_DISTANCE*0.5) // Everything between HALF_MAX and MAX_DISCERNABLE is scaled exponentially between HALF_MAX and MAX_DISTANCE
  809. class C3DObject : public CQuaternion
  810. {
  811. protected:
  812. C3DObject *m_pParent; // The object's parent
  813. float m_fBoundingRadius; // The object's bounding radius
  814. float m_fMass; // The object's mass (kg)
  815. CDoubleVector m_vPosition; // The object's position (km)
  816. CVector m_vVelocity; // The object's velocity (km/s)
  817. public:
  818. C3DObject() : CQuaternion(0.0f, 0.0f, 0.0f, 1.0f), m_vPosition(0.0f), m_vVelocity(0.0f)
  819. {
  820. m_fMass = 0.0f;
  821. }
  822. C3DObject(const CMatrix &m) : CQuaternion(m), m_vPosition(m.f41, m.f42, m.f43), m_vVelocity(0.0f)
  823. {
  824. m_fMass = 0.0f;
  825. }
  826. void operator=(const CQuaternion &q) { CQuaternion::operator=(q); }
  827. void operator=(const CMatrix &m)
  828. {
  829. CQuaternion::operator=(m);
  830. SetPosition(CDoubleVector(m.f41, m.f42, m.f43));
  831. }
  832. void SetParent(C3DObject *p) { m_pParent = p; }
  833. C3DObject *GetParent() { return m_pParent; }
  834. void SetMass(float f) { m_fMass = f; }
  835. float GetMass() { return m_fMass; }
  836. void SetPosition(CDoubleVector &v) { m_vPosition = v; }
  837. CDoubleVector GetPosition() { return m_vPosition; }
  838. void SetVelocity(CVector &v) { m_vVelocity = v; }
  839. CVector GetVelocity() { return m_vVelocity; }
  840. CMatrix GetViewMatrix()
  841. {
  842. // Don't use the normal view matrix because it causes precision problems if the camera is too far away from the origin.
  843. // Instead, pretend the camera is at the origin and offset all model matrices by subtracting the camera's position.
  844. CMatrix m = *this;
  845. m.Transpose();
  846. return m;
  847. }
  848. CMatrix GetModelMatrix(C3DObject *pCamera)
  849. {
  850. // Don't use the normal model matrix because it causes precision problems if the camera and model are too far away from the origin.
  851. // Instead, pretend the camera is at the origin and offset all model matrices by subtracting the camera's position.
  852. CMatrix m;
  853. m.ModelMatrix(*this, m_vPosition-pCamera->m_vPosition);
  854. return m;
  855. }
  856. static float GetScalingFactor(double dDistance, double dFactor=1.0)
  857. {
  858. if(dDistance > HALF_MAX)
  859. {
  860. dFactor *= (dDistance >= MAX_DISCERNABLE) ? MAX_DISTANCE : HALF_MAX + HALF_MAX * (1.0 - exp(-2.5 * dDistance / MAX_DISCERNABLE));
  861. dFactor /= dDistance;
  862. }
  863. return (float)dFactor;
  864. }
  865. float ScaleModelMatrix(CMatrix &m, double dDistance, double dFactor=1.0)
  866. {
  867. // This code scales the object's size and distance to the camera down when it's too far away.
  868. // This solves a problem with many video card drivers where objects too far away aren't rendering properly.
  869. // It also alleviates the Z-buffer precision problem caused by having your near and far clipping planes too far apart.
  870. float fFactor = GetScalingFactor(dDistance, dFactor);
  871. if(fFactor <= 1.0f)
  872. {
  873. m.f41 *= fFactor;
  874. m.f42 *= fFactor;
  875. m.f43 *= fFactor;
  876. m.Scale(fFactor, fFactor, fFactor);
  877. }
  878. return fFactor;
  879. }
  880. float GetScaledModelMatrix(CMatrix &m, C3DObject *pCamera, double dFactor=1.0)
  881. {
  882. CDoubleVector vPos = m_vPosition - pCamera->m_vPosition;
  883. double dDistance = vPos.Magnitude();
  884. m.ModelMatrix(*this, vPos);
  885. return ScaleModelMatrix(m, dDistance, dFactor);
  886. }
  887. void GetBillboardMatrix(CMatrix &m, C3DObject *pCamera, float fSize)
  888. {
  889. CDoubleVector vPos = m_vPosition - pCamera->m_vPosition;
  890. double dDistance = vPos.Magnitude();
  891. CVector vView = vPos / dDistance;
  892. CVector vRight = vView ^ CVector(0, 1, 0);
  893. vRight.Normalize();
  894. CVector vUp = vRight ^ vView;
  895. vUp.Normalize();
  896. m.ModelMatrix(vPos, vView, vUp, vRight);
  897. m.Scale(fSize, fSize, fSize);
  898. }
  899. float GetScaledBillboardMatrix(CMatrix &m, C3DObject *pCamera, float fSize, double dFactor=1.0)
  900. {
  901. CDoubleVector vPos = m_vPosition - pCamera->m_vPosition;
  902. double dDistance = vPos.Magnitude();
  903. CVector vView = vPos / dDistance;
  904. CVector vRight = vView ^ CVector(0, 1, 0);
  905. vRight.Normalize();
  906. CVector vUp = vRight ^ vView;
  907. vUp.Normalize();
  908. m.ModelMatrix(vPos, vView, vUp, vRight);
  909. float fFactor = ScaleModelMatrix(m, dDistance, dFactor);
  910. m.Scale(fSize, fSize, fSize);
  911. return fFactor;
  912. }
  913. float DistanceTo(C3DObject &obj) { return (float)m_vPosition.Distance(obj.m_vPosition); }
  914. CVector VectorTo(C3DObject &obj) { return obj.m_vPosition - m_vPosition; }
  915. float GravityPull(float fDistSquared) { return (GRAVCONST * m_fMass) / fDistSquared; }
  916. CVector GravityVector(C3DObject &obj)
  917. {
  918. CVector vGravity = obj.VectorTo(*this);
  919. float fDistSquared = vGravity.MagnitudeSquared();
  920. vGravity *= GravityPull(fDistSquared) / sqrtf(fDistSquared);
  921. return vGravity;
  922. }
  923. void Accelerate(CVector &vAccel, float fSeconds, float fResistance=0)
  924. {
  925. m_vVelocity += vAccel * fSeconds;
  926. if(fResistance > DELTA)
  927. m_vVelocity *= 1.0f - fResistance * fSeconds;
  928. m_vPosition += m_vVelocity * fSeconds;
  929. }
  930. // Kinetic energy (Joules) = 1/2 * mass * velocity^2 (mass in kg, velocity in m/s)
  931. // Kinetic energy (kilotons) = (KE in Joules) / (4.185e12 joules/KT)
  932. //float GetKEJoules(C3DObject &obj) { return 500000.0f * m_fMass * (m_vVelocity-obj.m_vVelocity).MagnitudeSquared(); }
  933. //float GetKEKilotons(C3DObject &obj) { return 1.19474e-7f * m_fMass * (m_vVelocity-obj.m_vVelocity).MagnitudeSquared(); }
  934. };
  935. #define COLOR_CTOF(x) (x/256.0f)
  936. #define COLOR_FTOC(x) (ColorClamp(x*256))
  937. inline unsigned char ColorClamp(int n) { return (unsigned char)(n < 0 ? 0 : n > 255 ? 255 : n); }
  938. inline unsigned char ColorClamp(float f) { return (unsigned char)(f < 0 ? 0 : f > 255 ? 255 : f); }
  939. class CColor
  940. {
  941. public:
  942. unsigned char r, g, b, a;
  943. CColor() {}
  944. CColor(int r, int g, int b, int a=255)
  945. {
  946. this->r = r;
  947. this->g = g;
  948. this->b = b;
  949. this->a = a;
  950. }
  951. CColor(float r, float g, float b, float a=1.0f)
  952. {
  953. this->r = COLOR_FTOC(r);
  954. this->g = COLOR_FTOC(g);
  955. this->b = COLOR_FTOC(b);
  956. this->a = COLOR_FTOC(a);
  957. }
  958. CColor operator*(const float f) const { return CColor(ColorClamp(r*f), ColorClamp(g*f), ColorClamp(b*f), ColorClamp(a*f)); }
  959. CColor operator+(const CColor c) const { return CColor(ColorClamp(r+c.r), ColorClamp(g+c.g), ColorClamp(b+c.b), ColorClamp(a+c.a)); }
  960. operator unsigned char*() { return &r; }
  961. };
  962. #endif //__Matrix_h__