ElementAnimation.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  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) 2018 Michael Ragazzon
  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 "ElementAnimation.h"
  29. #include "../../Include/Rocket/Core/Element.h"
  30. #include "../../Include/Rocket/Core/TransformPrimitive.h"
  31. namespace Rocket {
  32. namespace Core {
  33. static Colourf ColourToLinearSpace(Colourb c)
  34. {
  35. Colourf result;
  36. // Approximate inverse sRGB function
  37. result.red = Math::SquareRoot((float)c.red / 255.f);
  38. result.green = Math::SquareRoot((float)c.green / 255.f);
  39. result.blue = Math::SquareRoot((float)c.blue / 255.f);
  40. result.alpha = (float)c.alpha / 255.f;
  41. return result;
  42. }
  43. static Colourb ColourFromLinearSpace(Colourf c)
  44. {
  45. Colourb result;
  46. result.red = (Rocket::Core::byte)Math::Clamp(c.red*c.red*255.f, 0.0f, 255.f);
  47. result.green = (Rocket::Core::byte)Math::Clamp(c.green*c.green*255.f, 0.0f, 255.f);
  48. result.blue = (Rocket::Core::byte)Math::Clamp(c.blue*c.blue*255.f, 0.0f, 255.f);
  49. result.alpha = (Rocket::Core::byte)Math::Clamp(c.alpha*255.f, 0.0f, 255.f);
  50. return result;
  51. }
  52. template<size_t N>
  53. static bool TryInterpolatePrimitive(Rocket::Core::Transforms::Primitive* p_inout, const Rocket::Core::Transforms::Primitive* p1, float alpha)
  54. {
  55. using namespace Rocket::Core::Transforms;
  56. bool result = false;
  57. if (auto values0 = dynamic_cast<UnresolvedValuesPrimitive< N >*>(p_inout))
  58. {
  59. auto values1 = dynamic_cast<const UnresolvedValuesPrimitive< N >*>(p1);
  60. if (values1) {
  61. values0->InterpolateValues(*values1, alpha);
  62. result = true;
  63. }
  64. }
  65. return result;
  66. }
  67. template<size_t N>
  68. static bool TryInterpolateResolvedPrimitive(Rocket::Core::Transforms::Primitive* p_inout, const Rocket::Core::Transforms::Primitive* p1, float alpha)
  69. {
  70. using namespace Rocket::Core::Transforms;
  71. bool result = false;
  72. if (auto values0 = dynamic_cast<ResolvedValuesPrimitive< N >*>(p_inout))
  73. {
  74. auto values1 = dynamic_cast<const ResolvedValuesPrimitive< N >*>(p1);
  75. if (values1) {
  76. values0->InterpolateValues(*values1, alpha);
  77. result = true;
  78. }
  79. }
  80. return result;
  81. }
  82. static Variant InterpolateValues(const Variant & v0, const Variant & v1, float alpha)
  83. {
  84. auto type0 = v0.GetType();
  85. auto type1 = v1.GetType();
  86. if (type0 != type1)
  87. {
  88. Log::Message(Log::LT_WARNING, "Interpolating properties must be of same unit. Got types: '%c' and '%c'.", type0, type1);
  89. return v0;
  90. }
  91. switch (type0)
  92. {
  93. case Variant::FLOAT:
  94. {
  95. float f0 = v0.Get<float>();
  96. float f1 = v1.Get<float>();
  97. float f = (1.0f - alpha) * f0 + alpha * f1;
  98. return Variant(f);
  99. }
  100. case Variant::COLOURB:
  101. {
  102. Colourf c0 = ColourToLinearSpace(v0.Get<Colourb>());
  103. Colourf c1 = ColourToLinearSpace(v1.Get<Colourb>());
  104. Colourf c = c0 * (1.0f - alpha) + c1 * alpha;
  105. return Variant(ColourFromLinearSpace(c));
  106. }
  107. case Variant::TRANSFORMREF:
  108. {
  109. using namespace Rocket::Core::Transforms;
  110. auto t0 = v0.Get<TransformRef>();
  111. auto t1 = v1.Get<TransformRef>();
  112. Primitive* p0 = t0->GetPrimitive(0).Clone();
  113. const Primitive* p1 = &t1->GetPrimitive(0);
  114. bool success = false;
  115. // Todo: Check carefully for memory leaks
  116. // Todo: Lots of dynamic dispatch, not good!
  117. if (TryInterpolateResolvedPrimitive<1>(p0, p1, alpha))
  118. success = true;
  119. else if (TryInterpolateResolvedPrimitive<2>(p0, p1, alpha))
  120. success = true;
  121. else if (TryInterpolateResolvedPrimitive<3>(p0, p1, alpha))
  122. success = true;
  123. else if (TryInterpolateResolvedPrimitive<4>(p0, p1, alpha))
  124. success = true;
  125. else if (TryInterpolateResolvedPrimitive<6>(p0, p1, alpha))
  126. success = true;
  127. else if (TryInterpolateResolvedPrimitive<16>(p0, p1, alpha))
  128. success = true;
  129. else if (TryInterpolatePrimitive<1>(p0, p1, alpha))
  130. success = true;
  131. else if (TryInterpolatePrimitive<2>(p0, p1, alpha))
  132. success = true;
  133. else if (TryInterpolatePrimitive<3>(p0, p1, alpha))
  134. success = true;
  135. if(success)
  136. {
  137. auto transform = new Transform;
  138. transform->AddPrimitive(*p0);
  139. TransformRef tref{ transform };
  140. delete p0;
  141. return Variant(tref);
  142. }
  143. else
  144. {
  145. delete p0;
  146. }
  147. Log::Message(Log::LT_WARNING, "Could not decode transform for interpolation.");
  148. }
  149. }
  150. Log::Message(Log::LT_WARNING, "Currently, only float and color values can be interpolated. Got types of: '%c'.", type0);
  151. return v0;
  152. }
  153. bool ElementAnimation::AddKey(float time, const Property & property)
  154. {
  155. if (property.unit != property_unit)
  156. return false;
  157. keys.push_back({ time, property.value });
  158. return true;
  159. }
  160. Property ElementAnimation::UpdateAndGetProperty(float time)
  161. {
  162. Property result;
  163. //Log::Message(Log::LT_INFO, "Animation it = %d, t_it = %f, rev = %d, dt = %f", current_iteration, time_since_iteration_start, (int)reverse_direction, time - last_update_time);
  164. if (animation_complete || time - last_update_time <= 0.0f)
  165. return result;
  166. const float dt = 0.01f;// time - last_update_time;
  167. last_update_time = time;
  168. time_since_iteration_start += dt;
  169. if (time_since_iteration_start >= duration)
  170. {
  171. // Next iteration
  172. current_iteration += 1;
  173. if (current_iteration < num_iterations || num_iterations == -1)
  174. {
  175. time_since_iteration_start = 0.0f;
  176. if (alternate_direction)
  177. reverse_direction = !reverse_direction;
  178. }
  179. else
  180. {
  181. animation_complete = true;
  182. time_since_iteration_start = duration;
  183. }
  184. }
  185. float t = time_since_iteration_start;
  186. if (reverse_direction)
  187. t = duration - t;
  188. int key0 = -1;
  189. int key1 = -1;
  190. {
  191. for (int i = 0; i < (int)keys.size(); i++)
  192. {
  193. if (keys[i].time >= t)
  194. {
  195. key1 = i;
  196. break;
  197. }
  198. }
  199. if (key1 < 0) key1 = (int)keys.size() - 1;
  200. key0 = (key1 == 0 ? 0 : key1 - 1 );
  201. }
  202. ROCKET_ASSERT(key0 >= 0 && key0 < (int)keys.size() && key1 >= 0 && key1 < (int)keys.size());
  203. float alpha = 0.0f;
  204. {
  205. const float t0 = keys[key0].time;
  206. const float t1 = keys[key1].time;
  207. const float eps = 1e-3f;
  208. if (t1 - t0 > eps)
  209. alpha = (t - t0) / (t1 - t0);
  210. alpha = Math::Clamp(alpha, 0.0f, 1.0f);
  211. }
  212. result.unit = property_unit;
  213. result.specificity = property_specificity;
  214. result.value = InterpolateValues(keys[key0].value, keys[key1].value, alpha);
  215. return result;
  216. }
  217. }
  218. }