TransformPrimitive.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999
  1. /*
  2. * This source file is part of RmlUi, the HTML/CSS Interface Middleware
  3. *
  4. * For the latest information, see http://github.com/mikke89/RmlUi
  5. *
  6. * Copyright (c) 2014 Markus Schöngart
  7. * Copyright (c) 2019 The RmlUi Team, and contributors
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. *
  27. */
  28. #include "../../Include/RmlUi/Core/TransformPrimitive.h"
  29. #include "../../Include/RmlUi/Core/Element.h"
  30. #include "../../Include/RmlUi/Core/TypeConverter.h"
  31. namespace Rml {
  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::ResolveLengthPercentage(Element& e, float base) const noexcept
  70. {
  71. Property prop;
  72. prop.value = Variant(number);
  73. prop.unit = unit;
  74. return e.ResolveNumericProperty(&prop, base);
  75. }
  76. float NumericValue::ResolveWidth(Element& e) const noexcept
  77. {
  78. if(unit & (Property::PX | Property::NUMBER)) return number;
  79. return ResolveLengthPercentage(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 ResolveLengthPercentage(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 ResolveLengthPercentage(e, Math::Max(size.x, size.y));
  91. }
  92. float NumericValue::ResolveAbsoluteUnit(Property::Unit base_unit) const noexcept
  93. {
  94. if(base_unit == Property::RAD)
  95. {
  96. switch (unit)
  97. {
  98. case Property::NUMBER:
  99. case Property::DEG:
  100. return Math::DegreesToRadians(number);
  101. case Property::RAD:
  102. return number;
  103. case Property::PERCENT:
  104. return number * 0.01f * 2.0f * Math::RMLUI_PI;
  105. default:
  106. break;
  107. }
  108. }
  109. return number;
  110. }
  111. String NumericValue::ToString() const noexcept
  112. {
  113. Property prop;
  114. prop.value = Variant(number);
  115. prop.unit = unit;
  116. return prop.ToString();
  117. }
  118. struct ResolveTransformVisitor
  119. {
  120. Matrix4f& m;
  121. Element& e;
  122. bool operator()(const Matrix2D& p)
  123. {
  124. m = Matrix4f::FromRows(
  125. Vector4f(p.values[0], p.values[2], 0, p.values[4]),
  126. Vector4f(p.values[1], p.values[3], 0, p.values[5]),
  127. Vector4f(0, 0, 1, 0),
  128. Vector4f(0, 0, 0, 1)
  129. );
  130. return true;
  131. }
  132. bool operator()(const Matrix3D& p)
  133. {
  134. m = Matrix4f::FromColumns(
  135. Vector4f(p.values[0], p.values[1], p.values[2], p.values[3]),
  136. Vector4f(p.values[4], p.values[5], p.values[6], p.values[7]),
  137. Vector4f(p.values[8], p.values[9], p.values[10], p.values[11]),
  138. Vector4f(p.values[12], p.values[13], p.values[14], p.values[15])
  139. );
  140. return true;
  141. }
  142. bool operator()(const TranslateX& p)
  143. {
  144. m = Matrix4f::TranslateX(p.values[0].ResolveWidth(e));
  145. return true;
  146. }
  147. bool operator()(const TranslateY& p)
  148. {
  149. m = Matrix4f::TranslateY(p.values[0].ResolveHeight(e));
  150. return true;
  151. }
  152. bool operator()(const TranslateZ& p)
  153. {
  154. m = Matrix4f::TranslateZ(p.values[0].ResolveDepth(e));
  155. return true;
  156. }
  157. bool operator()(const Translate2D& p)
  158. {
  159. m = Matrix4f::Translate(
  160. p.values[0].ResolveWidth(e),
  161. p.values[1].ResolveHeight(e),
  162. 0
  163. );
  164. return true;
  165. }
  166. bool operator()(const Translate3D& p)
  167. {
  168. m = Matrix4f::Translate(
  169. p.values[0].ResolveWidth(e),
  170. p.values[1].ResolveHeight(e),
  171. p.values[2].ResolveDepth(e)
  172. );
  173. return true;
  174. }
  175. bool operator()(const ScaleX& p)
  176. {
  177. m = Matrix4f::ScaleX(p.values[0]);
  178. return true;
  179. }
  180. bool operator()(const ScaleY& p)
  181. {
  182. m = Matrix4f::ScaleY(p.values[0]);
  183. return true;
  184. }
  185. bool operator()(const ScaleZ& p)
  186. {
  187. m = Matrix4f::ScaleZ(p.values[0]);
  188. return true;
  189. }
  190. bool operator()(const Scale2D& p)
  191. {
  192. m = Matrix4f::Scale(p.values[0], p.values[1], 1);
  193. return true;
  194. }
  195. bool operator()(const Scale3D& p)
  196. {
  197. m = Matrix4f::Scale(p.values[0], p.values[1], p.values[2]);
  198. return true;
  199. }
  200. bool operator()(const RotateX& p)
  201. {
  202. m = Matrix4f::RotateX(p.values[0]);
  203. return true;
  204. }
  205. bool operator()(const RotateY& p)
  206. {
  207. m = Matrix4f::RotateY(p.values[0]);
  208. return true;
  209. }
  210. bool operator()(const RotateZ& p)
  211. {
  212. m = Matrix4f::RotateZ(p.values[0]);
  213. return true;
  214. }
  215. bool operator()(const Rotate2D& p)
  216. {
  217. m = Matrix4f::RotateZ(p.values[0]);
  218. return true;
  219. }
  220. bool operator()(const Rotate3D& p)
  221. {
  222. m = Matrix4f::Rotate(Vector3f(p.values[0], p.values[1], p.values[2]), p.values[3]);
  223. return true;
  224. }
  225. bool operator()(const SkewX& p)
  226. {
  227. m = Matrix4f::SkewX(p.values[0]);
  228. return true;
  229. }
  230. bool operator()(const SkewY& p)
  231. {
  232. m = Matrix4f::SkewY(p.values[0]);
  233. return true;
  234. }
  235. bool operator()(const Skew2D& p)
  236. {
  237. m = Matrix4f::Skew(p.values[0], p.values[1]);
  238. return true;
  239. }
  240. bool operator()(const DecomposedMatrix4& p)
  241. {
  242. m = Matrix4f::Compose(p.translation, p.scale, p.skew, p.perspective, p.quaternion);
  243. return true;
  244. }
  245. bool operator()(const Perspective& p)
  246. {
  247. m = Matrix4f::Perspective(p.values[0].ResolveDepth(e));
  248. return true;
  249. }
  250. bool run(const PrimitiveVariant& primitive)
  251. {
  252. switch (primitive.type)
  253. {
  254. case PrimitiveVariant::MATRIX2D: return this->operator()(primitive.matrix_2d);
  255. case PrimitiveVariant::MATRIX3D: return this->operator()(primitive.matrix_3d);
  256. case PrimitiveVariant::TRANSLATEX: return this->operator()(primitive.translate_x);
  257. case PrimitiveVariant::TRANSLATEY: return this->operator()(primitive.translate_y);
  258. case PrimitiveVariant::TRANSLATEZ: return this->operator()(primitive.translate_z);
  259. case PrimitiveVariant::TRANSLATE2D: return this->operator()(primitive.translate_2d);
  260. case PrimitiveVariant::TRANSLATE3D: return this->operator()(primitive.translate_3d);
  261. case PrimitiveVariant::SCALEX: return this->operator()(primitive.scale_x);
  262. case PrimitiveVariant::SCALEY: return this->operator()(primitive.scale_y);
  263. case PrimitiveVariant::SCALEZ: return this->operator()(primitive.scale_z);
  264. case PrimitiveVariant::SCALE2D: return this->operator()(primitive.scale_2d);
  265. case PrimitiveVariant::SCALE3D: return this->operator()(primitive.scale_3d);
  266. case PrimitiveVariant::ROTATEX: return this->operator()(primitive.rotate_x);
  267. case PrimitiveVariant::ROTATEY: return this->operator()(primitive.rotate_y);
  268. case PrimitiveVariant::ROTATEZ: return this->operator()(primitive.rotate_z);
  269. case PrimitiveVariant::ROTATE2D: return this->operator()(primitive.rotate_2d);
  270. case PrimitiveVariant::ROTATE3D: return this->operator()(primitive.rotate_3d);
  271. case PrimitiveVariant::SKEWX: return this->operator()(primitive.skew_x);
  272. case PrimitiveVariant::SKEWY: return this->operator()(primitive.skew_y);
  273. case PrimitiveVariant::SKEW2D: return this->operator()(primitive.skew_2d);
  274. case PrimitiveVariant::PERSPECTIVE: return this->operator()(primitive.perspective);
  275. case PrimitiveVariant::DECOMPOSEDMATRIX4: return this->operator()(primitive.decomposed_matrix_4);
  276. default:
  277. break;
  278. }
  279. RMLUI_ASSERT(false);
  280. return false;
  281. }
  282. };
  283. bool Primitive::ResolveTransform(Matrix4f & m, Element & e) const noexcept
  284. {
  285. ResolveTransformVisitor visitor{ m, e };
  286. bool result = visitor.run(primitive);
  287. return result;
  288. }
  289. struct SetIdentityVisitor
  290. {
  291. template <size_t N>
  292. void operator()(ResolvedPrimitive<N>& p)
  293. {
  294. for (auto& value : p.values)
  295. value = 0.0f;
  296. }
  297. template <size_t N>
  298. void operator()(UnresolvedPrimitive<N>& p)
  299. {
  300. for (auto& value : p.values)
  301. value.number = 0.0f;
  302. }
  303. void operator()(Matrix2D& p)
  304. {
  305. for (int i = 0; i < 6; i++)
  306. p.values[i] = ((i == 0 || i == 3) ? 1.0f : 0.0f);
  307. }
  308. void operator()(Matrix3D& p)
  309. {
  310. for (int i = 0; i < 16; i++)
  311. p.values[i] = ((i % 5) == 0 ? 1.0f : 0.0f);
  312. }
  313. void operator()(ScaleX& p)
  314. {
  315. p.values[0] = 1;
  316. }
  317. void operator()(ScaleY& p)
  318. {
  319. p.values[0] = 1;
  320. }
  321. void operator()(ScaleZ& p)
  322. {
  323. p.values[0] = 1;
  324. }
  325. void operator()(Scale2D& p)
  326. {
  327. p.values[0] = p.values[1] = 1;
  328. }
  329. void operator()(Scale3D& p)
  330. {
  331. p.values[0] = p.values[1] = p.values[2] = 1;
  332. }
  333. void operator()(DecomposedMatrix4& p)
  334. {
  335. p.perspective = Vector4f(0, 0, 0, 1);
  336. p.quaternion = Vector4f(0, 0, 0, 1);
  337. p.translation = Vector3f(0, 0, 0);
  338. p.scale = Vector3f(1, 1, 1);
  339. p.skew = Vector3f(0, 0, 0);
  340. }
  341. void run(PrimitiveVariant& primitive)
  342. {
  343. switch (primitive.type)
  344. {
  345. case PrimitiveVariant::MATRIX2D: this->operator()(primitive.matrix_2d); break;
  346. case PrimitiveVariant::MATRIX3D: this->operator()(primitive.matrix_3d); break;
  347. case PrimitiveVariant::TRANSLATEX: this->operator()(primitive.translate_x); break;
  348. case PrimitiveVariant::TRANSLATEY: this->operator()(primitive.translate_y); break;
  349. case PrimitiveVariant::TRANSLATEZ: this->operator()(primitive.translate_z); break;
  350. case PrimitiveVariant::TRANSLATE2D: this->operator()(primitive.translate_2d); break;
  351. case PrimitiveVariant::TRANSLATE3D: this->operator()(primitive.translate_3d); break;
  352. case PrimitiveVariant::SCALEX: this->operator()(primitive.scale_x); break;
  353. case PrimitiveVariant::SCALEY: this->operator()(primitive.scale_y); break;
  354. case PrimitiveVariant::SCALEZ: this->operator()(primitive.scale_z); break;
  355. case PrimitiveVariant::SCALE2D: this->operator()(primitive.scale_2d); break;
  356. case PrimitiveVariant::SCALE3D: this->operator()(primitive.scale_3d); break;
  357. case PrimitiveVariant::ROTATEX: this->operator()(primitive.rotate_x); break;
  358. case PrimitiveVariant::ROTATEY: this->operator()(primitive.rotate_y); break;
  359. case PrimitiveVariant::ROTATEZ: this->operator()(primitive.rotate_z); break;
  360. case PrimitiveVariant::ROTATE2D: this->operator()(primitive.rotate_2d); break;
  361. case PrimitiveVariant::ROTATE3D: this->operator()(primitive.rotate_3d); break;
  362. case PrimitiveVariant::SKEWX: this->operator()(primitive.skew_x); break;
  363. case PrimitiveVariant::SKEWY: this->operator()(primitive.skew_y); break;
  364. case PrimitiveVariant::SKEW2D: this->operator()(primitive.skew_2d); break;
  365. case PrimitiveVariant::PERSPECTIVE: this->operator()(primitive.perspective); break;
  366. case PrimitiveVariant::DECOMPOSEDMATRIX4: this->operator()(primitive.decomposed_matrix_4); break;
  367. default:
  368. RMLUI_ASSERT(false);
  369. break;
  370. }
  371. }
  372. };
  373. void Primitive::SetIdentity() noexcept
  374. {
  375. SetIdentityVisitor{}.run(primitive);
  376. }
  377. struct PrepareVisitor
  378. {
  379. Element& e;
  380. bool operator()(TranslateX& p)
  381. {
  382. p.values[0] = NumericValue{ p.values[0].ResolveWidth(e), Property::PX };
  383. return true;
  384. }
  385. bool operator()(TranslateY& p)
  386. {
  387. p.values[0] = NumericValue{ p.values[0].ResolveHeight(e), Property::PX };
  388. return true;
  389. }
  390. bool operator()(TranslateZ& p)
  391. {
  392. p.values[0] = NumericValue{ p.values[0].ResolveDepth(e), Property::PX };
  393. return true;
  394. }
  395. bool operator()(Translate2D& p)
  396. {
  397. p.values[0] = NumericValue{ p.values[0].ResolveWidth(e), Property::PX };
  398. p.values[1] = NumericValue{ p.values[1].ResolveHeight(e), Property::PX };
  399. return true;
  400. }
  401. bool operator()(Translate3D& p)
  402. {
  403. p.values[0] = NumericValue{ p.values[0].ResolveWidth(e), Property::PX };
  404. p.values[1] = NumericValue{ p.values[1].ResolveHeight(e), Property::PX };
  405. p.values[2] = NumericValue{ p.values[2].ResolveDepth(e), Property::PX };
  406. return true;
  407. }
  408. template <size_t N>
  409. bool operator()(ResolvedPrimitive<N>& /*p*/)
  410. {
  411. // No conversion needed for resolved transforms (with some exceptions below)
  412. return true;
  413. }
  414. bool operator()(DecomposedMatrix4& /*p*/)
  415. {
  416. return true;
  417. }
  418. bool operator()(Rotate3D& p)
  419. {
  420. // Rotate3D can be interpolated if and only if their rotation axes point in the same direction.
  421. // We normalize the rotation vector here for easy comparison, and return true here. Later on we make the
  422. // pair-wise check in 'TryConvertToMatchingGenericType' to see if we need to decompose.
  423. Vector3f vec = Vector3f(p.values[0], p.values[1], p.values[2]).Normalise();
  424. p.values[0] = vec.x;
  425. p.values[1] = vec.y;
  426. p.values[2] = vec.z;
  427. return true;
  428. }
  429. bool operator()(Matrix3D& /*p*/)
  430. {
  431. // Matrices must be decomposed for interpolation
  432. return false;
  433. }
  434. bool operator()(Matrix2D& /*p*/)
  435. {
  436. // Matrix2D can also be optimized for interpolation, but for now we decompose it to a full DecomposedMatrix4
  437. return false;
  438. }
  439. bool operator()(Perspective& /*p*/)
  440. {
  441. // Perspective must be decomposed
  442. return false;
  443. }
  444. bool run(PrimitiveVariant& primitive)
  445. {
  446. switch (primitive.type)
  447. {
  448. case PrimitiveVariant::MATRIX2D: return this->operator()(primitive.matrix_2d);
  449. case PrimitiveVariant::MATRIX3D: return this->operator()(primitive.matrix_3d);
  450. case PrimitiveVariant::TRANSLATEX: return this->operator()(primitive.translate_x);
  451. case PrimitiveVariant::TRANSLATEY: return this->operator()(primitive.translate_y);
  452. case PrimitiveVariant::TRANSLATEZ: return this->operator()(primitive.translate_z);
  453. case PrimitiveVariant::TRANSLATE2D: return this->operator()(primitive.translate_2d);
  454. case PrimitiveVariant::TRANSLATE3D: return this->operator()(primitive.translate_3d);
  455. case PrimitiveVariant::SCALEX: return this->operator()(primitive.scale_x);
  456. case PrimitiveVariant::SCALEY: return this->operator()(primitive.scale_y);
  457. case PrimitiveVariant::SCALEZ: return this->operator()(primitive.scale_z);
  458. case PrimitiveVariant::SCALE2D: return this->operator()(primitive.scale_2d);
  459. case PrimitiveVariant::SCALE3D: return this->operator()(primitive.scale_3d);
  460. case PrimitiveVariant::ROTATEX: return this->operator()(primitive.rotate_x);
  461. case PrimitiveVariant::ROTATEY: return this->operator()(primitive.rotate_y);
  462. case PrimitiveVariant::ROTATEZ: return this->operator()(primitive.rotate_z);
  463. case PrimitiveVariant::ROTATE2D: return this->operator()(primitive.rotate_2d);
  464. case PrimitiveVariant::ROTATE3D: return this->operator()(primitive.rotate_3d);
  465. case PrimitiveVariant::SKEWX: return this->operator()(primitive.skew_x);
  466. case PrimitiveVariant::SKEWY: return this->operator()(primitive.skew_y);
  467. case PrimitiveVariant::SKEW2D: return this->operator()(primitive.skew_2d);
  468. case PrimitiveVariant::PERSPECTIVE: return this->operator()(primitive.perspective);
  469. case PrimitiveVariant::DECOMPOSEDMATRIX4: return this->operator()(primitive.decomposed_matrix_4);
  470. default:
  471. break;
  472. }
  473. RMLUI_ASSERT(false);
  474. return false;
  475. }
  476. };
  477. bool Primitive::PrepareForInterpolation(Element & e) noexcept
  478. {
  479. return PrepareVisitor{ e }.run(primitive);
  480. }
  481. enum class GenericType { None, Scale3D, Translate3D, Rotate3D };
  482. struct GetGenericTypeVisitor
  483. {
  484. GenericType run(const PrimitiveVariant& primitive)
  485. {
  486. switch (primitive.type)
  487. {
  488. case PrimitiveVariant::TRANSLATEX: return GenericType::Translate3D;
  489. case PrimitiveVariant::TRANSLATEY: return GenericType::Translate3D;
  490. case PrimitiveVariant::TRANSLATEZ: return GenericType::Translate3D;
  491. case PrimitiveVariant::TRANSLATE2D: return GenericType::Translate3D;
  492. case PrimitiveVariant::TRANSLATE3D: return GenericType::Translate3D;
  493. case PrimitiveVariant::SCALEX: return GenericType::Scale3D;
  494. case PrimitiveVariant::SCALEY: return GenericType::Scale3D;
  495. case PrimitiveVariant::SCALEZ: return GenericType::Scale3D;
  496. case PrimitiveVariant::SCALE2D: return GenericType::Scale3D;
  497. case PrimitiveVariant::SCALE3D: return GenericType::Scale3D;
  498. case PrimitiveVariant::ROTATEX: return GenericType::Rotate3D;
  499. case PrimitiveVariant::ROTATEY: return GenericType::Rotate3D;
  500. case PrimitiveVariant::ROTATEZ: return GenericType::Rotate3D;
  501. case PrimitiveVariant::ROTATE2D: return GenericType::Rotate3D;
  502. case PrimitiveVariant::ROTATE3D: return GenericType::Rotate3D;
  503. default:
  504. break;
  505. }
  506. return GenericType::None;
  507. }
  508. };
  509. struct ConvertToGenericTypeVisitor
  510. {
  511. Translate3D operator()(const TranslateX& p) { return Translate3D{ p.values[0], {0.0f, Property::PX}, {0.0f, Property::PX} }; }
  512. Translate3D operator()(const TranslateY& p) { return Translate3D{ {0.0f, Property::PX}, p.values[0], {0.0f, Property::PX} }; }
  513. Translate3D operator()(const TranslateZ& p) { return Translate3D{ {0.0f, Property::PX}, {0.0f, Property::PX}, p.values[0] }; }
  514. Translate3D operator()(const Translate2D& p) { return Translate3D{ p.values[0], p.values[1], {0.0f, Property::PX} }; }
  515. Scale3D operator()(const ScaleX& p) { return Scale3D{ p.values[0], 1.0f, 1.0f }; }
  516. Scale3D operator()(const ScaleY& p) { return Scale3D{ 1.0f, p.values[0], 1.0f }; }
  517. Scale3D operator()(const ScaleZ& p) { return Scale3D{ 1.0f, 1.0f, p.values[0] }; }
  518. Scale3D operator()(const Scale2D& p) { return Scale3D{ p.values[0], p.values[1], 1.0f }; }
  519. Rotate3D operator()(const RotateX& p) { return Rotate3D{ 1, 0, 0, p.values[0], Property::RAD }; }
  520. Rotate3D operator()(const RotateY& p) { return Rotate3D{ 0, 1, 0, p.values[0], Property::RAD }; }
  521. Rotate3D operator()(const RotateZ& p) { return Rotate3D{ 0, 0, 1, p.values[0], Property::RAD }; }
  522. Rotate3D operator()(const Rotate2D& p) { return Rotate3D{ 0, 0, 1, p.values[0], Property::RAD }; }
  523. template <typename T>
  524. PrimitiveVariant operator()(const T& p) { RMLUI_ERROR; return p; }
  525. PrimitiveVariant run(const PrimitiveVariant& primitive)
  526. {
  527. PrimitiveVariant result = primitive;
  528. switch (primitive.type)
  529. {
  530. case PrimitiveVariant::TRANSLATEX: result.type = PrimitiveVariant::TRANSLATE3D; result.translate_3d = this->operator()(primitive.translate_x); break;
  531. case PrimitiveVariant::TRANSLATEY: result.type = PrimitiveVariant::TRANSLATE3D; result.translate_3d = this->operator()(primitive.translate_y); break;
  532. case PrimitiveVariant::TRANSLATEZ: result.type = PrimitiveVariant::TRANSLATE3D; result.translate_3d = this->operator()(primitive.translate_z); break;
  533. case PrimitiveVariant::TRANSLATE2D: result.type = PrimitiveVariant::TRANSLATE3D; result.translate_3d = this->operator()(primitive.translate_2d); break;
  534. case PrimitiveVariant::TRANSLATE3D: break;
  535. case PrimitiveVariant::SCALEX: result.type = PrimitiveVariant::SCALE3D; result.scale_3d = this->operator()(primitive.scale_x); break;
  536. case PrimitiveVariant::SCALEY: result.type = PrimitiveVariant::SCALE3D; result.scale_3d = this->operator()(primitive.scale_y); break;
  537. case PrimitiveVariant::SCALEZ: result.type = PrimitiveVariant::SCALE3D; result.scale_3d = this->operator()(primitive.scale_z); break;
  538. case PrimitiveVariant::SCALE2D: result.type = PrimitiveVariant::SCALE3D; result.scale_3d = this->operator()(primitive.scale_2d); break;
  539. case PrimitiveVariant::SCALE3D: break;
  540. case PrimitiveVariant::ROTATEX: result.type = PrimitiveVariant::ROTATE3D; result.rotate_3d = this->operator()(primitive.rotate_x); break;
  541. case PrimitiveVariant::ROTATEY: result.type = PrimitiveVariant::ROTATE3D; result.rotate_3d = this->operator()(primitive.rotate_y); break;
  542. case PrimitiveVariant::ROTATEZ: result.type = PrimitiveVariant::ROTATE3D; result.rotate_3d = this->operator()(primitive.rotate_z); break;
  543. case PrimitiveVariant::ROTATE2D: result.type = PrimitiveVariant::ROTATE3D; result.rotate_3d = this->operator()(primitive.rotate_2d); break;
  544. case PrimitiveVariant::ROTATE3D: break;
  545. default:
  546. RMLUI_ASSERT(false);
  547. break;
  548. }
  549. return result;
  550. }
  551. };
  552. static bool CanInterpolateRotate3D(const Rotate3D& p0, const Rotate3D& p1)
  553. {
  554. // Rotate3D can only be interpolated if and only if their rotation axes point in the same direction.
  555. // Assumes each rotation axis has already been normalized.
  556. auto& v0 = p0.values;
  557. auto& v1 = p1.values;
  558. return v0[0] == v1[0] && v0[1] == v1[1] && v0[2] == v1[2];
  559. }
  560. bool Primitive::TryConvertToMatchingGenericType(Primitive & p0, Primitive & p1) noexcept
  561. {
  562. if (p0.primitive.type == p1.primitive.type)
  563. {
  564. if(p0.primitive.type == PrimitiveVariant::ROTATE3D && !CanInterpolateRotate3D(p0.primitive.rotate_3d, p1.primitive.rotate_3d))
  565. return false;
  566. return true;
  567. }
  568. GenericType c0 = GetGenericTypeVisitor{}.run(p0.primitive);
  569. GenericType c1 = GetGenericTypeVisitor{}.run(p1.primitive);
  570. if (c0 == c1 && c0 != GenericType::None)
  571. {
  572. PrimitiveVariant new_p0 = ConvertToGenericTypeVisitor{}.run(p0.primitive);
  573. PrimitiveVariant new_p1 = ConvertToGenericTypeVisitor{}.run(p1.primitive);
  574. RMLUI_ASSERT(new_p0.type == new_p1.type);
  575. if (new_p0.type == PrimitiveVariant::ROTATE3D && !CanInterpolateRotate3D(new_p0.rotate_3d, new_p1.rotate_3d))
  576. return false;
  577. p0.primitive = new_p0;
  578. p1.primitive = new_p1;
  579. return true;
  580. }
  581. return false;
  582. }
  583. struct InterpolateVisitor
  584. {
  585. const PrimitiveVariant& other_variant;
  586. float alpha;
  587. template <size_t N>
  588. bool Interpolate(ResolvedPrimitive<N>& p0, const ResolvedPrimitive<N>& p1)
  589. {
  590. for (size_t i = 0; i < N; i++)
  591. p0.values[i] = p0.values[i] * (1.0f - alpha) + p1.values[i] * alpha;
  592. return true;
  593. }
  594. template <size_t N>
  595. bool Interpolate(UnresolvedPrimitive<N>& p0, const UnresolvedPrimitive<N>& p1)
  596. {
  597. // Assumes that the underlying units have been resolved (e.g. to pixels)
  598. for (size_t i = 0; i < N; i++)
  599. p0.values[i].number = p0.values[i].number*(1.0f - alpha) + p1.values[i].number * alpha;
  600. return true;
  601. }
  602. bool Interpolate(Rotate3D& p0, const Rotate3D& p1)
  603. {
  604. RMLUI_ASSERT(CanInterpolateRotate3D(p0, p1));
  605. // We can only interpolate rotate3d if their rotation axes align. That should be the case if we get here,
  606. // otherwise the generic type matching should decompose them. Thus, we only need to interpolate
  607. // the angle value here.
  608. p0.values[3] = p0.values[3] * (1.0f - alpha) + p1.values[3] * alpha;
  609. return true;
  610. }
  611. bool Interpolate(Matrix2D& /*p0*/, const Matrix2D& /*p1*/) { return false; /* Error if we get here, see PrepareForInterpolation() */ }
  612. bool Interpolate(Matrix3D& /*p0*/, const Matrix3D& /*p1*/) { return false; /* Error if we get here, see PrepareForInterpolation() */ }
  613. bool Interpolate(Perspective& /*p0*/, const Perspective& /*p1*/) { return false; /* Error if we get here, see PrepareForInterpolation() */ }
  614. bool Interpolate(DecomposedMatrix4& p0, const DecomposedMatrix4& p1)
  615. {
  616. p0.perspective = p0.perspective * (1.0f - alpha) + p1.perspective * alpha;
  617. p0.quaternion = QuaternionSlerp(p0.quaternion, p1.quaternion, alpha);
  618. p0.translation = p0.translation * (1.0f - alpha) + p1.translation * alpha;
  619. p0.scale = p0.scale* (1.0f - alpha) + p1.scale* alpha;
  620. p0.skew = p0.skew* (1.0f - alpha) + p1.skew* alpha;
  621. return true;
  622. }
  623. bool run(PrimitiveVariant& variant)
  624. {
  625. RMLUI_ASSERT(variant.type == other_variant.type);
  626. switch (variant.type)
  627. {
  628. case PrimitiveVariant::MATRIX2D: return Interpolate(variant.matrix_2d, other_variant.matrix_2d);
  629. case PrimitiveVariant::MATRIX3D: return Interpolate(variant.matrix_3d, other_variant.matrix_3d);
  630. case PrimitiveVariant::TRANSLATEX: return Interpolate(variant.translate_x, other_variant.translate_x);
  631. case PrimitiveVariant::TRANSLATEY: return Interpolate(variant.translate_y, other_variant.translate_y);
  632. case PrimitiveVariant::TRANSLATEZ: return Interpolate(variant.translate_z, other_variant.translate_z);
  633. case PrimitiveVariant::TRANSLATE2D: return Interpolate(variant.translate_2d, other_variant.translate_2d);
  634. case PrimitiveVariant::TRANSLATE3D: return Interpolate(variant.translate_3d, other_variant.translate_3d);
  635. case PrimitiveVariant::SCALEX: return Interpolate(variant.scale_x, other_variant.scale_x);
  636. case PrimitiveVariant::SCALEY: return Interpolate(variant.scale_y, other_variant.scale_y);
  637. case PrimitiveVariant::SCALEZ: return Interpolate(variant.scale_z, other_variant.scale_z);
  638. case PrimitiveVariant::SCALE2D: return Interpolate(variant.scale_2d, other_variant.scale_2d);
  639. case PrimitiveVariant::SCALE3D: return Interpolate(variant.scale_3d, other_variant.scale_3d);
  640. case PrimitiveVariant::ROTATEX: return Interpolate(variant.rotate_x, other_variant.rotate_x);
  641. case PrimitiveVariant::ROTATEY: return Interpolate(variant.rotate_y, other_variant.rotate_y);
  642. case PrimitiveVariant::ROTATEZ: return Interpolate(variant.rotate_z, other_variant.rotate_z);
  643. case PrimitiveVariant::ROTATE2D: return Interpolate(variant.rotate_2d, other_variant.rotate_2d);
  644. case PrimitiveVariant::ROTATE3D: return Interpolate(variant.rotate_3d, other_variant.rotate_3d);
  645. case PrimitiveVariant::SKEWX: return Interpolate(variant.skew_x, other_variant.skew_x);
  646. case PrimitiveVariant::SKEWY: return Interpolate(variant.skew_y, other_variant.skew_y);
  647. case PrimitiveVariant::SKEW2D: return Interpolate(variant.skew_2d, other_variant.skew_2d);
  648. case PrimitiveVariant::PERSPECTIVE: return Interpolate(variant.perspective, other_variant.perspective);
  649. case PrimitiveVariant::DECOMPOSEDMATRIX4: return Interpolate(variant.decomposed_matrix_4, other_variant.decomposed_matrix_4);
  650. default:
  651. break;
  652. }
  653. RMLUI_ASSERT(false);
  654. return false;
  655. }
  656. };
  657. bool Primitive::InterpolateWith(const Primitive & other, float alpha) noexcept
  658. {
  659. if (primitive.type != other.primitive.type)
  660. return false;
  661. bool result = InterpolateVisitor{ other.primitive, alpha }.run(primitive);
  662. return result;
  663. }
  664. template<size_t N>
  665. static inline String ToString(const Transforms::ResolvedPrimitive<N>& p, String unit, bool rad_to_deg = false, bool only_unit_on_last_value = false) noexcept {
  666. float multiplier = 1.0f;
  667. String tmp;
  668. String result = "(";
  669. for (size_t i = 0; i < N; i++)
  670. {
  671. if (only_unit_on_last_value && i < N - 1)
  672. multiplier = 1.0f;
  673. else if (rad_to_deg)
  674. multiplier = 180.f / Math::RMLUI_PI;
  675. if (TypeConverter<float, String>::Convert(p.values[i] * multiplier, tmp))
  676. result += tmp;
  677. if (!unit.empty() && (!only_unit_on_last_value || (i == N - 1)))
  678. result += unit;
  679. if (i < N - 1)
  680. result += ", ";
  681. }
  682. result += ")";
  683. return result;
  684. }
  685. template<size_t N>
  686. static inline String ToString(const Transforms::UnresolvedPrimitive<N> & p) noexcept {
  687. String result = "(";
  688. for (size_t i = 0; i < N; i++)
  689. {
  690. result += p.values[i].ToString();
  691. if (i != N - 1)
  692. result += ", ";
  693. }
  694. result += ")";
  695. return result;
  696. }
  697. static inline String ToString(const Transforms::DecomposedMatrix4& p) noexcept {
  698. static const DecomposedMatrix4 d{
  699. Vector4f(0, 0, 0, 1),
  700. Vector4f(0, 0, 0, 1),
  701. Vector3f(0, 0, 0),
  702. Vector3f(1, 1, 1),
  703. Vector3f(0, 0, 0)
  704. };
  705. String tmp;
  706. String result;
  707. if(p.perspective != d.perspective && TypeConverter< Vector4f, String >::Convert(p.perspective, tmp))
  708. result += "perspective(" + tmp + "), ";
  709. if (p.quaternion != d.quaternion && TypeConverter< Vector4f, String >::Convert(p.quaternion, tmp))
  710. result += "quaternion(" + tmp + "), ";
  711. if (p.translation != d.translation && TypeConverter< Vector3f, String >::Convert(p.translation, tmp))
  712. result += "translation(" + tmp + "), ";
  713. if (p.scale != d.scale && TypeConverter< Vector3f, String >::Convert(p.scale, tmp))
  714. result += "scale(" + tmp + "), ";
  715. if (p.skew != d.skew && TypeConverter< Vector3f, String >::Convert(p.skew, tmp))
  716. result += "skew(" + tmp + "), ";
  717. if (result.size() > 2)
  718. result.resize(result.size() - 2);
  719. result = "decomposedMatrix3d{ " + result + " }";
  720. return result;
  721. }
  722. String ToString(const Transforms::Matrix2D & p) noexcept { return "matrix" + ToString(static_cast<const Transforms::ResolvedPrimitive< 6 >&>(p), ""); }
  723. String ToString(const Transforms::Matrix3D & p) noexcept { return "matrix3d" + ToString(static_cast<const Transforms::ResolvedPrimitive< 16 >&>(p), ""); }
  724. String ToString(const Transforms::TranslateX & p) noexcept { return "translateX" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 1 >&>(p)); }
  725. String ToString(const Transforms::TranslateY & p) noexcept { return "translateY" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 1 >&>(p)); }
  726. String ToString(const Transforms::TranslateZ & p) noexcept { return "translateZ" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 1 >&>(p)); }
  727. String ToString(const Transforms::Translate2D & p) noexcept { return "translate" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 2 >&>(p)); }
  728. String ToString(const Transforms::Translate3D & p) noexcept { return "translate3d" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 3 >&>(p)); }
  729. String ToString(const Transforms::ScaleX & p) noexcept { return "scaleX" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), ""); }
  730. String ToString(const Transforms::ScaleY & p) noexcept { return "scaleY" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), ""); }
  731. String ToString(const Transforms::ScaleZ & p) noexcept { return "scaleZ" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), ""); }
  732. String ToString(const Transforms::Scale2D & p) noexcept { return "scale" + ToString(static_cast<const Transforms::ResolvedPrimitive< 2 >&>(p), ""); }
  733. String ToString(const Transforms::Scale3D & p) noexcept { return "scale3d" + ToString(static_cast<const Transforms::ResolvedPrimitive< 3 >&>(p), ""); }
  734. String ToString(const Transforms::RotateX & p) noexcept { return "rotateX" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
  735. String ToString(const Transforms::RotateY & p) noexcept { return "rotateY" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
  736. String ToString(const Transforms::RotateZ & p) noexcept { return "rotateZ" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
  737. String ToString(const Transforms::Rotate2D & p) noexcept { return "rotate" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
  738. String ToString(const Transforms::Rotate3D & p) noexcept { return "rotate3d" + ToString(static_cast<const Transforms::ResolvedPrimitive< 4 >&>(p), "deg", true, true); }
  739. String ToString(const Transforms::SkewX & p) noexcept { return "skewX" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
  740. String ToString(const Transforms::SkewY & p) noexcept { return "skewY" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
  741. String ToString(const Transforms::Skew2D & p) noexcept { return "skew" + ToString(static_cast<const Transforms::ResolvedPrimitive< 2 >&>(p), "deg", true); }
  742. String ToString(const Transforms::Perspective & p) noexcept { return "perspective" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 1 >&>(p)); }
  743. struct ToStringVisitor
  744. {
  745. String run(const PrimitiveVariant& variant)
  746. {
  747. switch (variant.type)
  748. {
  749. case PrimitiveVariant::MATRIX2D: return ToString(variant.matrix_2d);
  750. case PrimitiveVariant::MATRIX3D: return ToString(variant.matrix_3d);
  751. case PrimitiveVariant::TRANSLATEX: return ToString(variant.translate_x);
  752. case PrimitiveVariant::TRANSLATEY: return ToString(variant.translate_y);
  753. case PrimitiveVariant::TRANSLATEZ: return ToString(variant.translate_z);
  754. case PrimitiveVariant::TRANSLATE2D: return ToString(variant.translate_2d);
  755. case PrimitiveVariant::TRANSLATE3D: return ToString(variant.translate_3d);
  756. case PrimitiveVariant::SCALEX: return ToString(variant.scale_x);
  757. case PrimitiveVariant::SCALEY: return ToString(variant.scale_y);
  758. case PrimitiveVariant::SCALEZ: return ToString(variant.scale_z);
  759. case PrimitiveVariant::SCALE2D: return ToString(variant.scale_2d);
  760. case PrimitiveVariant::SCALE3D: return ToString(variant.scale_3d);
  761. case PrimitiveVariant::ROTATEX: return ToString(variant.rotate_x);
  762. case PrimitiveVariant::ROTATEY: return ToString(variant.rotate_y);
  763. case PrimitiveVariant::ROTATEZ: return ToString(variant.rotate_z);
  764. case PrimitiveVariant::ROTATE2D: return ToString(variant.rotate_2d);
  765. case PrimitiveVariant::ROTATE3D: return ToString(variant.rotate_3d);
  766. case PrimitiveVariant::SKEWX: return ToString(variant.skew_x);
  767. case PrimitiveVariant::SKEWY: return ToString(variant.skew_y);
  768. case PrimitiveVariant::SKEW2D: return ToString(variant.skew_2d);
  769. case PrimitiveVariant::PERSPECTIVE: return ToString(variant.perspective);
  770. case PrimitiveVariant::DECOMPOSEDMATRIX4: return ToString(variant.decomposed_matrix_4);
  771. default:
  772. break;
  773. }
  774. RMLUI_ASSERT(false);
  775. return String();
  776. }
  777. };
  778. String Primitive::ToString() const noexcept
  779. {
  780. String result = ToStringVisitor{}.run(primitive);
  781. return result;
  782. }
  783. bool DecomposedMatrix4::Decompose(const Matrix4f & m)
  784. {
  785. // Follows the procedure given in https://drafts.csswg.org/css-transforms-2/#interpolation-of-3d-matrices
  786. const float eps = 0.0005f;
  787. if (Math::AbsoluteValue(m[3][3]) < eps)
  788. return false;
  789. // Perspective matrix
  790. Matrix4f p = m;
  791. for (int i = 0; i < 3; i++)
  792. p[i][3] = 0;
  793. p[3][3] = 1;
  794. if (Math::AbsoluteValue(p.Determinant()) < eps)
  795. return false;
  796. if (m[0][3] != 0 || m[1][3] != 0 || m[2][3] != 0)
  797. {
  798. auto rhs = m.GetColumn(3);
  799. Matrix4f p_inv = p;
  800. if (!p_inv.Invert())
  801. return false;
  802. auto& p_inv_trans = p.Transpose();
  803. perspective = p_inv_trans * rhs;
  804. }
  805. else
  806. {
  807. perspective[0] = perspective[1] = perspective[2] = 0;
  808. perspective[3] = 1;
  809. }
  810. for (int i = 0; i < 3; i++)
  811. translation[i] = m[3][i];
  812. Vector3f row[3];
  813. for (int i = 0; i < 3; i++)
  814. {
  815. row[i][0] = m[i][0];
  816. row[i][1] = m[i][1];
  817. row[i][2] = m[i][2];
  818. }
  819. scale[0] = row[0].Magnitude();
  820. row[0] = row[0].Normalise();
  821. skew[0] = row[0].DotProduct(row[1]);
  822. row[1] = Combine(row[1], row[0], 1, -skew[0]);
  823. scale[1] = row[1].Magnitude();
  824. row[1] = row[1].Normalise();
  825. skew[0] /= scale[1];
  826. skew[1] = row[0].DotProduct(row[2]);
  827. row[2] = Combine(row[2], row[0], 1, -skew[1]);
  828. skew[2] = row[1].DotProduct(row[2]);
  829. row[2] = Combine(row[2], row[1], 1, -skew[2]);
  830. scale[2] = row[2].Magnitude();
  831. row[2] = row[2].Normalise();
  832. skew[1] /= scale[2];
  833. skew[2] /= scale[2];
  834. // Check if we need to flip coordinate system
  835. auto pdum3 = row[1].CrossProduct(row[2]);
  836. if (row[0].DotProduct(pdum3) < 0.0f)
  837. {
  838. for (int i = 0; i < 3; i++)
  839. {
  840. scale[i] *= -1.f;
  841. row[i] *= -1.f;
  842. }
  843. }
  844. quaternion[0] = 0.5f * Math::SquareRoot(Math::Max(1.f + row[0][0] - row[1][1] - row[2][2], 0.0f));
  845. quaternion[1] = 0.5f * Math::SquareRoot(Math::Max(1.f - row[0][0] + row[1][1] - row[2][2], 0.0f));
  846. quaternion[2] = 0.5f * Math::SquareRoot(Math::Max(1.f - row[0][0] - row[1][1] + row[2][2], 0.0f));
  847. quaternion[3] = 0.5f * Math::SquareRoot(Math::Max(1.f + row[0][0] + row[1][1] + row[2][2], 0.0f));
  848. if (row[2][1] > row[1][2])
  849. quaternion[0] *= -1.f;
  850. if (row[0][2] > row[2][0])
  851. quaternion[1] *= -1.f;
  852. if (row[1][0] > row[0][1])
  853. quaternion[2] *= -1.f;
  854. return true;
  855. }
  856. }
  857. }
  858. }