TransformPrimitive.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. /*
  2. * This source file is part of libRocket, the HTML/CSS Interface Middleware
  3. *
  4. * For the latest information, see http://www.librocket.com
  5. *
  6. * Copyright (c) 2014 Markus Schöngart
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. *
  26. */
  27. #include "precompiled.h"
  28. #include "../../Include/Rocket/Core/TransformPrimitive.h"
  29. #include <iostream>
  30. #include <unordered_map>
  31. namespace Rocket {
  32. namespace Core {
  33. namespace Transforms {
  34. static Vector3f Combine(const Vector3f& a, const Vector3f& b, float a_scale, float b_scale)
  35. {
  36. Vector3f result;
  37. result.x = a_scale * a.x + b_scale * b.x;
  38. result.y = a_scale * a.y + b_scale * b.y;
  39. result.z = a_scale * a.z + b_scale * b.z;
  40. return result;
  41. }
  42. // Interpolate two quaternions a, b with weight alpha [0, 1]
  43. static Vector4f QuaternionSlerp(const Vector4f& a, const Vector4f& b, float alpha)
  44. {
  45. using namespace Math;
  46. const float eps = 0.9995f;
  47. float dot = a.DotProduct(b);
  48. dot = Clamp(dot, -1.f, 1.f);
  49. if (dot > eps)
  50. return a;
  51. float theta = ACos(dot);
  52. float w = Sin(alpha * theta) / SquareRoot(1.f - dot * dot);
  53. float a_scale = Cos(alpha*theta) - dot * w;
  54. Vector4f result;
  55. for (int i = 0; i < 4; i++)
  56. {
  57. result[i] = a[i] * a_scale + b[i] * w;
  58. }
  59. return result;
  60. }
  61. NumericValue::NumericValue() noexcept
  62. : number(), unit(Property::UNKNOWN)
  63. {
  64. }
  65. NumericValue::NumericValue(float number, Property::Unit unit) noexcept
  66. : number(number), unit(unit)
  67. {
  68. }
  69. float NumericValue::Resolve(Element& e, float base) const noexcept
  70. {
  71. Property prop;
  72. prop.value = Variant(number);
  73. prop.unit = unit;
  74. return e.ResolveProperty(&prop, base);
  75. }
  76. float NumericValue::ResolveWidth(Element& e) const noexcept
  77. {
  78. if(unit & (Property::PX | Property::NUMBER)) return number;
  79. return Resolve(e, e.GetBox().GetSize(Box::BORDER).x);
  80. }
  81. float NumericValue::ResolveHeight(Element& e) const noexcept
  82. {
  83. if (unit & (Property::PX | Property::NUMBER)) return number;
  84. return Resolve(e, e.GetBox().GetSize(Box::BORDER).y);
  85. }
  86. float NumericValue::ResolveDepth(Element& e) const noexcept
  87. {
  88. if (unit & (Property::PX | Property::NUMBER)) return number;
  89. Vector2f size = e.GetBox().GetSize(Box::BORDER);
  90. return Resolve(e, Math::Max(size.x, size.y));
  91. }
  92. float NumericValue::ResolveAbsoluteUnit(Property::Unit base_unit) const noexcept
  93. {
  94. switch (base_unit)
  95. {
  96. case Property::RAD:
  97. {
  98. switch (unit)
  99. {
  100. case Property::NUMBER:
  101. case Property::DEG:
  102. return Math::DegreesToRadians(number);
  103. case Property::RAD:
  104. return number;
  105. case Property::PERCENT:
  106. return number * 0.01f * 2.0f * Math::ROCKET_PI;
  107. break;
  108. }
  109. }
  110. }
  111. return number;
  112. }
  113. String NumericValue::ToString() const noexcept
  114. {
  115. Property prop;
  116. prop.value = Variant(number);
  117. prop.unit = unit;
  118. return prop.ToString();
  119. }
  120. struct ResolveTransformVisitor
  121. {
  122. Matrix4f& m;
  123. Element& e;
  124. bool operator()(const Matrix2D& p)
  125. {
  126. m = Matrix4f::FromRows(
  127. Vector4f(p.values[0], p.values[2], 0, p.values[4]),
  128. Vector4f(p.values[1], p.values[3], 0, p.values[5]),
  129. Vector4f(0, 0, 1, 0),
  130. Vector4f(0, 0, 0, 1)
  131. );
  132. return true;
  133. }
  134. bool operator()(const Matrix3D& p)
  135. {
  136. m = Matrix4f::FromColumns(
  137. Vector4f(p.values[0], p.values[1], p.values[2], p.values[3]),
  138. Vector4f(p.values[4], p.values[5], p.values[6], p.values[7]),
  139. Vector4f(p.values[8], p.values[9], p.values[10], p.values[11]),
  140. Vector4f(p.values[12], p.values[13], p.values[14], p.values[15])
  141. );
  142. return true;
  143. }
  144. bool operator()(const TranslateX& p)
  145. {
  146. m = Matrix4f::TranslateX(p.values[0].ResolveWidth(e));
  147. return true;
  148. }
  149. bool operator()(const TranslateY& p)
  150. {
  151. m = Matrix4f::TranslateY(p.values[0].ResolveHeight(e));
  152. return true;
  153. }
  154. bool operator()(const TranslateZ& p)
  155. {
  156. m = Matrix4f::TranslateZ(p.values[0].ResolveDepth(e));
  157. return true;
  158. }
  159. bool operator()(const Translate2D& p)
  160. {
  161. m = Matrix4f::Translate(
  162. p.values[0].ResolveWidth(e),
  163. p.values[1].ResolveHeight(e),
  164. 0
  165. );
  166. return true;
  167. }
  168. bool operator()(const Translate3D& p)
  169. {
  170. m = Matrix4f::Translate(
  171. p.values[0].ResolveWidth(e),
  172. p.values[1].ResolveHeight(e),
  173. p.values[2].ResolveDepth(e)
  174. );
  175. return true;
  176. }
  177. bool operator()(const ScaleX& p)
  178. {
  179. m = Matrix4f::ScaleX(p.values[0]);
  180. return true;
  181. }
  182. bool operator()(const ScaleY& p)
  183. {
  184. m = Matrix4f::ScaleY(p.values[0]);
  185. return true;
  186. }
  187. bool operator()(const ScaleZ& p)
  188. {
  189. m = Matrix4f::ScaleZ(p.values[0]);
  190. return true;
  191. }
  192. bool operator()(const Scale2D& p)
  193. {
  194. m = Matrix4f::Scale(p.values[0], p.values[1], 1);
  195. return true;
  196. }
  197. bool operator()(const Scale3D& p)
  198. {
  199. m = Matrix4f::Scale(p.values[0], p.values[1], p.values[2]);
  200. return true;
  201. }
  202. bool operator()(const RotateX& p)
  203. {
  204. m = Matrix4f::RotateX(p.values[0]);
  205. return true;
  206. }
  207. bool operator()(const RotateY& p)
  208. {
  209. m = Matrix4f::RotateY(p.values[0]);
  210. return true;
  211. }
  212. bool operator()(const RotateZ& p)
  213. {
  214. m = Matrix4f::RotateZ(p.values[0]);
  215. return true;
  216. }
  217. bool operator()(const Rotate2D& p)
  218. {
  219. m = Matrix4f::RotateZ(p.values[0]);
  220. return true;
  221. }
  222. bool operator()(const Rotate3D& p)
  223. {
  224. m = Matrix4f::Rotate(Vector3f(p.values[0], p.values[1], p.values[2]), p.values[3]);
  225. return true;
  226. }
  227. bool operator()(const SkewX& p)
  228. {
  229. m = Matrix4f::SkewX(p.values[0]);
  230. return true;
  231. }
  232. bool operator()(const SkewY& p)
  233. {
  234. m = Matrix4f::SkewY(p.values[0]);
  235. return true;
  236. }
  237. bool operator()(const Skew2D& p)
  238. {
  239. m = Matrix4f::Skew(p.values[0], p.values[1]);
  240. return true;
  241. }
  242. bool operator()(const DecomposedMatrix4& p)
  243. {
  244. m = Matrix4f::Compose(p.translation, p.scale, p.skew, p.perspective, p.quaternion);
  245. return true;
  246. }
  247. bool operator()(const Perspective& p)
  248. {
  249. return false;
  250. }
  251. };
  252. bool Primitive::ResolveTransform(Matrix4f & m, Element & e) const noexcept
  253. {
  254. ResolveTransformVisitor visitor{ m, e };
  255. bool result = std::visit(visitor, primitive);
  256. return result;
  257. }
  258. bool Primitive::ResolvePerspective(float & p, Element & e) const noexcept
  259. {
  260. bool result = false;
  261. if (const Perspective* perspective = std::get_if<Perspective>(&primitive))
  262. {
  263. p = perspective->values[0].ResolveDepth(e);
  264. result = true;
  265. }
  266. return result;
  267. }
  268. struct SetIdentityVisitor
  269. {
  270. template <size_t N>
  271. void operator()(ResolvedPrimitive<N>& p)
  272. {
  273. for (auto& value : p.values)
  274. value = 0.0f;
  275. }
  276. template <size_t N>
  277. void operator()(UnresolvedPrimitive<N>& p)
  278. {
  279. for (auto& value : p.values)
  280. value.number = 0.0f;
  281. }
  282. void operator()(Matrix2D& p)
  283. {
  284. for (int i = 0; i < 6; i++)
  285. p.values[i] = ((i == 0 || i == 3) ? 1.0f : 0.0f);
  286. }
  287. void operator()(Matrix3D& p)
  288. {
  289. for (int i = 0; i < 16; i++)
  290. p.values[i] = ((i % 5) == 0 ? 1.0f : 0.0f);
  291. }
  292. void operator()(ScaleX& p)
  293. {
  294. p.values[0] = 1;
  295. }
  296. void operator()(ScaleY& p)
  297. {
  298. p.values[0] = 1;
  299. }
  300. void operator()(ScaleZ& p)
  301. {
  302. p.values[0] = 1;
  303. }
  304. void operator()(Scale2D& p)
  305. {
  306. p.values[0] = p.values[1] = 1;
  307. }
  308. void operator()(Scale3D& p)
  309. {
  310. p.values[0] = p.values[1] = p.values[2] = 1;
  311. }
  312. void operator()(DecomposedMatrix4& p)
  313. {
  314. p.perspective = Vector4f(0, 0, 0, 1);
  315. p.quaternion = Vector4f(0, 0, 0, 1);
  316. p.translation = Vector3f(0, 0, 0);
  317. p.scale = Vector3f(1, 1, 1);
  318. p.skew = Vector3f(0, 0, 0);
  319. }
  320. };
  321. void Primitive::SetIdentity() noexcept
  322. {
  323. std::visit(SetIdentityVisitor{}, primitive);
  324. }
  325. struct PrepareVisitor
  326. {
  327. Element& e;
  328. bool operator()(TranslateX& p)
  329. {
  330. p.values[0] = NumericValue{ p.values[0].ResolveWidth(e), Property::PX };
  331. return true;
  332. }
  333. bool operator()(TranslateY& p)
  334. {
  335. p.values[0] = NumericValue{ p.values[0].ResolveHeight(e), Property::PX };
  336. return true;
  337. }
  338. bool operator()(TranslateZ& p)
  339. {
  340. p.values[0] = NumericValue{ p.values[0].ResolveDepth(e), Property::PX };
  341. return true;
  342. }
  343. bool operator()(Translate2D& p)
  344. {
  345. p.values[0] = NumericValue{ p.values[0].ResolveWidth(e), Property::PX };
  346. p.values[1] = NumericValue{ p.values[1].ResolveHeight(e), Property::PX };
  347. return true;
  348. }
  349. bool operator()(Translate3D& p)
  350. {
  351. p.values[0] = NumericValue{ p.values[0].ResolveWidth(e), Property::PX };
  352. p.values[1] = NumericValue{ p.values[1].ResolveHeight(e), Property::PX };
  353. p.values[2] = NumericValue{ p.values[2].ResolveDepth(e), Property::PX };
  354. return true;
  355. }
  356. template <size_t N>
  357. bool operator()(ResolvedPrimitive<N>& p)
  358. {
  359. // No conversion needed for resolved transforms (with some exceptions below)
  360. return true;
  361. }
  362. bool operator()(DecomposedMatrix4& p)
  363. {
  364. return true;
  365. }
  366. bool operator()(Rotate3D& p)
  367. {
  368. // Rotate3D must be resolved to a full matrix for interpolation.
  369. // There is an exception in CSS specs when the two interpolating rotation vectors are in the same direction, but for simplicity we ignore this optimization.
  370. return false;
  371. }
  372. bool operator()(Matrix3D& p)
  373. {
  374. // Matrices must be decomposed for interpolatino
  375. return false;
  376. }
  377. bool operator()(Matrix2D& p)
  378. {
  379. // Matrix2D can also be optimized for interpolation, but for now we decompose it to a full DecomposedMatrix4
  380. return false;
  381. }
  382. bool operator()(Perspective& p)
  383. {
  384. // Perspective must be decomposed
  385. return false;
  386. }
  387. };
  388. bool Primitive::PrepareForInterpolation(Element & e) noexcept
  389. {
  390. return std::visit(PrepareVisitor{ e }, primitive);
  391. }
  392. enum class GenericType { None, Scale3D, Translate3D };
  393. struct GetGenericTypeVisitor
  394. {
  395. GenericType common_type = GenericType::None;
  396. GenericType operator()(const TranslateX& p) { return GenericType::Translate3D; }
  397. GenericType operator()(const TranslateY& p) { return GenericType::Translate3D; }
  398. GenericType operator()(const TranslateZ& p) { return GenericType::Translate3D; }
  399. GenericType operator()(const Translate2D& p) { return GenericType::Translate3D; }
  400. GenericType operator()(const ScaleX& p) { return GenericType::Scale3D; }
  401. GenericType operator()(const ScaleY& p) { return GenericType::Scale3D; }
  402. GenericType operator()(const ScaleZ& p) { return GenericType::Scale3D; }
  403. GenericType operator()(const Scale2D& p) { return GenericType::Scale3D; }
  404. template <typename T>
  405. GenericType operator()(const T& p) { return GenericType::None; }
  406. };
  407. struct ConvertToGenericTypeVisitor
  408. {
  409. PrimitiveVariant operator()(const TranslateX& p) { return Translate3D{ p.values[0], {0.0f, Property::PX}, {0.0f, Property::PX} }; }
  410. PrimitiveVariant operator()(const TranslateY& p) { return Translate3D{ {0.0f, Property::PX}, p.values[0], {0.0f, Property::PX} }; }
  411. PrimitiveVariant operator()(const TranslateZ& p) { return Translate3D{ {0.0f, Property::PX}, {0.0f, Property::PX}, p.values[0] }; }
  412. PrimitiveVariant operator()(const Translate2D& p) { return Translate3D{ p.values[0], p.values[1], {0.0f, Property::PX} }; }
  413. PrimitiveVariant operator()(const ScaleX& p) { return Scale3D{ p.values[0], 1.0f, 1.0f }; }
  414. PrimitiveVariant operator()(const ScaleY& p) { return Scale3D{ 1.0f, p.values[0], 1.0f }; }
  415. PrimitiveVariant operator()(const ScaleZ& p) { return Scale3D{ 1.0f, 1.0f, p.values[0] }; }
  416. PrimitiveVariant operator()(const Scale2D& p) { return Scale3D{ p.values[0], p.values[1], 1.0f }; }
  417. template <typename T>
  418. PrimitiveVariant operator()(const T& p) { ROCKET_ERROR; return p; }
  419. };
  420. bool Primitive::TryConvertToMatchingGenericType(Primitive & p0, Primitive & p1) noexcept
  421. {
  422. if (p0.primitive.index() == p1.primitive.index())
  423. return true;
  424. GenericType c0 = std::visit(GetGenericTypeVisitor{}, p0.primitive);
  425. GenericType c1 = std::visit(GetGenericTypeVisitor{}, p1.primitive);
  426. if (c0 == c1 && c0 != GenericType::None)
  427. {
  428. p0.primitive = std::visit(ConvertToGenericTypeVisitor{}, p0.primitive);
  429. p1.primitive = std::visit(ConvertToGenericTypeVisitor{}, p1.primitive);
  430. return true;
  431. }
  432. return false;
  433. }
  434. struct InterpolateVisitor
  435. {
  436. const PrimitiveVariant& other_variant;
  437. float alpha;
  438. template <size_t N>
  439. bool Interpolate(ResolvedPrimitive<N>& p0, const ResolvedPrimitive<N>& p1)
  440. {
  441. for (size_t i = 0; i < N; i++)
  442. p0.values[i] = p0.values[i] * (1.0f - alpha) + p1.values[i] * alpha;
  443. return true;
  444. }
  445. template <size_t N>
  446. bool Interpolate(UnresolvedPrimitive<N>& p0, const UnresolvedPrimitive<N>& p1)
  447. {
  448. // Assumes that the underlying units have been resolved (e.g. to pixels)
  449. for (size_t i = 0; i < N; i++)
  450. p0.values[i].number = p0.values[i].number*(1.0f - alpha) + p1.values[i].number * alpha;
  451. return true;
  452. }
  453. bool Interpolate(Rotate3D& p0, const Rotate3D& p1)
  454. {
  455. // Currently, we promote Rotate3D to decomposed matrices in PrepareForInterpolation(), thus, it is an error if we get here. Make sure primitives are prepared and decomposed as necessary.
  456. // We may change this later by assuming that the underlying direction vectors are equivalent (else, need to do full matrix interpolation)
  457. // If we change this later: p0.values[3] = p0.values[3] * (1.0f - alpha) + p1.values[3] * alpha;
  458. return false;
  459. }
  460. bool Interpolate(Matrix2D& p0, const Matrix2D& p1) { return false; /* Error if we get here, see PrepareForInterpolation() */ }
  461. bool Interpolate(Matrix3D& p0, const Matrix3D& p1) { return false; /* Error if we get here, see PrepareForInterpolation() */ }
  462. bool Interpolate(Perspective& p0, const Perspective& p1) { return false; /* Error if we get here, see PrepareForInterpolation() */ }
  463. bool Interpolate(DecomposedMatrix4& p0, const DecomposedMatrix4& p1)
  464. {
  465. p0.perspective = p0.perspective * (1.0f - alpha) + p1.perspective * alpha;
  466. p0.quaternion = QuaternionSlerp(p0.quaternion, p1.quaternion, alpha);
  467. p0.translation = p0.translation * (1.0f - alpha) + p1.translation * alpha;
  468. p0.scale = p0.scale* (1.0f - alpha) + p1.scale* alpha;
  469. p0.skew = p0.skew* (1.0f - alpha) + p1.skew* alpha;
  470. return true;
  471. }
  472. template <typename T>
  473. bool operator()(T& p0)
  474. {
  475. auto& p1 = std::get<T>(other_variant);
  476. return Interpolate(p0, p1);
  477. }
  478. };
  479. bool Primitive::InterpolateWith(const Primitive & other, float alpha) noexcept
  480. {
  481. if (primitive.index() != other.primitive.index())
  482. return false;
  483. bool result = std::visit(InterpolateVisitor{ other.primitive, alpha }, primitive);
  484. return result;
  485. }
  486. struct ToStringVisitor
  487. {
  488. template <typename T>
  489. String operator()(T& p0)
  490. {
  491. return p0.ToString();
  492. }
  493. };
  494. String Primitive::ToString() const noexcept
  495. {
  496. String result = std::visit(ToStringVisitor{}, primitive);
  497. return result;
  498. }
  499. bool DecomposedMatrix4::Decompose(const Matrix4f & m)
  500. {
  501. // Follows the procedure given in https://drafts.csswg.org/css-transforms-2/#interpolation-of-3d-matrices
  502. const float eps = 0.0005f;
  503. if (Math::AbsoluteValue(m[3][3]) < eps)
  504. return false;
  505. // Perspective matrix
  506. Matrix4f p = m;
  507. for (int i = 0; i < 3; i++)
  508. p[i][3] = 0;
  509. p[3][3] = 1;
  510. if (Math::AbsoluteValue(p.Determinant()) < eps)
  511. return false;
  512. if (m[0][3] != 0 || m[1][3] != 0 || m[2][3] != 0)
  513. {
  514. auto rhs = m.GetColumn(3);
  515. Matrix4f p_inv = p;
  516. if (!p_inv.Invert())
  517. return false;
  518. auto& p_inv_trans = p.Transpose();
  519. perspective = p_inv_trans * rhs;
  520. }
  521. else
  522. {
  523. perspective[0] = perspective[1] = perspective[2] = 0;
  524. perspective[3] = 1;
  525. }
  526. for (int i = 0; i < 3; i++)
  527. translation[i] = m[3][i];
  528. Vector3f row[3];
  529. for (int i = 0; i < 3; i++)
  530. {
  531. row[i][0] = m[i][0];
  532. row[i][1] = m[i][1];
  533. row[i][2] = m[i][2];
  534. }
  535. scale[0] = row[0].Magnitude();
  536. row[0] = row[0].Normalise();
  537. skew[0] = row[0].DotProduct(row[1]);
  538. row[1] = Combine(row[1], row[0], 1, -skew[0]);
  539. scale[1] = row[1].Magnitude();
  540. row[1] = row[1].Normalise();
  541. skew[0] /= scale[1];
  542. skew[1] = row[0].DotProduct(row[2]);
  543. row[2] = Combine(row[2], row[0], 1, -skew[1]);
  544. skew[2] = row[1].DotProduct(row[2]);
  545. row[2] = Combine(row[2], row[1], 1, -skew[2]);
  546. scale[2] = row[2].Magnitude();
  547. row[2] = row[2].Normalise();
  548. skew[1] /= scale[2];
  549. skew[2] /= scale[2];
  550. // Check if we need to flip coordinate system
  551. auto pdum3 = row[1].CrossProduct(row[2]);
  552. if (row[0].DotProduct(pdum3) < 0.0f)
  553. {
  554. for (int i = 0; i < 3; i++)
  555. {
  556. scale[i] *= -1.f;
  557. row[i] *= -1.f;
  558. }
  559. }
  560. quaternion[0] = 0.5f * Math::SquareRoot(Math::Max(1.f + row[0][0] - row[1][1] - row[2][2], 0.0f));
  561. quaternion[1] = 0.5f * Math::SquareRoot(Math::Max(1.f - row[0][0] + row[1][1] - row[2][2], 0.0f));
  562. quaternion[2] = 0.5f * Math::SquareRoot(Math::Max(1.f - row[0][0] - row[1][1] + row[2][2], 0.0f));
  563. quaternion[3] = 0.5f * Math::SquareRoot(Math::Max(1.f + row[0][0] + row[1][1] + row[2][2], 0.0f));
  564. if (row[2][1] > row[1][2])
  565. quaternion[0] *= -1.f;
  566. if (row[0][2] > row[2][0])
  567. quaternion[1] *= -1.f;
  568. if (row[1][0] > row[0][1])
  569. quaternion[2] *= -1.f;
  570. return true;
  571. }
  572. }
  573. }
  574. }