quat.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: /Commando/Code/wwmath/quat.h 29 5/11/01 7:11p Jani_p $ */
  19. /***************************************************************************
  20. *** Confidential - Westwood Studios ***
  21. ***************************************************************************
  22. * *
  23. * Project Name : Voxel Technology *
  24. * *
  25. * File Name : QUAT.H *
  26. * *
  27. * Programmer : Greg Hjelstrom *
  28. * *
  29. * Start Date : 02/24/97 *
  30. * *
  31. * Last Update : February 24, 1997 [GH] *
  32. * *
  33. *-------------------------------------------------------------------------*
  34. * Functions: *
  35. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  36. #if defined(_MSC_VER)
  37. #pragma once
  38. #endif
  39. #ifndef QUAT_H
  40. #define QUAT_H
  41. #include "always.h"
  42. #include "wwmath.h"
  43. #include "matrix3.h"
  44. #include "vector3.h"
  45. #include "matrix3d.h"
  46. class Quaternion
  47. {
  48. private:
  49. public:
  50. // X,Y,Z are the imaginary parts of the quaterion
  51. // W is the real part
  52. float X;
  53. float Y;
  54. float Z;
  55. float W;
  56. public:
  57. WWINLINE Quaternion(void) {};
  58. WWINLINE explicit Quaternion(bool init) { if (init) { X = 0.0f; Y = 0.0f; Z = 0.0f; W = 1.0f; } }
  59. WWINLINE explicit Quaternion(float a, float b, float c, float d) { X=a; Y=b; Z=c; W=d; }
  60. WWINLINE explicit Quaternion(const Vector3 & axis,float angle);
  61. WWINLINE Quaternion & operator=(const Quaternion & source);
  62. WWINLINE void Set(float a = 0.0, float b = 0.0, float c = 0.0, float d = 1.0) { X = a; Y = b; Z = c; W = d; }
  63. WWINLINE void Make_Identity(void) { Set(); };
  64. WWINLINE void Scale(float s) { X = (float)(s*X); Y = (float)(s*Y); Z = (float)(s*Z); W = (float)(s*W); }
  65. // Array access
  66. WWINLINE float & operator [](int i) { return (&X)[i]; }
  67. WWINLINE const float & operator [](int i) const { return (&X)[i]; }
  68. // Unary operators.
  69. // Remember that q and -q represent the same 3D rotation.
  70. WWINLINE Quaternion operator-() const { return(Quaternion(-X,-Y,-Z,-W)); }
  71. WWINLINE Quaternion operator+() const { return *this; }
  72. // Every 3D rotation can be expressed by two different quaternions, This
  73. // function makes the current quaternion convert itself to the representation
  74. // which is closer on the 4D unit-hypersphere to the given quaternion.
  75. Quaternion & Make_Closest(const Quaternion & qto);
  76. // Square of the magnitude of the quaternion
  77. WWINLINE float Length2(void) const { return (X*X + Y*Y + Z*Z + W*W); }
  78. // Magnitude of the quaternion
  79. WWINLINE float Length(void) const { return WWMath::Sqrt(Length2()); }
  80. // Make the quaternion unit length
  81. void Normalize(void);
  82. // post-concatenate rotations about the coordinate axes
  83. void Rotate_X(float theta);
  84. void Rotate_Y(float theta);
  85. void Rotate_Z(float theta);
  86. // initialize this quaternion randomly (creates a random *unit* quaternion)
  87. void Randomize(void);
  88. // transform (rotate) a vector with this quaternion
  89. WWINLINE Vector3 Rotate_Vector(const Vector3 & v) const;
  90. WWINLINE void Rotate_Vector(const Vector3 & v,Vector3 * set_result) const;
  91. // verify that none of the members of this quaternion are invalid floats
  92. bool Is_Valid(void) const;
  93. };
  94. // Inverse of the quaternion (1/q)
  95. WWINLINE Quaternion Inverse(const Quaternion & a)
  96. {
  97. return Quaternion(-a[0],-a[1],-a[2],a[3]);
  98. }
  99. // Conjugate of the quaternion
  100. WWINLINE Quaternion Conjugate(const Quaternion & a)
  101. {
  102. return Quaternion(-a[0],-a[1],-a[2],a[3]);
  103. }
  104. // Add two quaternions
  105. WWINLINE Quaternion operator + (const Quaternion & a,const Quaternion & b)
  106. {
  107. return Quaternion(a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]);
  108. }
  109. // Subract two quaternions
  110. WWINLINE Quaternion operator - (const Quaternion & a,const Quaternion & b)
  111. {
  112. return Quaternion(a[0] - b[0], a[1] - b[1], a[2] - b[2], a[3] - b[3]);
  113. }
  114. // Multiply a quaternion by a scalar:
  115. WWINLINE Quaternion operator * (float scl, const Quaternion & a)
  116. {
  117. return Quaternion(scl*a[0], scl*a[1], scl*a[2], scl*a[3]);
  118. }
  119. // Multiply a quaternion by a scalar
  120. WWINLINE Quaternion operator * (const Quaternion & a, float scl)
  121. {
  122. return scl*a;
  123. }
  124. // Multiply two quaternions
  125. WWINLINE Quaternion operator * (const Quaternion & a,const Quaternion & b)
  126. {
  127. return Quaternion
  128. (
  129. a.W*b.X + b.W*a.X + (a.Y*b.Z - b.Y*a.Z),
  130. a.W*b.Y + b.W*a.Y - (a.X*b.Z - b.X*a.Z),
  131. a.W*b.Z + b.W*a.Z + (a.X*b.Y - b.X*a.Y),
  132. a.W * b.W - (a.X * b.X + a.Y * b.Y + a.Z * b.Z)
  133. );
  134. }
  135. // Divide two quaternions
  136. WWINLINE Quaternion operator / (const Quaternion & a,const Quaternion & b)
  137. {
  138. return a * Inverse(b);
  139. }
  140. // Normalized version of the quaternion
  141. WWINLINE Quaternion Normalize(const Quaternion & a)
  142. {
  143. float mag = a.Length();
  144. if (0.0f == mag) {
  145. return a;
  146. } else {
  147. float oomag = 1.0f / mag;
  148. return Quaternion(a[0] * oomag, a[1] * oomag, a[2] * oomag, a[3] * oomag);
  149. }
  150. }
  151. // This function computes a quaternion based on an axis
  152. // (defined by the given Vector a) and an angle about
  153. // which to rotate. The angle is expressed in radians.
  154. Quaternion Axis_To_Quat(const Vector3 &a, float angle);
  155. // Pass the x and y coordinates of the last and current position
  156. // of the mouse, scaled so they are from -1.0 to 1.0
  157. // The quaternion is the computed as the rotation of a trackball
  158. // between the two points projected onto a sphere. This can
  159. // be used to implement an intuitive viewing control system.
  160. Quaternion Trackball(float x0, float y0, float x1, float y1, float sphsize);
  161. // Spherical Linear interpolation of quaternions
  162. //Quaternion Slerp(const Quaternion & a,const Quaternion & b,float t);
  163. void __cdecl Slerp(Quaternion& result, const Quaternion & a,const Quaternion & b,float t);
  164. // Fast slerp is innaccurate but multiple times faster
  165. void __cdecl Fast_Slerp(Quaternion& result, const Quaternion & a,const Quaternion & b,float t);
  166. // Convert a rotation matrix into a quaternion
  167. Quaternion Build_Quaternion(const Matrix3 & matrix);
  168. Quaternion Build_Quaternion(const Matrix3D & matrix);
  169. Quaternion Build_Quaternion(const Matrix4 & matrix);
  170. // Convert a quaternion into a rotation matrix
  171. Matrix3 Build_Matrix3(const Quaternion & quat);
  172. Matrix3D &Build_Matrix3D(const Quaternion & q, Matrix3D &out);
  173. WWINLINE Matrix3D &Build_Matrix3D(const Quaternion & q, Matrix3D &out)
  174. {
  175. out[0][0] = (float)(1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]));
  176. out[0][1] = (float)(2.0 * (q[0] * q[1] - q[2] * q[3]));
  177. out[0][2] = (float)(2.0 * (q[2] * q[0] + q[1] * q[3]));
  178. out[1][0] = (float)(2.0 * (q[0] * q[1] + q[2] * q[3]));
  179. out[1][1] = (float)(1.0 - 2.0f * (q[2] * q[2] + q[0] * q[0]));
  180. out[1][2] = (float)(2.0 * (q[1] * q[2] - q[0] * q[3]));
  181. out[2][0] = (float)(2.0 * (q[2] * q[0] - q[1] * q[3]));
  182. out[2][1] = (float)(2.0 * (q[1] * q[2] + q[0] * q[3]));
  183. out[2][2] =(float)(1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]));
  184. // no translation
  185. out[0][3] = out[1][3] = out[2][3] = 0.0f;
  186. return out;
  187. }
  188. Matrix4 Build_Matrix4(const Quaternion & quat);
  189. // Some values can be cached if you are performing multiple slerps
  190. // between the same two quaternions...
  191. struct SlerpInfoStruct
  192. {
  193. float SinT;
  194. float Theta;
  195. bool Flip;
  196. bool Linear;
  197. };
  198. // Cached slerp implementation
  199. void Slerp_Setup(const Quaternion & p,const Quaternion & q,SlerpInfoStruct * slerpinfo);
  200. void Cached_Slerp(const Quaternion & p,const Quaternion & q,float alpha,SlerpInfoStruct * slerpinfo,Quaternion * set_q);
  201. Quaternion Cached_Slerp(const Quaternion & p,const Quaternion & q,float alpha,SlerpInfoStruct * slerpinfo);
  202. WWINLINE Vector3 Quaternion::Rotate_Vector(const Vector3 & v) const
  203. {
  204. float x = W*v.X + (Y*v.Z - v.Y*Z);
  205. float y = W*v.Y - (X*v.Z - v.X*Z);
  206. float z = W*v.Z + (X*v.Y - v.X*Y);
  207. float w = -(X*v.X + Y*v.Y + Z*v.Z);
  208. return Vector3
  209. (
  210. w*(-X) + W*x + (y*(-Z) - (-Y)*z),
  211. w*(-Y) + W*y - (x*(-Z) - (-X)*z),
  212. w*(-Z) + W*z + (x*(-Y) - (-X)*y)
  213. );
  214. }
  215. WWINLINE void Quaternion::Rotate_Vector(const Vector3 & v,Vector3 * result) const
  216. {
  217. assert(result != NULL);
  218. float x = W*v.X + (Y*v.Z - v.Y*Z);
  219. float y = W*v.Y - (X*v.Z - v.X*Z);
  220. float z = W*v.Z + (X*v.Y - v.X*Y);
  221. float w = -(X*v.X + Y*v.Y + Z*v.Z);
  222. result->X = w*(-X) + W*x + (y*(-Z) - (-Y)*z);
  223. result->Y = w*(-Y) + W*y - (x*(-Z) - (-X)*z);
  224. result->Z = w*(-Z) + W*z + (x*(-Y) - (-X)*y);
  225. }
  226. WWINLINE bool Quaternion::Is_Valid(void) const
  227. {
  228. return ( WWMath::Is_Valid_Float(X) &&
  229. WWMath::Is_Valid_Float(Y) &&
  230. WWMath::Is_Valid_Float(Z) &&
  231. WWMath::Is_Valid_Float(W) );
  232. }
  233. WWINLINE bool Equal_Within_Epsilon(const Quaternion &a, const Quaternion &b, float epsilon)
  234. {
  235. return( (WWMath::Fabs(a.X - b.X) < epsilon) &&
  236. (WWMath::Fabs(a.Y - b.Y) < epsilon) &&
  237. (WWMath::Fabs(a.Z - b.Z) < epsilon) &&
  238. (WWMath::Fabs(a.W - b.W) < epsilon) );
  239. }
  240. /***********************************************************************************************
  241. * Quaternion::operator= -- Assignment operator *
  242. * *
  243. * INPUT: *
  244. * *
  245. * OUTPUT: *
  246. * *
  247. * WARNINGS: *
  248. * *
  249. * HISTORY: *
  250. * 02/24/1997 GH : Created. *
  251. *=============================================================================================*/
  252. WWINLINE Quaternion & Quaternion::operator = (const Quaternion & source)
  253. {
  254. X = source[0];
  255. Y = source[1];
  256. Z = source[2];
  257. W = source[3];
  258. return *this;
  259. }
  260. #endif /* QUAT_H */