TransformPrimitive.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  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. NumericValue::NumericValue() noexcept
  35. : number(), unit(Property::UNKNOWN)
  36. {
  37. }
  38. NumericValue::NumericValue(float number, Property::Unit unit) noexcept
  39. : number(number), unit(unit)
  40. {
  41. }
  42. float NumericValue::Resolve(Element& e, float base) const noexcept
  43. {
  44. Property prop;
  45. prop.value = Variant(number);
  46. prop.unit = unit;
  47. return e.ResolveProperty(&prop, base);
  48. }
  49. float NumericValue::ResolveWidth(Element& e) const noexcept
  50. {
  51. if(unit & (Property::PX | Property::NUMBER)) return number;
  52. return Resolve(e, e.GetBox().GetSize().x);
  53. }
  54. float NumericValue::ResolveHeight(Element& e) const noexcept
  55. {
  56. if (unit & (Property::PX | Property::NUMBER)) return number;
  57. return Resolve(e, e.GetBox().GetSize().y);
  58. }
  59. float NumericValue::ResolveDepth(Element& e) const noexcept
  60. {
  61. if (unit & (Property::PX | Property::NUMBER)) return number;
  62. Vector2f size = e.GetBox().GetSize();
  63. return Resolve(e, Math::Max(size.x, size.y));
  64. }
  65. float NumericValue::ResolveAbsoluteUnit(Property::Unit base_unit) const noexcept
  66. {
  67. switch (base_unit)
  68. {
  69. case Property::RAD:
  70. {
  71. switch (unit)
  72. {
  73. case Property::NUMBER:
  74. case Property::DEG:
  75. return Math::DegreesToRadians(number);
  76. case Property::RAD:
  77. return number;
  78. case Property::PERCENT:
  79. return number * 0.01f * 2.0f * Math::ROCKET_PI;
  80. break;
  81. }
  82. }
  83. }
  84. return number;
  85. }
  86. struct ResolveTransformVisitor
  87. {
  88. Matrix4f& m;
  89. Element& e;
  90. bool operator()(const Matrix2D& p)
  91. {
  92. m = Matrix4f::FromRows(
  93. Vector4f(p.values[0], p.values[2], 0, p.values[4]),
  94. Vector4f(p.values[1], p.values[3], 0, p.values[5]),
  95. Vector4f(0, 0, 1, 0),
  96. Vector4f(0, 0, 0, 1)
  97. );
  98. return true;
  99. }
  100. bool operator()(const Matrix3D& p)
  101. {
  102. m = Matrix4f::FromRows(
  103. Vector4f(p.values[0], p.values[1], p.values[2], p.values[3]),
  104. Vector4f(p.values[4], p.values[5], p.values[6], p.values[7]),
  105. Vector4f(p.values[8], p.values[9], p.values[10], p.values[11]),
  106. Vector4f(p.values[12], p.values[13], p.values[14], p.values[15])
  107. );
  108. return true;
  109. }
  110. bool operator()(const TranslateX& p)
  111. {
  112. m = Matrix4f::TranslateX(p.values[0].ResolveWidth(e));
  113. return true;
  114. }
  115. bool operator()(const TranslateY& p)
  116. {
  117. m = Matrix4f::TranslateY(p.values[0].ResolveHeight(e));
  118. return true;
  119. }
  120. bool operator()(const TranslateZ& p)
  121. {
  122. m = Matrix4f::TranslateZ(p.values[0].ResolveDepth(e));
  123. return true;
  124. }
  125. bool operator()(const Translate2D& p)
  126. {
  127. m = Matrix4f::Translate(
  128. p.values[0].ResolveWidth(e),
  129. p.values[1].ResolveHeight(e),
  130. 0
  131. );
  132. return true;
  133. }
  134. bool operator()(const Translate3D& p)
  135. {
  136. m = Matrix4f::Translate(
  137. p.values[0].ResolveWidth(e),
  138. p.values[1].ResolveHeight(e),
  139. p.values[2].ResolveDepth(e)
  140. );
  141. return true;
  142. }
  143. bool operator()(const ScaleX& p)
  144. {
  145. m = Matrix4f::ScaleX(p.values[0]);
  146. return true;
  147. }
  148. bool operator()(const ScaleY& p)
  149. {
  150. m = Matrix4f::ScaleY(p.values[0]);
  151. return true;
  152. }
  153. bool operator()(const ScaleZ& p)
  154. {
  155. m = Matrix4f::ScaleZ(p.values[0]);
  156. return true;
  157. }
  158. bool operator()(const Scale2D& p)
  159. {
  160. m = Matrix4f::Scale(p.values[0], p.values[1], 1);
  161. return true;
  162. }
  163. bool operator()(const Scale3D& p)
  164. {
  165. m = Matrix4f::Scale(p.values[0], p.values[1], p.values[2]);
  166. return true;
  167. }
  168. bool operator()(const RotateX& p)
  169. {
  170. m = Matrix4f::RotateX(p.values[0]);
  171. return true;
  172. }
  173. bool operator()(const RotateY& p)
  174. {
  175. m = Matrix4f::RotateY(p.values[0]);
  176. return true;
  177. }
  178. bool operator()(const RotateZ& p)
  179. {
  180. m = Matrix4f::RotateZ(p.values[0]);
  181. return true;
  182. }
  183. bool operator()(const Rotate2D& p)
  184. {
  185. m = Matrix4f::RotateZ(p.values[0]);
  186. return true;
  187. }
  188. bool operator()(const Rotate3D& p)
  189. {
  190. m = Matrix4f::Rotate(Vector3f(p.values[0], p.values[1], p.values[2]), p.values[3]);
  191. return true;
  192. }
  193. bool operator()(const SkewX& p)
  194. {
  195. m = Matrix4f::SkewX(p.values[0]);
  196. return true;
  197. }
  198. bool operator()(const SkewY& p)
  199. {
  200. m = Matrix4f::SkewY(p.values[0]);
  201. return true;
  202. }
  203. bool operator()(const Skew2D& p)
  204. {
  205. m = Matrix4f::Skew(p.values[0], p.values[1]);
  206. return true;
  207. }
  208. bool operator()(const DecomposedMatrix4& p)
  209. {
  210. m = Matrix4f::Compose(p.translation, p.scale, p.skew, p.perspective, p.quaternion);
  211. return true;
  212. }
  213. bool operator()(const Perspective& p)
  214. {
  215. return false;
  216. }
  217. };
  218. bool Primitive::ResolveTransform(Matrix4f & m, Element & e) const noexcept
  219. {
  220. ResolveTransformVisitor visitor{ m, e };
  221. bool result = std::visit(visitor, primitive);
  222. return result;
  223. }
  224. bool Primitive::ResolvePerspective(float & p, Element & e) const noexcept
  225. {
  226. bool result = false;
  227. if (const Perspective* perspective = std::get_if<Perspective>(&primitive))
  228. {
  229. p = perspective->values[0].ResolveDepth(e);
  230. result = true;
  231. }
  232. return result;
  233. }
  234. struct SetIdentityVisitor
  235. {
  236. template <size_t N>
  237. void operator()(ResolvedPrimitive<N>& p)
  238. {
  239. for (auto& value : p.values)
  240. value = 0.0f;
  241. }
  242. template <size_t N>
  243. void operator()(UnresolvedPrimitive<N>& p)
  244. {
  245. for (auto& value : p.values)
  246. value.number = 0.0f;
  247. }
  248. void operator()(Matrix2D& p)
  249. {
  250. for (int i = 0; i < 6; i++)
  251. p.values[i] = ((i == 0 || i == 3) ? 1.0f : 0.0f);
  252. }
  253. void operator()(Matrix3D& p)
  254. {
  255. for (int i = 0; i < 16; i++)
  256. p.values[i] = ((i % 5) == 0 ? 1.0f : 0.0f);
  257. }
  258. void operator()(ScaleX& p)
  259. {
  260. p.values[0] = 1;
  261. }
  262. void operator()(ScaleY& p)
  263. {
  264. p.values[0] = 1;
  265. }
  266. void operator()(ScaleZ& p)
  267. {
  268. p.values[0] = 1;
  269. }
  270. void operator()(Scale2D& p)
  271. {
  272. p.values[0] = p.values[1] = 1;
  273. }
  274. void operator()(Scale3D& p)
  275. {
  276. p.values[0] = p.values[1] = p.values[2] = 1;
  277. }
  278. void operator()(DecomposedMatrix4& p)
  279. {
  280. p.perspective = Vector4f(0, 0, 0, 1);
  281. p.quaternion = Vector4f(0, 0, 0, 1);
  282. p.translation = Vector3f(0, 0, 0);
  283. p.scale = Vector3f(1, 1, 1);
  284. p.skew = Vector3f(0, 0, 0);
  285. }
  286. };
  287. void Primitive::SetIdentity() noexcept
  288. {
  289. std::visit(SetIdentityVisitor{}, primitive);
  290. }
  291. // Interpolate two quaternions a, b with the factor alpha
  292. static Vector4f QuaternionSlerp(const Vector4f& a, const Vector4f& b, float alpha)
  293. {
  294. using namespace Math;
  295. float dot = a.DotProduct(b);
  296. dot = Clamp(dot, -1.f, 1.f);
  297. if (dot == 1)
  298. return a;
  299. float theta = ACos(dot);
  300. float w = Sin(alpha * theta) / SquareRoot(1.f - dot * dot);
  301. float a_scale = Cos(alpha*theta) - dot * w;
  302. Vector4f result;
  303. for (int i = 0; i < 4; i++)
  304. {
  305. result[i] = a[i] * a_scale + b[i] * w;
  306. }
  307. return result;
  308. }
  309. struct InterpolateVisitor
  310. {
  311. const PrimitiveVariant& other_variant;
  312. float alpha;
  313. template <size_t N>
  314. void Interpolate(ResolvedPrimitive<N>& p0, const ResolvedPrimitive<N>& p1)
  315. {
  316. for (size_t i = 0; i < N; i++)
  317. p0.values[i] = p0.values[i] * (1.0f - alpha) + p1.values[i] * alpha;
  318. }
  319. template <size_t N>
  320. void Interpolate(UnresolvedPrimitive<N>& p0, const UnresolvedPrimitive<N>& p1)
  321. {
  322. // Assumes that the underlying units have been resolved (e.g. to pixels)
  323. for (size_t i = 0; i < N; i++)
  324. p0.values[i].number = p0.values[i].number*(1.0f - alpha) + p1.values[i].number * alpha;
  325. }
  326. void Interpolate(Rotate3D& p0, const Rotate3D& p1)
  327. {
  328. // Assumes that the underlying direction vectors are normalized and equivalent (else, need to do full matrix interpolation)
  329. p0.values[4] = p0.values[4] * (1.0f - alpha) + p1.values[4] * alpha;
  330. }
  331. //void Interpolate(Matrix3D& p0, const Matrix3D& p1)
  332. //{
  333. // // Special interpolation for full matrices TODO
  334. // // Also, Matrix2d, Perspective, and conditionally Rotate3d get interpolated in this way
  335. //}
  336. void Interpolate(DecomposedMatrix4& p0, const DecomposedMatrix4& p1)
  337. {
  338. p0.perspective = p0.perspective * (1.0f - alpha) + p1.perspective * alpha;
  339. p0.quaternion = QuaternionSlerp(p0.quaternion, p1.quaternion, alpha);
  340. p0.translation = p0.translation * (1.0f - alpha) + p1.translation * alpha;
  341. p0.scale = p0.scale* (1.0f - alpha) + p1.scale* alpha;
  342. p0.skew = p0.skew* (1.0f - alpha) + p1.skew* alpha;
  343. }
  344. template <typename T>
  345. void operator()(T& p0)
  346. {
  347. auto& p1 = std::get<T>(other_variant);
  348. Interpolate(p0, p1);
  349. }
  350. };
  351. bool Primitive::InterpolateWith(const Primitive & other, float alpha) noexcept
  352. {
  353. if (primitive.index() != other.primitive.index())
  354. return false;
  355. std::visit(InterpolateVisitor{ other.primitive, alpha }, primitive);
  356. return true;
  357. }
  358. enum class GenericType { None, Scale3D, Translate3D };
  359. struct GetGenericTypeVisitor
  360. {
  361. GenericType common_type = GenericType::None;
  362. GenericType operator()(const TranslateX& p) { return GenericType::Translate3D; }
  363. GenericType operator()(const TranslateY& p) { return GenericType::Translate3D; }
  364. GenericType operator()(const TranslateZ& p) { return GenericType::Translate3D; }
  365. GenericType operator()(const Translate2D& p) { return GenericType::Translate3D; }
  366. GenericType operator()(const ScaleX& p) { return GenericType::Scale3D; }
  367. GenericType operator()(const ScaleY& p) { return GenericType::Scale3D; }
  368. GenericType operator()(const ScaleZ& p) { return GenericType::Scale3D; }
  369. GenericType operator()(const Scale2D& p) { return GenericType::Scale3D; }
  370. template <typename T>
  371. GenericType operator()(const T& p) { return GenericType::None; }
  372. };
  373. struct ConvertToGenericTypeVisitor
  374. {
  375. PrimitiveVariant operator()(const TranslateX& p) { return Translate3D{ p.values[0], {0.0f, Property::PX}, {0.0f, Property::PX} }; }
  376. PrimitiveVariant operator()(const TranslateY& p) { return Translate3D{ {0.0f, Property::PX}, p.values[0], {0.0f, Property::PX} }; }
  377. PrimitiveVariant operator()(const TranslateZ& p) { return Translate3D{ {0.0f, Property::PX}, {0.0f, Property::PX}, p.values[0] }; }
  378. PrimitiveVariant operator()(const Translate2D& p) { return Translate3D{ p.values[0], p.values[1], {0.0f, Property::PX} }; }
  379. PrimitiveVariant operator()(const ScaleX& p) { return Scale3D{ p.values[0], 1.0f, 1.0f }; }
  380. PrimitiveVariant operator()(const ScaleY& p) { return Scale3D{ 1.0f, p.values[0], 1.0f }; }
  381. PrimitiveVariant operator()(const ScaleZ& p) { return Scale3D{ 1.0f, 1.0f, p.values[0] }; }
  382. PrimitiveVariant operator()(const Scale2D& p) { return Scale3D{ p.values[0], p.values[1], 1.0f }; }
  383. template <typename T>
  384. PrimitiveVariant operator()(const T& p) { ROCKET_ERROR; return p; }
  385. };
  386. bool Primitive::TryConvertToMatchingGenericType(Primitive & p0, Primitive & p1) noexcept
  387. {
  388. if (p0.primitive.index() == p1.primitive.index())
  389. return true;
  390. GenericType c0 = std::visit(GetGenericTypeVisitor{}, p0.primitive);
  391. GenericType c1 = std::visit(GetGenericTypeVisitor{}, p1.primitive);
  392. if (c0 == c1 && c0 != GenericType::None)
  393. {
  394. p0.primitive = std::visit(ConvertToGenericTypeVisitor{}, p0.primitive);
  395. p1.primitive = std::visit(ConvertToGenericTypeVisitor{}, p1.primitive);
  396. return true;
  397. }
  398. return false;
  399. }
  400. struct ResolveUnitsVisitor
  401. {
  402. Element& e;
  403. bool operator()(TranslateX& p)
  404. {
  405. p.values[0] = NumericValue{ p.values[0].ResolveWidth(e), Property::PX };
  406. return true;
  407. }
  408. bool operator()(TranslateY& p)
  409. {
  410. p.values[0] = NumericValue{ p.values[0].ResolveHeight(e), Property::PX };
  411. return true;
  412. }
  413. bool operator()(TranslateZ& p)
  414. {
  415. p.values[0] = NumericValue{ p.values[0].ResolveDepth(e), Property::PX };
  416. return true;
  417. }
  418. bool operator()(Translate2D& p)
  419. {
  420. p.values[0] = NumericValue{ p.values[0].ResolveWidth(e), Property::PX };
  421. p.values[1] = NumericValue{ p.values[1].ResolveHeight(e), Property::PX };
  422. return true;
  423. }
  424. bool operator()(Translate3D& p)
  425. {
  426. p.values[0] = NumericValue{ p.values[0].ResolveWidth(e), Property::PX };
  427. p.values[1] = NumericValue{ p.values[1].ResolveHeight(e), Property::PX };
  428. p.values[2] = NumericValue{ p.values[2].ResolveDepth(e), Property::PX };
  429. return true;
  430. }
  431. template <size_t N>
  432. bool operator()(ResolvedPrimitive<N>& p)
  433. {
  434. // No conversion needed for resolved transforms
  435. return true;
  436. }
  437. bool operator()(DecomposedMatrix4& p)
  438. {
  439. return true;
  440. }
  441. bool operator()(Perspective& p)
  442. {
  443. // Perspective is special and not used for transform animations, ignore.
  444. return false;
  445. }
  446. };
  447. bool Primitive::ResolveUnits(Element & e) noexcept
  448. {
  449. return std::visit(ResolveUnitsVisitor{ e }, primitive);
  450. }
  451. static Vector3f Combine(const Vector3f& a, const Vector3f& b, float a_scale, float b_scale)
  452. {
  453. Vector3f result;
  454. result.x = a_scale * a.x + b_scale * b.x;
  455. result.y = a_scale * a.y + b_scale * b.y;
  456. result.z = a_scale * a.z + b_scale * b.z;
  457. return result;
  458. }
  459. bool DecomposedMatrix4::Decompose(const Matrix4f & m)
  460. {
  461. // Follows the procedure given in https://drafts.csswg.org/css-transforms-2/#interpolation-of-3d-matrices
  462. if (m[3][3] == 0)
  463. return false;
  464. // Perspective matrix
  465. Matrix4f p = m;
  466. for (int i = 0; i < 3; i++)
  467. p[i][3] = 0;
  468. p[3][3] = 1;
  469. if (p.Determinant() == 0)
  470. return false;
  471. if (m[0][3] != 0 || m[1][3] != 0 || m[2][3] != 0)
  472. {
  473. auto rhs = m.GetColumn(3);
  474. Matrix4f p_inv = p;
  475. if (!p_inv.Invert())
  476. return false;
  477. auto& p_inv_trans = p.Transpose();
  478. perspective = p_inv_trans * rhs;
  479. }
  480. else
  481. {
  482. perspective[0] = perspective[1] = perspective[2] = 0;
  483. perspective[3] = 1;
  484. }
  485. for (int i = 0; i < 3; i++)
  486. translation[i] = m[3][i];
  487. Vector3f row[3];
  488. for (int i = 0; i < 3; i++)
  489. {
  490. row[i][0] = m[i][0];
  491. row[i][1] = m[i][1];
  492. row[i][2] = m[i][2];
  493. }
  494. scale[0] = row[0].Magnitude();
  495. row[0] = row[0].Normalise();
  496. skew[0] = row[0].DotProduct(row[1]);
  497. row[1] = Combine(row[1], row[0], 1, -skew[0]);
  498. scale[1] = row[1].Magnitude();
  499. row[1] = row[1].Normalise();
  500. skew[0] /= scale[1];
  501. skew[1] = row[0].DotProduct(row[2]);
  502. row[2] = Combine(row[2], row[0], 1, -skew[1]);
  503. skew[2] = row[1].DotProduct(row[2]);
  504. row[2] = Combine(row[2], row[1], 1, -skew[2]);
  505. scale[2] = row[2].Magnitude();
  506. row[2] = row[2].Normalise();
  507. skew[1] /= scale[2];
  508. skew[2] /= scale[2];
  509. // Check if we need to flip coordinate system
  510. auto pdum3 = row[1].CrossProduct(row[2]);
  511. if (row[0].DotProduct(pdum3) < 0.0f)
  512. {
  513. for (int i = 0; i < 3; i++)
  514. {
  515. scale[i] *= -1.f;
  516. row[i] *= -1.f;
  517. }
  518. }
  519. quaternion[0] = 0.5f * Math::SquareRoot(Math::Max(1.f + row[0][0] - row[1][1] - row[2][2], 0.0f));
  520. quaternion[1] = 0.5f * Math::SquareRoot(Math::Max(1.f - row[0][0] + row[1][1] - row[2][2], 0.0f));
  521. quaternion[2] = 0.5f * Math::SquareRoot(Math::Max(1.f - row[0][0] - row[1][1] + row[2][2], 0.0f));
  522. quaternion[3] = 0.5f * Math::SquareRoot(Math::Max(1.f + row[0][0] + row[1][1] + row[2][2], 0.0f));
  523. if (row[2][1] > row[1][2])
  524. quaternion[0] *= -1.f;
  525. if (row[0][2] > row[2][0])
  526. quaternion[1] *= -1.f;
  527. if (row[1][0] > row[0][1])
  528. quaternion[2] *= -1.f;
  529. return true;
  530. }
  531. }
  532. }
  533. }