TransformPrimitive.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  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. #ifndef ROCKETCORETRANSFORMPRIMITIVE_H
  28. #define ROCKETCORETRANSFORMPRIMITIVE_H
  29. #include "Header.h"
  30. #include "Types.h"
  31. #include "Property.h"
  32. #include <array>
  33. namespace Rocket {
  34. namespace Core {
  35. namespace Transforms {
  36. struct NumericValue
  37. {
  38. /// Non-initializing constructor.
  39. NumericValue() noexcept;
  40. /// Construct from a float and a Unit.
  41. NumericValue(float number, Property::Unit unit) noexcept;
  42. /// Resolve a numeric property value for an element.
  43. float Resolve(Element& e, float base) const noexcept;
  44. /// Resolve a numeric property value with the element's width as relative base value.
  45. float ResolveWidth(Element& e) const noexcept;
  46. /// Resolve a numeric property value with the element's height as relative base value.
  47. float ResolveHeight(Element& e) const noexcept;
  48. /// Resolve a numeric property value with the element's depth as relative base value.
  49. float ResolveDepth(Element& e) const noexcept;
  50. /// Returns the numeric value converted to base_unit, or 'number' if no relationship defined.
  51. /// Defined for: {Number, Deg, %} -> Rad
  52. float ResolveAbsoluteUnit(Property::Unit base_unit) const noexcept;
  53. String ToString() const noexcept;
  54. float number;
  55. Property::Unit unit;
  56. };
  57. template< size_t N >
  58. struct ResolvedPrimitive
  59. {
  60. ResolvedPrimitive(const float* values) noexcept
  61. {
  62. for (size_t i = 0; i < N; ++i)
  63. this->values[i] = values[i];
  64. }
  65. ResolvedPrimitive(const NumericValue* values) noexcept
  66. {
  67. for (size_t i = 0; i < N; ++i)
  68. this->values[i] = values[i].number;
  69. }
  70. ResolvedPrimitive(const NumericValue* values, std::array<Property::Unit, N> base_units) noexcept
  71. {
  72. for (size_t i = 0; i < N; ++i)
  73. this->values[i] = values[i].ResolveAbsoluteUnit(base_units[i]);
  74. }
  75. ResolvedPrimitive(std::array<NumericValue, N> values, std::array<Property::Unit, N> base_units) noexcept
  76. {
  77. for (size_t i = 0; i < N; ++i)
  78. this->values[i] = values[i].ResolveAbsoluteUnit(base_units[i]);
  79. }
  80. ResolvedPrimitive(std::array<float, N> values) noexcept : values(values) { }
  81. std::array<float, N> values;
  82. String ToString(String unit, bool rad_to_deg = false, bool only_unit_on_last_value = false) const noexcept;
  83. };
  84. template< size_t N >
  85. struct UnresolvedPrimitive
  86. {
  87. UnresolvedPrimitive(const NumericValue* values) noexcept
  88. {
  89. for (size_t i = 0; i < N; ++i)
  90. this->values[i] = values[i];
  91. }
  92. UnresolvedPrimitive(std::array<NumericValue, N> values) noexcept : values(values) { }
  93. std::array<NumericValue, N> values;
  94. String ToString() const noexcept;
  95. };
  96. struct Matrix2D : public ResolvedPrimitive< 6 >
  97. {
  98. Matrix2D(const NumericValue* values) noexcept : ResolvedPrimitive(values) { }
  99. String ToString() const noexcept { return "matrix" + ResolvedPrimitive< 6 >::ToString(""); }
  100. };
  101. struct Matrix3D : public ResolvedPrimitive< 16 >
  102. {
  103. Matrix3D(const Matrix4f& matrix) noexcept : ResolvedPrimitive(matrix.data()) { }
  104. Matrix3D(const NumericValue* values) noexcept : ResolvedPrimitive(values) { }
  105. String ToString() const noexcept { return "matrix3d" + ResolvedPrimitive< 16 >::ToString(""); }
  106. };
  107. struct TranslateX : public UnresolvedPrimitive< 1 >
  108. {
  109. TranslateX(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { }
  110. TranslateX(float x, Property::Unit unit = Property::PX) noexcept : UnresolvedPrimitive({ NumericValue(x, unit) }) { }
  111. String ToString() const noexcept { return "translateX" + UnresolvedPrimitive< 1 >::ToString(); }
  112. };
  113. struct TranslateY : public UnresolvedPrimitive< 1 >
  114. {
  115. TranslateY(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { }
  116. TranslateY(float y, Property::Unit unit = Property::PX) noexcept : UnresolvedPrimitive({ NumericValue(y, unit) }) { }
  117. String ToString() const noexcept { return "translateY" + UnresolvedPrimitive< 1 >::ToString(); }
  118. };
  119. struct TranslateZ : public UnresolvedPrimitive< 1 >
  120. {
  121. TranslateZ(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { }
  122. TranslateZ(float z, Property::Unit unit = Property::PX) noexcept : UnresolvedPrimitive({ NumericValue(z, unit) }) { }
  123. String ToString() const noexcept { return "translateZ" + UnresolvedPrimitive< 1 >::ToString(); }
  124. };
  125. struct Translate2D : public UnresolvedPrimitive< 2 >
  126. {
  127. Translate2D(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { }
  128. Translate2D(float x, float y, Property::Unit units = Property::PX) noexcept : UnresolvedPrimitive({ NumericValue(x, units), NumericValue(y, units) }) { }
  129. String ToString() const noexcept { return "translate" + UnresolvedPrimitive< 2 >::ToString(); }
  130. };
  131. struct Translate3D : public UnresolvedPrimitive< 3 >
  132. {
  133. Translate3D(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { }
  134. Translate3D(NumericValue x, NumericValue y, NumericValue z) noexcept : UnresolvedPrimitive({ x, y, z }) { }
  135. Translate3D(float x, float y, float z, Property::Unit units = Property::PX) noexcept : UnresolvedPrimitive({ NumericValue(x, units), NumericValue(y, units), NumericValue(z, units) }) { }
  136. String ToString() const noexcept { return "translate3d" + UnresolvedPrimitive< 3 >::ToString(); }
  137. };
  138. struct ScaleX : public ResolvedPrimitive< 1 >
  139. {
  140. ScaleX(const NumericValue* values) noexcept : ResolvedPrimitive(values) { }
  141. ScaleX(float value) noexcept : ResolvedPrimitive({ value }) { }
  142. String ToString() const noexcept { return "scaleX" + ResolvedPrimitive< 1 >::ToString(""); }
  143. };
  144. struct ScaleY : public ResolvedPrimitive< 1 >
  145. {
  146. ScaleY(const NumericValue* values) noexcept : ResolvedPrimitive(values) { }
  147. ScaleY(float value) noexcept : ResolvedPrimitive({ value }) { }
  148. String ToString() const noexcept { return "scaleY" + ResolvedPrimitive< 1 >::ToString(""); }
  149. };
  150. struct ScaleZ : public ResolvedPrimitive< 1 >
  151. {
  152. ScaleZ(const NumericValue* values) noexcept : ResolvedPrimitive(values) { }
  153. ScaleZ(float value) noexcept : ResolvedPrimitive({ value }) { }
  154. String ToString() const noexcept { return "scaleZ" + ResolvedPrimitive< 1 >::ToString(""); }
  155. };
  156. struct Scale2D : public ResolvedPrimitive< 2 >
  157. {
  158. Scale2D(const NumericValue* values) noexcept : ResolvedPrimitive(values) { }
  159. Scale2D(float xy) noexcept : ResolvedPrimitive({ xy, xy }) { }
  160. Scale2D(float x, float y) noexcept : ResolvedPrimitive({ x, y }) { }
  161. String ToString() const noexcept { return "scale" + ResolvedPrimitive< 2 >::ToString(""); }
  162. };
  163. struct Scale3D : public ResolvedPrimitive< 3 >
  164. {
  165. Scale3D(const NumericValue* values) noexcept : ResolvedPrimitive(values) { }
  166. Scale3D(float xyz) noexcept : ResolvedPrimitive({ xyz, xyz, xyz }) { }
  167. Scale3D(float x, float y, float z) noexcept : ResolvedPrimitive({ x, y, z }) { }
  168. String ToString() const noexcept { return "scale3d" + ResolvedPrimitive< 3 >::ToString(""); }
  169. };
  170. struct RotateX : public ResolvedPrimitive< 1 >
  171. {
  172. RotateX(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) { }
  173. RotateX(float angle, Property::Unit unit = Property::DEG) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { }
  174. String ToString() const noexcept { return "rotateX" + ResolvedPrimitive< 1 >::ToString("deg", true); }
  175. };
  176. struct RotateY : public ResolvedPrimitive< 1 >
  177. {
  178. RotateY(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) {}
  179. RotateY(float angle, Property::Unit unit = Property::DEG) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { }
  180. String ToString() const noexcept { return "rotateY" + ResolvedPrimitive< 1 >::ToString("deg", true); }
  181. };
  182. struct RotateZ : public ResolvedPrimitive< 1 >
  183. {
  184. RotateZ(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) { }
  185. RotateZ(float angle, Property::Unit unit = Property::DEG) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { }
  186. String ToString() const noexcept { return "rotateZ" + ResolvedPrimitive< 1 >::ToString("deg", true); }
  187. };
  188. struct Rotate2D : public ResolvedPrimitive< 1 >
  189. {
  190. Rotate2D(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) { }
  191. Rotate2D(float angle, Property::Unit unit = Property::DEG) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { }
  192. String ToString() const noexcept { return "rotate" + ResolvedPrimitive< 1 >::ToString("deg", true); }
  193. };
  194. struct Rotate3D : public ResolvedPrimitive< 4 >
  195. {
  196. Rotate3D(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::NUMBER, Property::NUMBER, Property::NUMBER, Property::RAD }) { }
  197. Rotate3D(float x, float y, float z, float angle, Property::Unit angle_unit = Property::DEG) noexcept
  198. : ResolvedPrimitive({ NumericValue{x, Property::NUMBER}, NumericValue{y, Property::NUMBER}, NumericValue{z, Property::NUMBER}, NumericValue{angle, angle_unit} },
  199. { Property::NUMBER, Property::NUMBER, Property::NUMBER, Property::RAD }) { }
  200. String ToString() const noexcept { return "rotate3d" + ResolvedPrimitive< 4 >::ToString("deg", true, true); }
  201. };
  202. struct SkewX : public ResolvedPrimitive< 1 >
  203. {
  204. SkewX(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) { }
  205. SkewX(float angle, Property::Unit unit = Property::DEG) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { }
  206. String ToString() const noexcept { return "skewX" + ResolvedPrimitive< 1 >::ToString("deg", true); }
  207. };
  208. struct SkewY : public ResolvedPrimitive< 1 >
  209. {
  210. SkewY(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) { }
  211. SkewY(float angle, Property::Unit unit = Property::DEG) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { }
  212. String ToString() const noexcept { return "skewY" + ResolvedPrimitive< 1 >::ToString("deg", true); }
  213. };
  214. struct Skew2D : public ResolvedPrimitive< 2 >
  215. {
  216. Skew2D(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD, Property::RAD }) { }
  217. Skew2D(float x, float y, Property::Unit unit = Property::DEG) noexcept : ResolvedPrimitive({NumericValue{ x, unit }, { NumericValue{ y, unit }}}, {Property::RAD, Property::RAD}) { }
  218. String ToString() const noexcept { return "skew" + ResolvedPrimitive< 2 >::ToString("deg", true); }
  219. };
  220. struct Perspective : public UnresolvedPrimitive< 1 >
  221. {
  222. Perspective(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { }
  223. String ToString() const noexcept { return "perspective" + UnresolvedPrimitive< 1 >::ToString(); }
  224. };
  225. struct DecomposedMatrix4
  226. {
  227. Vector4f perspective;
  228. Vector4f quaternion;
  229. Vector3f translation;
  230. Vector3f scale;
  231. Vector3f skew;
  232. bool Decompose(const Matrix4f& m);
  233. String ToString() const noexcept { return "decomposedMatrix3d"; }
  234. };
  235. struct PrimitiveVariant {
  236. enum Type {
  237. MATRIX2D, MATRIX3D,
  238. TRANSLATEX, TRANSLATEY, TRANSLATEZ, TRANSLATE2D, TRANSLATE3D,
  239. SCALEX, SCALEY, SCALEZ, SCALE2D, SCALE3D,
  240. ROTATEX, ROTATEY, ROTATEZ, ROTATE2D, ROTATE3D,
  241. SKEWX, SKEWY, SKEW2D,
  242. PERSPECTIVE, DECOMPOSEDMATRIX4
  243. };
  244. PrimitiveVariant(Type type) : type(type) {}
  245. Type type;
  246. union {
  247. Matrix2D matrix_2d;
  248. Matrix3D matrix_3d;
  249. TranslateX translate_x;
  250. TranslateY translate_y;
  251. TranslateZ translate_z;
  252. Translate2D translate_2d;
  253. Translate3D translate_3d;
  254. ScaleX scale_x;
  255. ScaleY scale_y;
  256. ScaleZ scale_z;
  257. Scale2D scale_2d;
  258. Scale3D scale_3d;
  259. RotateX rotate_x;
  260. RotateY rotate_y;
  261. RotateZ rotate_z;
  262. Rotate2D rotate_2d;
  263. Rotate3D rotate_3d;
  264. SkewX skew_x;
  265. SkewY skew_y;
  266. Skew2D skew_2d;
  267. Perspective perspective;
  268. DecomposedMatrix4 decomposed_matrix_4;
  269. };
  270. };
  271. /**
  272. The Primitive struct is the base struct of geometric transforms such as rotations, scalings and translations.
  273. Instances of this struct are added to a Rocket::Core::Transform instance
  274. by the Rocket::Core::PropertyParserTransform, which is responsible for
  275. parsing the `transform' property.
  276. @author Markus Schöngart
  277. @see Rocket::Core::Transform
  278. @see Rocket::Core::PropertyParserTransform
  279. */
  280. struct Primitive
  281. {
  282. PrimitiveVariant primitive;
  283. Primitive(Matrix2D p) : primitive(PrimitiveVariant::MATRIX2D) { primitive.matrix_2d = p; }
  284. Primitive(Matrix3D p) : primitive(PrimitiveVariant::MATRIX3D) { primitive.matrix_3d = p; }
  285. Primitive(TranslateX p) : primitive(PrimitiveVariant::TRANSLATEX) { primitive.translate_x = p; }
  286. Primitive(TranslateY p) : primitive(PrimitiveVariant::TRANSLATEY) { primitive.translate_y = p; }
  287. Primitive(TranslateZ p) : primitive(PrimitiveVariant::TRANSLATEZ) { primitive.translate_z = p; }
  288. Primitive(Translate2D p) : primitive(PrimitiveVariant::TRANSLATE2D) { primitive.translate_2d = p; }
  289. Primitive(Translate3D p) : primitive(PrimitiveVariant::TRANSLATE3D) { primitive.translate_3d = p; }
  290. Primitive(ScaleX p) : primitive(PrimitiveVariant::SCALEX) { primitive.scale_x = p; }
  291. Primitive(ScaleY p) : primitive(PrimitiveVariant::SCALEY) { primitive.scale_y = p; }
  292. Primitive(ScaleZ p) : primitive(PrimitiveVariant::SCALEZ) { primitive.scale_z = p; }
  293. Primitive(Scale2D p) : primitive(PrimitiveVariant::SCALE2D) { primitive.scale_2d = p; }
  294. Primitive(Scale3D p) : primitive(PrimitiveVariant::SCALE3D) { primitive.scale_3d = p; }
  295. Primitive(RotateX p) : primitive(PrimitiveVariant::ROTATEX) { primitive.rotate_x = p; }
  296. Primitive(RotateY p) : primitive(PrimitiveVariant::ROTATEY) { primitive.rotate_y = p; }
  297. Primitive(RotateZ p) : primitive(PrimitiveVariant::ROTATEZ) { primitive.rotate_z = p; }
  298. Primitive(Rotate2D p) : primitive(PrimitiveVariant::ROTATE2D) { primitive.rotate_2d = p; }
  299. Primitive(Rotate3D p) : primitive(PrimitiveVariant::ROTATE3D) { primitive.rotate_3d = p; }
  300. Primitive(SkewX p) : primitive(PrimitiveVariant::SKEWX) { primitive.skew_x = p; }
  301. Primitive(SkewY p) : primitive(PrimitiveVariant::SKEWY) { primitive.skew_y = p; }
  302. Primitive(Skew2D p) : primitive(PrimitiveVariant::SKEW2D) { primitive.skew_2d = p; }
  303. Primitive(Perspective p) : primitive(PrimitiveVariant::PERSPECTIVE) { primitive.perspective = p; }
  304. Primitive(DecomposedMatrix4 p) : primitive(PrimitiveVariant::DECOMPOSEDMATRIX4) { primitive.decomposed_matrix_4 = p; }
  305. void SetIdentity() noexcept;
  306. bool ResolveTransform(Matrix4f& m, Element& e) const noexcept;
  307. bool ResolvePerspective(float &p, Element& e) const noexcept;
  308. // Prepares this primitive for interpolation. This must be done before calling InterpolateWith().
  309. // Promote units to basic types which can be interpolated, that is, convert 'length -> pixel' for unresolved primitives.
  310. // Returns false if the owning transform must to be converted to a DecomposedMatrix4 primitive.
  311. bool PrepareForInterpolation(Element& e) noexcept;
  312. // If primitives do not match, try to convert them to a common generic type, e.g. TranslateX -> Translate3D.
  313. // Returns true if they are already the same type or were converted to a common generic type.
  314. static bool TryConvertToMatchingGenericType(Primitive& p0, Primitive& p1) noexcept;
  315. // Interpolate this primitive with another primitive, weighted by alpha [0, 1].
  316. // Primitives must be of same type and PrepareForInterpolation() must previously have been called on both.
  317. bool InterpolateWith(const Primitive& other, float alpha) noexcept;
  318. String ToString() const noexcept;
  319. };
  320. template<size_t N>
  321. inline String ResolvedPrimitive<N>::ToString(String unit, bool rad_to_deg, bool only_unit_on_last_value) const noexcept {
  322. float multiplier = 1.0f;
  323. if (rad_to_deg) multiplier = 180.f / Math::ROCKET_PI;
  324. String tmp;
  325. String result = "(";
  326. for (size_t i = 0; i < N; i++) {
  327. if (TypeConverter<float, String>::Convert(values[i] * multiplier, tmp))
  328. result += tmp;
  329. if (!unit.Empty() && (!only_unit_on_last_value || (i == N - 1)))
  330. result += unit;
  331. if (i != N - 1) result += ", ";
  332. }
  333. result += ")";
  334. return result;
  335. }
  336. template<size_t N>
  337. inline String UnresolvedPrimitive<N>::ToString() const noexcept {
  338. String result = "(";
  339. for (size_t i = 0; i < N; i++) {
  340. result += values[i].ToString();
  341. if (i != N - 1) result += ", ";
  342. }
  343. result += ")";
  344. return result;
  345. }
  346. }
  347. }
  348. }
  349. #endif