llmatrix3.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. /**
  2. * @file llmatrix3.cpp
  3. * @brief LLMatrix3 class implementation.
  4. *
  5. * $LicenseInfo:firstyear=2000&license=viewergpl$
  6. *
  7. * Copyright (c) 2000-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "linden_common.h"
  33. #include "llvector3.h"
  34. #include "llvector3d.h"
  35. #include "llvector4.h"
  36. #include "llmatrix4.h"
  37. #include "llmatrix3.h"
  38. #include "llquaternion.h"
  39. // LLMatrix3
  40. // ji
  41. // LLMatrix3 = |00 01 02 |
  42. // |10 11 12 |
  43. // |20 21 22 |
  44. // LLMatrix3 = |fx fy fz | forward-axis
  45. // |lx ly lz | left-axis
  46. // |ux uy uz | up-axis
  47. // Constructors
  48. LLMatrix3::LLMatrix3(const LLQuaternion& q) noexcept
  49. {
  50. setRot(q);
  51. }
  52. LLMatrix3::LLMatrix3(F32 angle, const LLVector3& vec) noexcept
  53. {
  54. LLQuaternion quat(angle, vec);
  55. setRot(quat);
  56. }
  57. LLMatrix3::LLMatrix3(F32 angle, const LLVector3d& vec) noexcept
  58. {
  59. LLVector3 vec_f;
  60. vec_f.set(vec);
  61. LLQuaternion quat(angle, vec_f);
  62. setRot(quat);
  63. }
  64. LLMatrix3::LLMatrix3(F32 angle, const LLVector4 &vec) noexcept
  65. {
  66. LLQuaternion quat(angle, vec);
  67. setRot(quat);
  68. }
  69. LLMatrix3::LLMatrix3(F32 roll, F32 pitch, F32 yaw) noexcept
  70. {
  71. setRot(roll, pitch, yaw);
  72. }
  73. // From Matrix and Quaternion FAQ
  74. void LLMatrix3::getEulerAngles(F32* roll, F32* pitch, F32* yaw) const
  75. {
  76. F64 angle_x, angle_z;
  77. F64 cx, cz; // cosine of angle_x, angle_z
  78. F64 sx, sz; // sine of angle_x, angle_z
  79. F64 angle_y = asin(llclamp((F64)mMatrix[2][0], -1.0, 1.0));
  80. F64 cy = cos(angle_y);
  81. if (fabs(cy) > 0.005) // non-zero
  82. {
  83. // No gimbal lock
  84. cx = (F64)mMatrix[2][2] / cy;
  85. sx = -(F64)mMatrix[2][1] / cy;
  86. angle_x = atan2(sx, cx);
  87. cz = (F64)mMatrix[0][0] / cy;
  88. sz = -(F64)mMatrix[1][0] / cy;
  89. angle_z = atan2(sz, cz);
  90. }
  91. else
  92. {
  93. // Gimbal lock
  94. angle_x = 0;
  95. // Some tricky math thereby avoided, see article
  96. cz = mMatrix[1][1];
  97. sz = mMatrix[0][1];
  98. angle_z = atan2(sz, cz);
  99. }
  100. *roll = (F32)angle_x;
  101. *pitch = (F32)angle_y;
  102. *yaw = (F32)angle_z;
  103. }
  104. // Clear and Assignment Functions
  105. const LLMatrix3& LLMatrix3::setIdentity()
  106. {
  107. mMatrix[0][0] = 1.f;
  108. mMatrix[0][1] = 0.f;
  109. mMatrix[0][2] = 0.f;
  110. mMatrix[1][0] = 0.f;
  111. mMatrix[1][1] = 1.f;
  112. mMatrix[1][2] = 0.f;
  113. mMatrix[2][0] = 0.f;
  114. mMatrix[2][1] = 0.f;
  115. mMatrix[2][2] = 1.f;
  116. return *this;
  117. }
  118. const LLMatrix3& LLMatrix3::clear()
  119. {
  120. mMatrix[0][0] = mMatrix[0][1] = mMatrix[0][2] = 0.f;
  121. mMatrix[1][0] = mMatrix[1][1] = mMatrix[1][2] = 0.f;
  122. mMatrix[2][0] = mMatrix[2][1] = mMatrix[2][2] = 0.f;
  123. return *this;
  124. }
  125. const LLMatrix3& LLMatrix3::setZero()
  126. {
  127. mMatrix[0][0] = mMatrix[0][1] = mMatrix[0][2] = 0.f;
  128. mMatrix[1][0] = mMatrix[1][1] = mMatrix[1][2] = 0.f;
  129. mMatrix[2][0] = mMatrix[2][1] = mMatrix[2][2] = 0.f;
  130. return *this;
  131. }
  132. // Various useful mMatrix functions
  133. const LLMatrix3& LLMatrix3::transpose()
  134. {
  135. // Transpose the matrix
  136. F32 temp = mMatrix[VX][VY];
  137. mMatrix[VX][VY] = mMatrix[VY][VX];
  138. mMatrix[VY][VX] = temp;
  139. temp = mMatrix[VX][VZ];
  140. mMatrix[VX][VZ] = mMatrix[VZ][VX];
  141. mMatrix[VZ][VX] = temp;
  142. temp = mMatrix[VY][VZ];
  143. mMatrix[VY][VZ] = mMatrix[VZ][VY];
  144. mMatrix[VZ][VY] = temp;
  145. return *this;
  146. }
  147. F32 LLMatrix3::determinant() const
  148. {
  149. // Is this a useful method when we assume the matrices are valid rotation
  150. // matrices throughout this implementation?
  151. return mMatrix[0][0] * (mMatrix[1][1] * mMatrix[2][2] -
  152. mMatrix[1][2] * mMatrix[2][1]) +
  153. mMatrix[0][1] * (mMatrix[1][2] * mMatrix[2][0] -
  154. mMatrix[1][0] * mMatrix[2][2]) +
  155. mMatrix[0][2] * (mMatrix[1][0] * mMatrix[2][1] -
  156. mMatrix[1][1] * mMatrix[2][0]);
  157. }
  158. // inverts this matrix
  159. void LLMatrix3::invert()
  160. {
  161. // fails silently if determinant is zero too small
  162. F32 det = determinant();
  163. constexpr F32 VERY_SMALL_DETERMINANT = 0.000001f;
  164. if (fabsf(det) > VERY_SMALL_DETERMINANT)
  165. {
  166. // invertiable
  167. LLMatrix3 t(*this);
  168. mMatrix[VX][VX] = (t.mMatrix[VY][VY] * t.mMatrix[VZ][VZ] -
  169. t.mMatrix[VY][VZ] * t.mMatrix[VZ][VY]) / det;
  170. mMatrix[VY][VX] = (t.mMatrix[VY][VZ] * t.mMatrix[VZ][VX] -
  171. t.mMatrix[VY][VX] * t.mMatrix[VZ][VZ]) / det;
  172. mMatrix[VZ][VX] = (t.mMatrix[VY][VX] * t.mMatrix[VZ][VY] -
  173. t.mMatrix[VY][VY] * t.mMatrix[VZ][VX]) / det;
  174. mMatrix[VX][VY] = (t.mMatrix[VZ][VY] * t.mMatrix[VX][VZ] -
  175. t.mMatrix[VZ][VZ] * t.mMatrix[VX][VY]) / det;
  176. mMatrix[VY][VY] = (t.mMatrix[VZ][VZ] * t.mMatrix[VX][VX] -
  177. t.mMatrix[VZ][VX] * t.mMatrix[VX][VZ]) / det;
  178. mMatrix[VZ][VY] = (t.mMatrix[VZ][VX] * t.mMatrix[VX][VY] -
  179. t.mMatrix[VZ][VY] * t.mMatrix[VX][VX]) / det;
  180. mMatrix[VX][VZ] = (t.mMatrix[VX][VY] * t.mMatrix[VY][VZ] -
  181. t.mMatrix[VX][VZ] * t.mMatrix[VY][VY]) / det;
  182. mMatrix[VY][VZ] = (t.mMatrix[VX][VZ] * t.mMatrix[VY][VX] -
  183. t.mMatrix[VX][VX] * t.mMatrix[VY][VZ]) / det;
  184. mMatrix[VZ][VZ] = (t.mMatrix[VX][VX] * t.mMatrix[VY][VY] -
  185. t.mMatrix[VX][VY] * t.mMatrix[VY][VX]) / det;
  186. }
  187. }
  188. // does not assume a rotation matrix, and does not divide by determinant,
  189. // assuming results will be renormalized.
  190. const LLMatrix3& LLMatrix3::adjointTranspose()
  191. {
  192. LLMatrix3 adjoint_transpose;
  193. adjoint_transpose.mMatrix[VX][VX] = mMatrix[VY][VY] * mMatrix[VZ][VZ] -
  194. mMatrix[VY][VZ] * mMatrix[VZ][VY];
  195. adjoint_transpose.mMatrix[VY][VX] = mMatrix[VY][VZ] * mMatrix[VZ][VX] -
  196. mMatrix[VY][VX] * mMatrix[VZ][VZ];
  197. adjoint_transpose.mMatrix[VZ][VX] = mMatrix[VY][VX] * mMatrix[VZ][VY] -
  198. mMatrix[VY][VY] * mMatrix[VZ][VX];
  199. adjoint_transpose.mMatrix[VX][VY] = mMatrix[VZ][VY] * mMatrix[VX][VZ] -
  200. mMatrix[VZ][VZ] * mMatrix[VX][VY];
  201. adjoint_transpose.mMatrix[VY][VY] = mMatrix[VZ][VZ] * mMatrix[VX][VX] -
  202. mMatrix[VZ][VX] * mMatrix[VX][VZ];
  203. adjoint_transpose.mMatrix[VZ][VY] = mMatrix[VZ][VX] * mMatrix[VX][VY] -
  204. mMatrix[VZ][VY] * mMatrix[VX][VX];
  205. adjoint_transpose.mMatrix[VX][VZ] = mMatrix[VX][VY] * mMatrix[VY][VZ] -
  206. mMatrix[VX][VZ] * mMatrix[VY][VY];
  207. adjoint_transpose.mMatrix[VY][VZ] = mMatrix[VX][VZ] * mMatrix[VY][VX] -
  208. mMatrix[VX][VX] * mMatrix[VY][VZ];
  209. adjoint_transpose.mMatrix[VZ][VZ] = mMatrix[VX][VX] * mMatrix[VY][VY] -
  210. mMatrix[VX][VY] * mMatrix[VY][VX];
  211. *this = adjoint_transpose;
  212. return *this;
  213. }
  214. // SJB: This code is correct for a logicly stored (non-transposed) matrix;
  215. // Our matrices are stored transposed, OpenGL style, so this generates the
  216. // INVERSE quaternion (-x, -y, -z, w)!
  217. // Because we use similar logic in LLQuaternion::getMatrix3,
  218. // we are internally consistant so everything works OK :)
  219. LLQuaternion LLMatrix3::quaternion() const
  220. {
  221. LLQuaternion quat;
  222. F32 s, q[4];
  223. U32 i, j, k;
  224. U32 nxt[3] = { 1, 2, 0 };
  225. F32 tr = mMatrix[0][0] + mMatrix[1][1] + mMatrix[2][2];
  226. // Check the diagonal
  227. if (tr > 0.f)
  228. {
  229. s = sqrtf(tr + 1.f);
  230. quat.mQ[VS] = s * 0.5f;
  231. s = 0.5f / s;
  232. quat.mQ[VX] = (mMatrix[1][2] - mMatrix[2][1]) * s;
  233. quat.mQ[VY] = (mMatrix[2][0] - mMatrix[0][2]) * s;
  234. quat.mQ[VZ] = (mMatrix[0][1] - mMatrix[1][0]) * s;
  235. }
  236. else
  237. {
  238. // diagonal is negative
  239. i = 0;
  240. if (mMatrix[1][1] > mMatrix[0][0])
  241. {
  242. i = 1;
  243. }
  244. if (mMatrix[2][2] > mMatrix[i][i])
  245. {
  246. i = 2;
  247. }
  248. j = nxt[i];
  249. k = nxt[j];
  250. s = sqrtf((mMatrix[i][i] - (mMatrix[j][j] + mMatrix[k][k])) + 1.f);
  251. q[i] = s * 0.5f;
  252. if (s != 0.f)
  253. {
  254. s = 0.5f / s;
  255. }
  256. q[3] = (mMatrix[j][k] - mMatrix[k][j]) * s;
  257. q[j] = (mMatrix[i][j] + mMatrix[j][i]) * s;
  258. q[k] = (mMatrix[i][k] + mMatrix[k][i]) * s;
  259. quat.set(q);
  260. }
  261. return quat;
  262. }
  263. // These functions take Rotation arguments
  264. const LLMatrix3& LLMatrix3::setRot(F32 angle, const LLVector3& vec)
  265. {
  266. setRot(LLQuaternion(angle, vec));
  267. return *this;
  268. }
  269. const LLMatrix3& LLMatrix3::setRot(F32 roll, F32 pitch, F32 yaw)
  270. {
  271. // Rotates RH about x-axis by 'roll' then
  272. // rotates RH about the old y-axis by 'pitch' then
  273. // rotates RH about the original z-axis by 'yaw'.
  274. // .
  275. // /|\ yaw axis
  276. // | __.
  277. // ._ ___| /| pitch axis
  278. // _||\ \\ |-. /
  279. // \|| \_______\_|__\_/_______
  280. // | _ _ o o o_o_o_o o /_\_ ________\ roll axis
  281. // // /_______/ /__________> /
  282. // /_,-' // /
  283. // /__,-'
  284. F32 cx = cosf(roll); //A
  285. F32 sx = sinf(roll); //B
  286. F32 cy = cosf(pitch); //C
  287. F32 sy = sinf(pitch); //D
  288. F32 cz = cosf(yaw); //E
  289. F32 sz = sinf(yaw); //F
  290. F32 cxsy = cx * sy; //AD
  291. F32 sxsy = sx * sy; //BD
  292. mMatrix[0][0] = cy * cz;
  293. mMatrix[1][0] = -cy * sz;
  294. mMatrix[2][0] = sy;
  295. mMatrix[0][1] = sxsy * cz + cx * sz;
  296. mMatrix[1][1] = -sxsy * sz + cx * cz;
  297. mMatrix[2][1] = -sx * cy;
  298. mMatrix[0][2] = -cxsy * cz + sx * sz;
  299. mMatrix[1][2] = cxsy * sz + sx * cz;
  300. mMatrix[2][2] = cx * cy;
  301. return *this;
  302. }
  303. const LLMatrix3& LLMatrix3::setRot(const LLQuaternion& q)
  304. {
  305. *this = q.getMatrix3();
  306. return *this;
  307. }
  308. const LLMatrix3& LLMatrix3::setRows(const LLVector3& fwd,
  309. const LLVector3& left,
  310. const LLVector3& up)
  311. {
  312. mMatrix[0][0] = fwd.mV[0];
  313. mMatrix[0][1] = fwd.mV[1];
  314. mMatrix[0][2] = fwd.mV[2];
  315. mMatrix[1][0] = left.mV[0];
  316. mMatrix[1][1] = left.mV[1];
  317. mMatrix[1][2] = left.mV[2];
  318. mMatrix[2][0] = up.mV[0];
  319. mMatrix[2][1] = up.mV[1];
  320. mMatrix[2][2] = up.mV[2];
  321. return *this;
  322. }
  323. const LLMatrix3& LLMatrix3::setRow(U32 rowIndex, const LLVector3& row)
  324. {
  325. llassert(rowIndex >= 0 && rowIndex < NUM_VALUES_IN_MAT3);
  326. mMatrix[rowIndex][0] = row[0];
  327. mMatrix[rowIndex][1] = row[1];
  328. mMatrix[rowIndex][2] = row[2];
  329. return *this;
  330. }
  331. const LLMatrix3& LLMatrix3::setCol(U32 col_idx, const LLVector3& col)
  332. {
  333. llassert(col_idx >= 0 && col_idx < NUM_VALUES_IN_MAT3);
  334. mMatrix[0][col_idx] = col[0];
  335. mMatrix[1][col_idx] = col[1];
  336. mMatrix[2][col_idx] = col[2];
  337. return *this;
  338. }
  339. const LLMatrix3& LLMatrix3::rotate(F32 angle, const LLVector3& vec)
  340. {
  341. LLMatrix3 mat(angle, vec);
  342. *this *= mat;
  343. return *this;
  344. }
  345. const LLMatrix3& LLMatrix3::rotate(F32 roll, F32 pitch, F32 yaw)
  346. {
  347. LLMatrix3 mat(roll, pitch, yaw);
  348. *this *= mat;
  349. return *this;
  350. }
  351. const LLMatrix3& LLMatrix3::rotate(const LLQuaternion& q)
  352. {
  353. LLMatrix3 mat(q);
  354. *this *= mat;
  355. return *this;
  356. }
  357. void LLMatrix3::add(const LLMatrix3& other_matrix)
  358. {
  359. for (S32 i = 0; i < 3; ++i)
  360. {
  361. for (S32 j = 0; j < 3; ++j)
  362. {
  363. mMatrix[i][j] += other_matrix.mMatrix[i][j];
  364. }
  365. }
  366. }
  367. LLVector3 LLMatrix3::getFwdRow() const
  368. {
  369. return LLVector3(mMatrix[VX]);
  370. }
  371. LLVector3 LLMatrix3::getLeftRow() const
  372. {
  373. return LLVector3(mMatrix[VY]);
  374. }
  375. LLVector3 LLMatrix3::getUpRow() const
  376. {
  377. return LLVector3(mMatrix[VZ]);
  378. }
  379. const LLMatrix3& LLMatrix3::orthogonalize()
  380. {
  381. LLVector3 x_axis(mMatrix[VX]);
  382. LLVector3 y_axis(mMatrix[VY]);
  383. LLVector3 z_axis(mMatrix[VZ]);
  384. x_axis.normalize();
  385. y_axis -= x_axis * (x_axis * y_axis);
  386. y_axis.normalize();
  387. z_axis = x_axis % y_axis;
  388. setRows(x_axis, y_axis, z_axis);
  389. return *this;
  390. }
  391. // LLMatrix3 Operators
  392. LLMatrix3 operator*(const LLMatrix3& a, const LLMatrix3& b)
  393. {
  394. LLMatrix3 mat;
  395. for (U32 i = 0; i < NUM_VALUES_IN_MAT3; ++i)
  396. {
  397. for (U32 j = 0; j < NUM_VALUES_IN_MAT3; ++j)
  398. {
  399. mat.mMatrix[j][i] = a.mMatrix[j][0] * b.mMatrix[0][i] +
  400. a.mMatrix[j][1] * b.mMatrix[1][i] +
  401. a.mMatrix[j][2] * b.mMatrix[2][i];
  402. }
  403. }
  404. return mat;
  405. }
  406. #if 0 // Not implemented to help enforce code consistency with the syntax of
  407. // row-major notation. This is a Good Thing.
  408. LLVector3 operator*(const LLMatrix3& a, const LLVector3& b)
  409. {
  410. LLVector3 vec;
  411. // matrix operates "from the left" on column vector
  412. vec.mV[VX] = a.mMatrix[VX][VX] * b.mV[VX] +
  413. a.mMatrix[VX][VY] * b.mV[VY] +
  414. a.mMatrix[VX][VZ] * b.mV[VZ];
  415. vec.mV[VY] = a.mMatrix[VY][VX] * b.mV[VX] +
  416. a.mMatrix[VY][VY] * b.mV[VY] +
  417. a.mMatrix[VY][VZ] * b.mV[VZ];
  418. vec.mV[VZ] = a.mMatrix[VZ][VX] * b.mV[VX] +
  419. a.mMatrix[VZ][VY] * b.mV[VY] +
  420. a.mMatrix[VZ][VZ] * b.mV[VZ];
  421. return vec;
  422. }
  423. #endif
  424. LLVector3 operator*(const LLVector3& a, const LLMatrix3& b)
  425. {
  426. // matrix operates "from the right" on row vector
  427. return LLVector3(a.mV[VX] * b.mMatrix[VX][VX] +
  428. a.mV[VY] * b.mMatrix[VY][VX] +
  429. a.mV[VZ] * b.mMatrix[VZ][VX],
  430. a.mV[VX] * b.mMatrix[VX][VY] +
  431. a.mV[VY] * b.mMatrix[VY][VY] +
  432. a.mV[VZ] * b.mMatrix[VZ][VY],
  433. a.mV[VX] * b.mMatrix[VX][VZ] +
  434. a.mV[VY] * b.mMatrix[VY][VZ] +
  435. a.mV[VZ] * b.mMatrix[VZ][VZ]);
  436. }
  437. LLVector3d operator*(const LLVector3d& a, const LLMatrix3& b)
  438. {
  439. // matrix operates "from the right" on row vector
  440. return LLVector3d(a.mdV[VX] * b.mMatrix[VX][VX] +
  441. a.mdV[VY] * b.mMatrix[VY][VX] +
  442. a.mdV[VZ] * b.mMatrix[VZ][VX],
  443. a.mdV[VX] * b.mMatrix[VX][VY] +
  444. a.mdV[VY] * b.mMatrix[VY][VY] +
  445. a.mdV[VZ] * b.mMatrix[VZ][VY],
  446. a.mdV[VX] * b.mMatrix[VX][VZ] +
  447. a.mdV[VY] * b.mMatrix[VY][VZ] +
  448. a.mdV[VZ] * b.mMatrix[VZ][VZ]);
  449. }
  450. bool operator==(const LLMatrix3& a, const LLMatrix3& b)
  451. {
  452. for (U32 i = 0; i < NUM_VALUES_IN_MAT3; ++i)
  453. {
  454. for (U32 j = 0; j < NUM_VALUES_IN_MAT3; ++j)
  455. {
  456. if (a.mMatrix[j][i] != b.mMatrix[j][i])
  457. {
  458. return false;
  459. }
  460. }
  461. }
  462. return true;
  463. }
  464. bool operator!=(const LLMatrix3& a, const LLMatrix3& b)
  465. {
  466. for (U32 i = 0; i < NUM_VALUES_IN_MAT3; ++i)
  467. {
  468. for (U32 j = 0; j < NUM_VALUES_IN_MAT3; ++j)
  469. {
  470. if (a.mMatrix[j][i] != b.mMatrix[j][i])
  471. {
  472. return true;
  473. }
  474. }
  475. }
  476. return false;
  477. }
  478. const LLMatrix3& operator*=(LLMatrix3& a, const LLMatrix3& b)
  479. {
  480. LLMatrix3 mat;
  481. for (U32 i = 0; i < NUM_VALUES_IN_MAT3; ++i)
  482. {
  483. for (U32 j = 0; j < NUM_VALUES_IN_MAT3; ++j)
  484. {
  485. mat.mMatrix[j][i] = a.mMatrix[j][0] * b.mMatrix[0][i] +
  486. a.mMatrix[j][1] * b.mMatrix[1][i] +
  487. a.mMatrix[j][2] * b.mMatrix[2][i];
  488. }
  489. }
  490. a = mat;
  491. return a;
  492. }
  493. const LLMatrix3& operator*=(LLMatrix3& a, F32 scalar)
  494. {
  495. for (U32 i = 0; i < NUM_VALUES_IN_MAT3; ++i)
  496. {
  497. for (U32 j = 0; j < NUM_VALUES_IN_MAT3; ++j)
  498. {
  499. a.mMatrix[i][j] *= scalar;
  500. }
  501. }
  502. return a;
  503. }
  504. std::ostream& operator<<(std::ostream& s, const LLMatrix3& a)
  505. {
  506. s << "{ "
  507. << a.mMatrix[VX][VX] << ", " << a.mMatrix[VX][VY] << ", "
  508. << a.mMatrix[VX][VZ] << "; " << a.mMatrix[VY][VX] << ", "
  509. << a.mMatrix[VY][VY] << ", " << a.mMatrix[VY][VZ] << "; "
  510. << a.mMatrix[VZ][VX] << ", " << a.mMatrix[VZ][VY] << ", "
  511. << a.mMatrix[VZ][VZ] << " }";
  512. return s;
  513. }