TransformPrimitive.h 14 KB

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