TransformPrimitive.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  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 "precompiled.h"
  29. #include "../../Include/RmlUi/Core/TransformPrimitive.h"
  30. #include "../../Include/RmlUi/Core/TypeConverter.h"
  31. #include <iostream>
  32. #include <unordered_map>
  33. namespace Rml {
  34. namespace Core {
  35. namespace Transforms {
  36. static Vector3f Combine(const Vector3f& a, const Vector3f& b, float a_scale, float b_scale)
  37. {
  38. Vector3f result;
  39. result.x = a_scale * a.x + b_scale * b.x;
  40. result.y = a_scale * a.y + b_scale * b.y;
  41. result.z = a_scale * a.z + b_scale * b.z;
  42. return result;
  43. }
  44. // Interpolate two quaternions a, b with weight alpha [0, 1]
  45. static Vector4f QuaternionSlerp(const Vector4f& a, const Vector4f& b, float alpha)
  46. {
  47. using namespace Math;
  48. const float eps = 0.9995f;
  49. float dot = a.DotProduct(b);
  50. dot = Clamp(dot, -1.f, 1.f);
  51. if (dot > eps)
  52. return a;
  53. float theta = ACos(dot);
  54. float w = Sin(alpha * theta) / SquareRoot(1.f - dot * dot);
  55. float a_scale = Cos(alpha*theta) - dot * w;
  56. Vector4f result;
  57. for (int i = 0; i < 4; i++)
  58. {
  59. result[i] = a[i] * a_scale + b[i] * w;
  60. }
  61. return result;
  62. }
  63. NumericValue::NumericValue() noexcept
  64. : number(), unit(Property::UNKNOWN)
  65. {
  66. }
  67. NumericValue::NumericValue(float number, Property::Unit unit) noexcept
  68. : number(number), unit(unit)
  69. {
  70. }
  71. float NumericValue::ResolveLengthPercentage(Element& e, float base) const noexcept
  72. {
  73. Property prop;
  74. prop.value = Variant(number);
  75. prop.unit = unit;
  76. return e.ResolveLengthPercentage(&prop, base);
  77. }
  78. float NumericValue::ResolveWidth(Element& e) const noexcept
  79. {
  80. if(unit & (Property::PX | Property::NUMBER)) return number;
  81. return ResolveLengthPercentage(e, e.GetBox().GetSize(Box::BORDER).x);
  82. }
  83. float NumericValue::ResolveHeight(Element& e) const noexcept
  84. {
  85. if (unit & (Property::PX | Property::NUMBER)) return number;
  86. return ResolveLengthPercentage(e, e.GetBox().GetSize(Box::BORDER).y);
  87. }
  88. float NumericValue::ResolveDepth(Element& e) const noexcept
  89. {
  90. if (unit & (Property::PX | Property::NUMBER)) return number;
  91. Vector2f size = e.GetBox().GetSize(Box::BORDER);
  92. return ResolveLengthPercentage(e, Math::Max(size.x, size.y));
  93. }
  94. float NumericValue::ResolveAbsoluteUnit(Property::Unit base_unit) const noexcept
  95. {
  96. if(base_unit == 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::RMLUI_PI;
  107. default:
  108. break;
  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. bool run(const PrimitiveVariant& primitive)
  252. {
  253. switch (primitive.type)
  254. {
  255. case PrimitiveVariant::MATRIX2D: return this->operator()(primitive.matrix_2d);
  256. case PrimitiveVariant::MATRIX3D: return this->operator()(primitive.matrix_3d);
  257. case PrimitiveVariant::TRANSLATEX: return this->operator()(primitive.translate_x);
  258. case PrimitiveVariant::TRANSLATEY: return this->operator()(primitive.translate_y);
  259. case PrimitiveVariant::TRANSLATEZ: return this->operator()(primitive.translate_z);
  260. case PrimitiveVariant::TRANSLATE2D: return this->operator()(primitive.translate_2d);
  261. case PrimitiveVariant::TRANSLATE3D: return this->operator()(primitive.translate_3d);
  262. case PrimitiveVariant::SCALEX: return this->operator()(primitive.scale_x);
  263. case PrimitiveVariant::SCALEY: return this->operator()(primitive.scale_y);
  264. case PrimitiveVariant::SCALEZ: return this->operator()(primitive.scale_z);
  265. case PrimitiveVariant::SCALE2D: return this->operator()(primitive.scale_2d);
  266. case PrimitiveVariant::SCALE3D: return this->operator()(primitive.scale_3d);
  267. case PrimitiveVariant::ROTATEX: return this->operator()(primitive.rotate_x);
  268. case PrimitiveVariant::ROTATEY: return this->operator()(primitive.rotate_y);
  269. case PrimitiveVariant::ROTATEZ: return this->operator()(primitive.rotate_z);
  270. case PrimitiveVariant::ROTATE2D: return this->operator()(primitive.rotate_2d);
  271. case PrimitiveVariant::ROTATE3D: return this->operator()(primitive.rotate_3d);
  272. case PrimitiveVariant::SKEWX: return this->operator()(primitive.skew_x);
  273. case PrimitiveVariant::SKEWY: return this->operator()(primitive.skew_y);
  274. case PrimitiveVariant::SKEW2D: return this->operator()(primitive.skew_2d);
  275. case PrimitiveVariant::PERSPECTIVE: return this->operator()(primitive.perspective);
  276. case PrimitiveVariant::DECOMPOSEDMATRIX4: return this->operator()(primitive.decomposed_matrix_4);
  277. default:
  278. break;
  279. }
  280. RMLUI_ASSERT(false);
  281. return false;
  282. }
  283. };
  284. bool Primitive::ResolveTransform(Matrix4f & m, Element & e) const noexcept
  285. {
  286. ResolveTransformVisitor visitor{ m, e };
  287. bool result = visitor.run(primitive);
  288. return result;
  289. }
  290. bool Primitive::ResolvePerspective(float & p, Element & e) const noexcept
  291. {
  292. bool result = false;
  293. if (primitive.type == PrimitiveVariant::PERSPECTIVE)
  294. {
  295. p = primitive.perspective.values[0].ResolveDepth(e);
  296. result = true;
  297. }
  298. return result;
  299. }
  300. struct SetIdentityVisitor
  301. {
  302. template <size_t N>
  303. void operator()(ResolvedPrimitive<N>& p)
  304. {
  305. for (auto& value : p.values)
  306. value = 0.0f;
  307. }
  308. template <size_t N>
  309. void operator()(UnresolvedPrimitive<N>& p)
  310. {
  311. for (auto& value : p.values)
  312. value.number = 0.0f;
  313. }
  314. void operator()(Matrix2D& p)
  315. {
  316. for (int i = 0; i < 6; i++)
  317. p.values[i] = ((i == 0 || i == 3) ? 1.0f : 0.0f);
  318. }
  319. void operator()(Matrix3D& p)
  320. {
  321. for (int i = 0; i < 16; i++)
  322. p.values[i] = ((i % 5) == 0 ? 1.0f : 0.0f);
  323. }
  324. void operator()(ScaleX& p)
  325. {
  326. p.values[0] = 1;
  327. }
  328. void operator()(ScaleY& p)
  329. {
  330. p.values[0] = 1;
  331. }
  332. void operator()(ScaleZ& p)
  333. {
  334. p.values[0] = 1;
  335. }
  336. void operator()(Scale2D& p)
  337. {
  338. p.values[0] = p.values[1] = 1;
  339. }
  340. void operator()(Scale3D& p)
  341. {
  342. p.values[0] = p.values[1] = p.values[2] = 1;
  343. }
  344. void operator()(DecomposedMatrix4& p)
  345. {
  346. p.perspective = Vector4f(0, 0, 0, 1);
  347. p.quaternion = Vector4f(0, 0, 0, 1);
  348. p.translation = Vector3f(0, 0, 0);
  349. p.scale = Vector3f(1, 1, 1);
  350. p.skew = Vector3f(0, 0, 0);
  351. }
  352. void run(PrimitiveVariant& primitive)
  353. {
  354. switch (primitive.type)
  355. {
  356. case PrimitiveVariant::MATRIX2D: this->operator()(primitive.matrix_2d); break;
  357. case PrimitiveVariant::MATRIX3D: this->operator()(primitive.matrix_3d); break;
  358. case PrimitiveVariant::TRANSLATEX: this->operator()(primitive.translate_x); break;
  359. case PrimitiveVariant::TRANSLATEY: this->operator()(primitive.translate_y); break;
  360. case PrimitiveVariant::TRANSLATEZ: this->operator()(primitive.translate_z); break;
  361. case PrimitiveVariant::TRANSLATE2D: this->operator()(primitive.translate_2d); break;
  362. case PrimitiveVariant::TRANSLATE3D: this->operator()(primitive.translate_3d); break;
  363. case PrimitiveVariant::SCALEX: this->operator()(primitive.scale_x); break;
  364. case PrimitiveVariant::SCALEY: this->operator()(primitive.scale_y); break;
  365. case PrimitiveVariant::SCALEZ: this->operator()(primitive.scale_z); break;
  366. case PrimitiveVariant::SCALE2D: this->operator()(primitive.scale_2d); break;
  367. case PrimitiveVariant::SCALE3D: this->operator()(primitive.scale_3d); break;
  368. case PrimitiveVariant::ROTATEX: this->operator()(primitive.rotate_x); break;
  369. case PrimitiveVariant::ROTATEY: this->operator()(primitive.rotate_y); break;
  370. case PrimitiveVariant::ROTATEZ: this->operator()(primitive.rotate_z); break;
  371. case PrimitiveVariant::ROTATE2D: this->operator()(primitive.rotate_2d); break;
  372. case PrimitiveVariant::ROTATE3D: this->operator()(primitive.rotate_3d); break;
  373. case PrimitiveVariant::SKEWX: this->operator()(primitive.skew_x); break;
  374. case PrimitiveVariant::SKEWY: this->operator()(primitive.skew_y); break;
  375. case PrimitiveVariant::SKEW2D: this->operator()(primitive.skew_2d); break;
  376. case PrimitiveVariant::PERSPECTIVE: this->operator()(primitive.perspective); break;
  377. case PrimitiveVariant::DECOMPOSEDMATRIX4: this->operator()(primitive.decomposed_matrix_4); break;
  378. default:
  379. RMLUI_ASSERT(false);
  380. break;
  381. }
  382. }
  383. };
  384. void Primitive::SetIdentity() noexcept
  385. {
  386. SetIdentityVisitor{}.run(primitive);
  387. }
  388. struct PrepareVisitor
  389. {
  390. Element& e;
  391. bool operator()(TranslateX& p)
  392. {
  393. p.values[0] = NumericValue{ p.values[0].ResolveWidth(e), Property::PX };
  394. return true;
  395. }
  396. bool operator()(TranslateY& p)
  397. {
  398. p.values[0] = NumericValue{ p.values[0].ResolveHeight(e), Property::PX };
  399. return true;
  400. }
  401. bool operator()(TranslateZ& p)
  402. {
  403. p.values[0] = NumericValue{ p.values[0].ResolveDepth(e), Property::PX };
  404. return true;
  405. }
  406. bool operator()(Translate2D& p)
  407. {
  408. p.values[0] = NumericValue{ p.values[0].ResolveWidth(e), Property::PX };
  409. p.values[1] = NumericValue{ p.values[1].ResolveHeight(e), Property::PX };
  410. return true;
  411. }
  412. bool operator()(Translate3D& p)
  413. {
  414. p.values[0] = NumericValue{ p.values[0].ResolveWidth(e), Property::PX };
  415. p.values[1] = NumericValue{ p.values[1].ResolveHeight(e), Property::PX };
  416. p.values[2] = NumericValue{ p.values[2].ResolveDepth(e), Property::PX };
  417. return true;
  418. }
  419. template <size_t N>
  420. bool operator()(ResolvedPrimitive<N>& p)
  421. {
  422. // No conversion needed for resolved transforms (with some exceptions below)
  423. return true;
  424. }
  425. bool operator()(DecomposedMatrix4& p)
  426. {
  427. return true;
  428. }
  429. bool operator()(Rotate3D& p)
  430. {
  431. // Rotate3D must be resolved to a full matrix for interpolation.
  432. // 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.
  433. return false;
  434. }
  435. bool operator()(Matrix3D& p)
  436. {
  437. // Matrices must be decomposed for interpolation
  438. return false;
  439. }
  440. bool operator()(Matrix2D& p)
  441. {
  442. // Matrix2D can also be optimized for interpolation, but for now we decompose it to a full DecomposedMatrix4
  443. return false;
  444. }
  445. bool operator()(Perspective& p)
  446. {
  447. // Perspective must be decomposed
  448. return false;
  449. }
  450. bool run(PrimitiveVariant& primitive)
  451. {
  452. switch (primitive.type)
  453. {
  454. case PrimitiveVariant::MATRIX2D: return this->operator()(primitive.matrix_2d);
  455. case PrimitiveVariant::MATRIX3D: return this->operator()(primitive.matrix_3d);
  456. case PrimitiveVariant::TRANSLATEX: return this->operator()(primitive.translate_x);
  457. case PrimitiveVariant::TRANSLATEY: return this->operator()(primitive.translate_y);
  458. case PrimitiveVariant::TRANSLATEZ: return this->operator()(primitive.translate_z);
  459. case PrimitiveVariant::TRANSLATE2D: return this->operator()(primitive.translate_2d);
  460. case PrimitiveVariant::TRANSLATE3D: return this->operator()(primitive.translate_3d);
  461. case PrimitiveVariant::SCALEX: return this->operator()(primitive.scale_x);
  462. case PrimitiveVariant::SCALEY: return this->operator()(primitive.scale_y);
  463. case PrimitiveVariant::SCALEZ: return this->operator()(primitive.scale_z);
  464. case PrimitiveVariant::SCALE2D: return this->operator()(primitive.scale_2d);
  465. case PrimitiveVariant::SCALE3D: return this->operator()(primitive.scale_3d);
  466. case PrimitiveVariant::ROTATEX: return this->operator()(primitive.rotate_x);
  467. case PrimitiveVariant::ROTATEY: return this->operator()(primitive.rotate_y);
  468. case PrimitiveVariant::ROTATEZ: return this->operator()(primitive.rotate_z);
  469. case PrimitiveVariant::ROTATE2D: return this->operator()(primitive.rotate_2d);
  470. case PrimitiveVariant::ROTATE3D: return this->operator()(primitive.rotate_3d);
  471. case PrimitiveVariant::SKEWX: return this->operator()(primitive.skew_x);
  472. case PrimitiveVariant::SKEWY: return this->operator()(primitive.skew_y);
  473. case PrimitiveVariant::SKEW2D: return this->operator()(primitive.skew_2d);
  474. case PrimitiveVariant::PERSPECTIVE: return this->operator()(primitive.perspective);
  475. case PrimitiveVariant::DECOMPOSEDMATRIX4: return this->operator()(primitive.decomposed_matrix_4);
  476. default:
  477. break;
  478. }
  479. RMLUI_ASSERT(false);
  480. return false;
  481. }
  482. };
  483. bool Primitive::PrepareForInterpolation(Element & e) noexcept
  484. {
  485. return PrepareVisitor{ e }.run(primitive);
  486. }
  487. enum class GenericType { None, Scale3D, Translate3D };
  488. struct GetGenericTypeVisitor
  489. {
  490. GenericType common_type = GenericType::None;
  491. GenericType operator()(const TranslateX& p) { return GenericType::Translate3D; }
  492. GenericType operator()(const TranslateY& p) { return GenericType::Translate3D; }
  493. GenericType operator()(const TranslateZ& p) { return GenericType::Translate3D; }
  494. GenericType operator()(const Translate2D& p) { return GenericType::Translate3D; }
  495. GenericType operator()(const ScaleX& p) { return GenericType::Scale3D; }
  496. GenericType operator()(const ScaleY& p) { return GenericType::Scale3D; }
  497. GenericType operator()(const ScaleZ& p) { return GenericType::Scale3D; }
  498. GenericType operator()(const Scale2D& p) { return GenericType::Scale3D; }
  499. template <typename T>
  500. GenericType operator()(const T& p) { return GenericType::None; }
  501. GenericType run(const PrimitiveVariant& primitive)
  502. {
  503. switch (primitive.type)
  504. {
  505. case PrimitiveVariant::TRANSLATEX: return this->operator()(primitive.translate_x); break;
  506. case PrimitiveVariant::TRANSLATEY: return this->operator()(primitive.translate_y); break;
  507. case PrimitiveVariant::TRANSLATEZ: return this->operator()(primitive.translate_z); break;
  508. case PrimitiveVariant::TRANSLATE2D: return this->operator()(primitive.translate_2d); break;
  509. case PrimitiveVariant::SCALEX: return this->operator()(primitive.scale_x); break;
  510. case PrimitiveVariant::SCALEY: return this->operator()(primitive.scale_y); break;
  511. case PrimitiveVariant::SCALEZ: return this->operator()(primitive.scale_z); break;
  512. case PrimitiveVariant::SCALE2D: return this->operator()(primitive.scale_2d); break;
  513. default:
  514. break;
  515. }
  516. return GenericType::None;
  517. }
  518. };
  519. struct ConvertToGenericTypeVisitor
  520. {
  521. Translate3D operator()(const TranslateX& p) { return Translate3D{ p.values[0], {0.0f, Property::PX}, {0.0f, Property::PX} }; }
  522. Translate3D operator()(const TranslateY& p) { return Translate3D{ {0.0f, Property::PX}, p.values[0], {0.0f, Property::PX} }; }
  523. Translate3D operator()(const TranslateZ& p) { return Translate3D{ {0.0f, Property::PX}, {0.0f, Property::PX}, p.values[0] }; }
  524. Translate3D operator()(const Translate2D& p) { return Translate3D{ p.values[0], p.values[1], {0.0f, Property::PX} }; }
  525. Scale3D operator()(const ScaleX& p) { return Scale3D{ p.values[0], 1.0f, 1.0f }; }
  526. Scale3D operator()(const ScaleY& p) { return Scale3D{ 1.0f, p.values[0], 1.0f }; }
  527. Scale3D operator()(const ScaleZ& p) { return Scale3D{ 1.0f, 1.0f, p.values[0] }; }
  528. Scale3D operator()(const Scale2D& p) { return Scale3D{ p.values[0], p.values[1], 1.0f }; }
  529. template <typename T>
  530. PrimitiveVariant operator()(const T& p) { RMLUI_ERROR; return p; }
  531. PrimitiveVariant run(const PrimitiveVariant& primitive)
  532. {
  533. PrimitiveVariant result = primitive;
  534. switch (primitive.type)
  535. {
  536. case PrimitiveVariant::TRANSLATEX: result.translate_3d = this->operator()(primitive.translate_x); break;
  537. case PrimitiveVariant::TRANSLATEY: result.translate_3d = this->operator()(primitive.translate_y); break;
  538. case PrimitiveVariant::TRANSLATEZ: result.translate_3d = this->operator()(primitive.translate_z); break;
  539. case PrimitiveVariant::TRANSLATE2D: result.translate_3d = this->operator()(primitive.translate_2d); break;
  540. case PrimitiveVariant::SCALEX: result.scale_3d = this->operator()(primitive.scale_x); break;
  541. case PrimitiveVariant::SCALEY: result.scale_3d = this->operator()(primitive.scale_y); break;
  542. case PrimitiveVariant::SCALEZ: result.scale_3d = this->operator()(primitive.scale_z); break;
  543. case PrimitiveVariant::SCALE2D: result.scale_3d = this->operator()(primitive.scale_2d); break;
  544. default:
  545. RMLUI_ASSERT(false);
  546. break;
  547. }
  548. return result;
  549. }
  550. };
  551. bool Primitive::TryConvertToMatchingGenericType(Primitive & p0, Primitive & p1) noexcept
  552. {
  553. if (p0.primitive.type == p1.primitive.type)
  554. return true;
  555. GenericType c0 = GetGenericTypeVisitor{}.run(p0.primitive);
  556. GenericType c1 = GetGenericTypeVisitor{}.run(p1.primitive);
  557. if (c0 == c1 && c0 != GenericType::None)
  558. {
  559. p0.primitive = ConvertToGenericTypeVisitor{}.run(p0.primitive);
  560. p1.primitive = ConvertToGenericTypeVisitor{}.run(p1.primitive);
  561. return true;
  562. }
  563. return false;
  564. }
  565. struct InterpolateVisitor
  566. {
  567. const PrimitiveVariant& other_variant;
  568. float alpha;
  569. template <size_t N>
  570. bool Interpolate(ResolvedPrimitive<N>& p0, const ResolvedPrimitive<N>& p1)
  571. {
  572. for (size_t i = 0; i < N; i++)
  573. p0.values[i] = p0.values[i] * (1.0f - alpha) + p1.values[i] * alpha;
  574. return true;
  575. }
  576. template <size_t N>
  577. bool Interpolate(UnresolvedPrimitive<N>& p0, const UnresolvedPrimitive<N>& p1)
  578. {
  579. // Assumes that the underlying units have been resolved (e.g. to pixels)
  580. for (size_t i = 0; i < N; i++)
  581. p0.values[i].number = p0.values[i].number*(1.0f - alpha) + p1.values[i].number * alpha;
  582. return true;
  583. }
  584. bool Interpolate(Rotate3D& p0, const Rotate3D& p1)
  585. {
  586. // 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.
  587. // We may change this later by assuming that the underlying direction vectors are equivalent (else, need to do full matrix interpolation)
  588. // If we change this later: p0.values[3] = p0.values[3] * (1.0f - alpha) + p1.values[3] * alpha;
  589. return false;
  590. }
  591. bool Interpolate(Matrix2D& p0, const Matrix2D& p1) { return false; /* Error if we get here, see PrepareForInterpolation() */ }
  592. bool Interpolate(Matrix3D& p0, const Matrix3D& p1) { return false; /* Error if we get here, see PrepareForInterpolation() */ }
  593. bool Interpolate(Perspective& p0, const Perspective& p1) { return false; /* Error if we get here, see PrepareForInterpolation() */ }
  594. bool Interpolate(DecomposedMatrix4& p0, const DecomposedMatrix4& p1)
  595. {
  596. p0.perspective = p0.perspective * (1.0f - alpha) + p1.perspective * alpha;
  597. p0.quaternion = QuaternionSlerp(p0.quaternion, p1.quaternion, alpha);
  598. p0.translation = p0.translation * (1.0f - alpha) + p1.translation * alpha;
  599. p0.scale = p0.scale* (1.0f - alpha) + p1.scale* alpha;
  600. p0.skew = p0.skew* (1.0f - alpha) + p1.skew* alpha;
  601. return true;
  602. }
  603. bool run(PrimitiveVariant& variant)
  604. {
  605. RMLUI_ASSERT(variant.type == other_variant.type);
  606. switch (variant.type)
  607. {
  608. case PrimitiveVariant::MATRIX2D: return Interpolate(variant.matrix_2d, other_variant.matrix_2d);
  609. case PrimitiveVariant::MATRIX3D: return Interpolate(variant.matrix_3d, other_variant.matrix_3d);
  610. case PrimitiveVariant::TRANSLATEX: return Interpolate(variant.translate_x, other_variant.translate_x);
  611. case PrimitiveVariant::TRANSLATEY: return Interpolate(variant.translate_y, other_variant.translate_y);
  612. case PrimitiveVariant::TRANSLATEZ: return Interpolate(variant.translate_z, other_variant.translate_z);
  613. case PrimitiveVariant::TRANSLATE2D: return Interpolate(variant.translate_2d, other_variant.translate_2d);
  614. case PrimitiveVariant::TRANSLATE3D: return Interpolate(variant.translate_3d, other_variant.translate_3d);
  615. case PrimitiveVariant::SCALEX: return Interpolate(variant.scale_x, other_variant.scale_x);
  616. case PrimitiveVariant::SCALEY: return Interpolate(variant.scale_y, other_variant.scale_y);
  617. case PrimitiveVariant::SCALEZ: return Interpolate(variant.scale_z, other_variant.scale_z);
  618. case PrimitiveVariant::SCALE2D: return Interpolate(variant.scale_2d, other_variant.scale_2d);
  619. case PrimitiveVariant::SCALE3D: return Interpolate(variant.scale_3d, other_variant.scale_3d);
  620. case PrimitiveVariant::ROTATEX: return Interpolate(variant.rotate_x, other_variant.rotate_x);
  621. case PrimitiveVariant::ROTATEY: return Interpolate(variant.rotate_y, other_variant.rotate_y);
  622. case PrimitiveVariant::ROTATEZ: return Interpolate(variant.rotate_z, other_variant.rotate_z);
  623. case PrimitiveVariant::ROTATE2D: return Interpolate(variant.rotate_2d, other_variant.rotate_2d);
  624. case PrimitiveVariant::ROTATE3D: return Interpolate(variant.rotate_3d, other_variant.rotate_3d);
  625. case PrimitiveVariant::SKEWX: return Interpolate(variant.skew_x, other_variant.skew_x);
  626. case PrimitiveVariant::SKEWY: return Interpolate(variant.skew_y, other_variant.skew_y);
  627. case PrimitiveVariant::SKEW2D: return Interpolate(variant.skew_2d, other_variant.skew_2d);
  628. case PrimitiveVariant::PERSPECTIVE: return Interpolate(variant.perspective, other_variant.perspective);
  629. case PrimitiveVariant::DECOMPOSEDMATRIX4: return Interpolate(variant.decomposed_matrix_4, other_variant.decomposed_matrix_4);
  630. default:
  631. break;
  632. }
  633. RMLUI_ASSERT(false);
  634. return false;
  635. }
  636. };
  637. bool Primitive::InterpolateWith(const Primitive & other, float alpha) noexcept
  638. {
  639. if (primitive.type != other.primitive.type)
  640. return false;
  641. bool result = InterpolateVisitor{ other.primitive, alpha }.run(primitive);
  642. return result;
  643. }
  644. template<size_t N>
  645. inline String ToString(const Transforms::ResolvedPrimitive<N>& p, String unit, bool rad_to_deg = false, bool only_unit_on_last_value = false) noexcept {
  646. float multiplier = 1.0f;
  647. if (rad_to_deg) multiplier = 180.f / Math::RMLUI_PI;
  648. String tmp;
  649. String result = "(";
  650. for (size_t i = 0; i < N; i++) {
  651. if (TypeConverter<float, String>::Convert(p.values[i] * multiplier, tmp))
  652. result += tmp;
  653. if (!unit.empty() && (!only_unit_on_last_value || (i == N - 1)))
  654. result += unit;
  655. if (i != N - 1) result += ", ";
  656. }
  657. result += ")";
  658. return result;
  659. }
  660. template<size_t N>
  661. inline String ToString(const Transforms::UnresolvedPrimitive<N> & p) noexcept {
  662. String result = "(";
  663. for (size_t i = 0; i < N; i++) {
  664. result += p.values[i].ToString();
  665. if (i != N - 1) result += ", ";
  666. }
  667. result += ")";
  668. return result;
  669. }
  670. String ToString(const Transforms::Matrix2D & p) noexcept { return "matrix" + ToString(static_cast<const Transforms::ResolvedPrimitive< 6 >&>(p), ""); }
  671. String ToString(const Transforms::Matrix3D & p) noexcept { return "matrix3d" + ToString(static_cast<const Transforms::ResolvedPrimitive< 16 >&>(p), ""); }
  672. String ToString(const Transforms::TranslateX & p) noexcept { return "translateX" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 1 >&>(p)); }
  673. String ToString(const Transforms::TranslateY & p) noexcept { return "translateY" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 1 >&>(p)); }
  674. String ToString(const Transforms::TranslateZ & p) noexcept { return "translateZ" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 1 >&>(p)); }
  675. String ToString(const Transforms::Translate2D & p) noexcept { return "translate" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 2 >&>(p)); }
  676. String ToString(const Transforms::Translate3D & p) noexcept { return "translate3d" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 3 >&>(p)); }
  677. String ToString(const Transforms::ScaleX & p) noexcept { return "scaleX" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), ""); }
  678. String ToString(const Transforms::ScaleY & p) noexcept { return "scaleY" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), ""); }
  679. String ToString(const Transforms::ScaleZ & p) noexcept { return "scaleZ" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), ""); }
  680. String ToString(const Transforms::Scale2D & p) noexcept { return "scale" + ToString(static_cast<const Transforms::ResolvedPrimitive< 2 >&>(p), ""); }
  681. String ToString(const Transforms::Scale3D & p) noexcept { return "scale3d" + ToString(static_cast<const Transforms::ResolvedPrimitive< 3 >&>(p), ""); }
  682. String ToString(const Transforms::RotateX & p) noexcept { return "rotateX" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
  683. String ToString(const Transforms::RotateY & p) noexcept { return "rotateY" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
  684. String ToString(const Transforms::RotateZ & p) noexcept { return "rotateZ" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
  685. String ToString(const Transforms::Rotate2D & p) noexcept { return "rotate" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
  686. String ToString(const Transforms::Rotate3D & p) noexcept { return "rotate3d" + ToString(static_cast<const Transforms::ResolvedPrimitive< 4 >&>(p), "deg", true, true); }
  687. String ToString(const Transforms::SkewX & p) noexcept { return "skewX" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
  688. String ToString(const Transforms::SkewY & p) noexcept { return "skewY" + ToString(static_cast<const Transforms::ResolvedPrimitive< 1 >&>(p), "deg", true); }
  689. String ToString(const Transforms::Skew2D & p) noexcept { return "skew" + ToString(static_cast<const Transforms::ResolvedPrimitive< 2 >&>(p), "deg", true); }
  690. String ToString(const Transforms::Perspective & p) noexcept { return "perspective" + ToString(static_cast<const Transforms::UnresolvedPrimitive< 1 >&>(p)); }
  691. String ToString(const Transforms::DecomposedMatrix4& p) noexcept { return "decomposedMatrix3d"; }
  692. struct ToStringVisitor
  693. {
  694. String run(const PrimitiveVariant& variant)
  695. {
  696. switch (variant.type)
  697. {
  698. case PrimitiveVariant::MATRIX2D: return ToString(variant.matrix_2d);
  699. case PrimitiveVariant::MATRIX3D: return ToString(variant.matrix_3d);
  700. case PrimitiveVariant::TRANSLATEX: return ToString(variant.translate_x);
  701. case PrimitiveVariant::TRANSLATEY: return ToString(variant.translate_y);
  702. case PrimitiveVariant::TRANSLATEZ: return ToString(variant.translate_z);
  703. case PrimitiveVariant::TRANSLATE2D: return ToString(variant.translate_2d);
  704. case PrimitiveVariant::TRANSLATE3D: return ToString(variant.translate_3d);
  705. case PrimitiveVariant::SCALEX: return ToString(variant.scale_x);
  706. case PrimitiveVariant::SCALEY: return ToString(variant.scale_y);
  707. case PrimitiveVariant::SCALEZ: return ToString(variant.scale_z);
  708. case PrimitiveVariant::SCALE2D: return ToString(variant.scale_2d);
  709. case PrimitiveVariant::SCALE3D: return ToString(variant.scale_3d);
  710. case PrimitiveVariant::ROTATEX: return ToString(variant.rotate_x);
  711. case PrimitiveVariant::ROTATEY: return ToString(variant.rotate_y);
  712. case PrimitiveVariant::ROTATEZ: return ToString(variant.rotate_z);
  713. case PrimitiveVariant::ROTATE2D: return ToString(variant.rotate_2d);
  714. case PrimitiveVariant::ROTATE3D: return ToString(variant.rotate_3d);
  715. case PrimitiveVariant::SKEWX: return ToString(variant.skew_x);
  716. case PrimitiveVariant::SKEWY: return ToString(variant.skew_y);
  717. case PrimitiveVariant::SKEW2D: return ToString(variant.skew_2d);
  718. case PrimitiveVariant::PERSPECTIVE: return ToString(variant.perspective);
  719. case PrimitiveVariant::DECOMPOSEDMATRIX4: return ToString(variant.decomposed_matrix_4);
  720. default:
  721. break;
  722. }
  723. RMLUI_ASSERT(false);
  724. return String();
  725. }
  726. };
  727. String Primitive::ToString() const noexcept
  728. {
  729. String result = ToStringVisitor{}.run(primitive);
  730. return result;
  731. }
  732. bool DecomposedMatrix4::Decompose(const Matrix4f & m)
  733. {
  734. // Follows the procedure given in https://drafts.csswg.org/css-transforms-2/#interpolation-of-3d-matrices
  735. const float eps = 0.0005f;
  736. if (Math::AbsoluteValue(m[3][3]) < eps)
  737. return false;
  738. // Perspective matrix
  739. Matrix4f p = m;
  740. for (int i = 0; i < 3; i++)
  741. p[i][3] = 0;
  742. p[3][3] = 1;
  743. if (Math::AbsoluteValue(p.Determinant()) < eps)
  744. return false;
  745. if (m[0][3] != 0 || m[1][3] != 0 || m[2][3] != 0)
  746. {
  747. auto rhs = m.GetColumn(3);
  748. Matrix4f p_inv = p;
  749. if (!p_inv.Invert())
  750. return false;
  751. auto& p_inv_trans = p.Transpose();
  752. perspective = p_inv_trans * rhs;
  753. }
  754. else
  755. {
  756. perspective[0] = perspective[1] = perspective[2] = 0;
  757. perspective[3] = 1;
  758. }
  759. for (int i = 0; i < 3; i++)
  760. translation[i] = m[3][i];
  761. Vector3f row[3];
  762. for (int i = 0; i < 3; i++)
  763. {
  764. row[i][0] = m[i][0];
  765. row[i][1] = m[i][1];
  766. row[i][2] = m[i][2];
  767. }
  768. scale[0] = row[0].Magnitude();
  769. row[0] = row[0].Normalise();
  770. skew[0] = row[0].DotProduct(row[1]);
  771. row[1] = Combine(row[1], row[0], 1, -skew[0]);
  772. scale[1] = row[1].Magnitude();
  773. row[1] = row[1].Normalise();
  774. skew[0] /= scale[1];
  775. skew[1] = row[0].DotProduct(row[2]);
  776. row[2] = Combine(row[2], row[0], 1, -skew[1]);
  777. skew[2] = row[1].DotProduct(row[2]);
  778. row[2] = Combine(row[2], row[1], 1, -skew[2]);
  779. scale[2] = row[2].Magnitude();
  780. row[2] = row[2].Normalise();
  781. skew[1] /= scale[2];
  782. skew[2] /= scale[2];
  783. // Check if we need to flip coordinate system
  784. auto pdum3 = row[1].CrossProduct(row[2]);
  785. if (row[0].DotProduct(pdum3) < 0.0f)
  786. {
  787. for (int i = 0; i < 3; i++)
  788. {
  789. scale[i] *= -1.f;
  790. row[i] *= -1.f;
  791. }
  792. }
  793. quaternion[0] = 0.5f * Math::SquareRoot(Math::Max(1.f + row[0][0] - row[1][1] - row[2][2], 0.0f));
  794. quaternion[1] = 0.5f * Math::SquareRoot(Math::Max(1.f - row[0][0] + row[1][1] - row[2][2], 0.0f));
  795. quaternion[2] = 0.5f * Math::SquareRoot(Math::Max(1.f - row[0][0] - row[1][1] + row[2][2], 0.0f));
  796. quaternion[3] = 0.5f * Math::SquareRoot(Math::Max(1.f + row[0][0] + row[1][1] + row[2][2], 0.0f));
  797. if (row[2][1] > row[1][2])
  798. quaternion[0] *= -1.f;
  799. if (row[0][2] > row[2][0])
  800. quaternion[1] *= -1.f;
  801. if (row[1][0] > row[0][1])
  802. quaternion[2] *= -1.f;
  803. return true;
  804. }
  805. }
  806. }
  807. }