particles.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. Minetest
  3. Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #pragma once
  17. #include <string>
  18. #include <sstream>
  19. #include <vector>
  20. #include <ctgmath>
  21. #include <type_traits>
  22. #include "irrlicht_changes/printing.h"
  23. #include "irrlichttypes_bloated.h"
  24. #include "tileanimation.h"
  25. #include "mapnode.h"
  26. #include "util/serialize.h"
  27. #include "util/numeric.h"
  28. // This file defines the particle-related structures that both the server and
  29. // client need. The ParticleManager and rendering is in client/particles.h
  30. namespace ParticleParamTypes
  31. {
  32. template <bool cond, typename T>
  33. using enableIf = typename std::enable_if<cond, T>::type;
  34. // std::enable_if_t does not appear to be present in GCC????
  35. // std::is_enum_v also missing. wtf. these are supposed to be
  36. // present as of c++14
  37. template<typename T> using BlendFunction = T(float,T,T);
  38. #define DECL_PARAM_SRZRS(type) \
  39. void serializeParameterValue (std::ostream& os, type v); \
  40. void deSerializeParameterValue(std::istream& is, type& r);
  41. #define DECL_PARAM_OVERLOADS(type) DECL_PARAM_SRZRS(type) \
  42. type interpolateParameterValue(float fac, const type a, const type b); \
  43. type pickParameterValue (float* facs, const type a, const type b);
  44. // Function definition: see "particles.cpp"
  45. DECL_PARAM_OVERLOADS(u8); DECL_PARAM_OVERLOADS(s8);
  46. DECL_PARAM_OVERLOADS(u16); DECL_PARAM_OVERLOADS(s16);
  47. DECL_PARAM_OVERLOADS(u32); DECL_PARAM_OVERLOADS(s32);
  48. DECL_PARAM_OVERLOADS(f32);
  49. DECL_PARAM_OVERLOADS(v2f);
  50. DECL_PARAM_OVERLOADS(v3f);
  51. /* C++ is a strongly typed language. this means that enums cannot be implicitly
  52. * cast to integers, as they can be in C. while this may sound good in principle,
  53. * it means that our normal serialization functions cannot be called on
  54. * enumerations unless they are explicitly cast to a particular type first. this
  55. * is problematic, because in C++ enums can have any integral type as an underlying
  56. * type, and that type would need to be named everywhere an enumeration is
  57. * de/serialized.
  58. *
  59. * this is obviously not cool, both in terms of writing legible, succinct code,
  60. * and in terms of robustness: the underlying type might be changed at some point,
  61. * e.g. if a bitmask gets too big for its britches. we could use an equivalent of
  62. * `std::to_underlying(value)` everywhere we need to deal with enumerations, but
  63. * that's hideous and unintuitive. instead, we supply the following functions to
  64. * transparently map enumeration types to their underlying values. */
  65. template <typename E, enableIf<std::is_enum<E>::value, bool> = true>
  66. void serializeParameterValue(std::ostream& os, E k) {
  67. serializeParameterValue(os, (std::underlying_type_t<E>)k);
  68. }
  69. template <typename E, enableIf<std::is_enum<E>::value, bool> = true>
  70. void deSerializeParameterValue(std::istream& is, E& k) {
  71. std::underlying_type_t<E> v;
  72. deSerializeParameterValue(is, v);
  73. k = (E)v;
  74. }
  75. // Describes a single value
  76. template <typename T, size_t PN>
  77. struct Parameter
  78. {
  79. using ValType = T;
  80. using pickFactors = float[PN];
  81. T val = T();
  82. using This = Parameter<T, PN>;
  83. Parameter() = default;
  84. template <typename... Args>
  85. Parameter(Args... args) : val(args...) {}
  86. virtual void serialize(std::ostream &os) const
  87. { serializeParameterValue (os, this->val); }
  88. virtual void deSerialize(std::istream &is)
  89. { deSerializeParameterValue(is, this->val); }
  90. virtual T interpolate(float fac, const This& against) const
  91. {
  92. return interpolateParameterValue(fac, this->val, against.val);
  93. }
  94. static T pick(float* f, const This& a, const This& b)
  95. {
  96. return pickParameterValue(f, a.val, b.val);
  97. }
  98. operator T() const { return val; }
  99. T operator=(T b) { return val = b; }
  100. };
  101. // New struct required to differentiate between core::vectorNd-compatible
  102. // structs for proper value dumping (debugging)
  103. template <typename T, size_t N>
  104. struct VectorParameter : public Parameter<T,N> {
  105. using This = VectorParameter<T,N>;
  106. template <typename... Args>
  107. VectorParameter(Args... args) : Parameter<T,N>(args...) {}
  108. };
  109. template <typename T, size_t PN>
  110. inline std::string dump(const Parameter<T,PN>& p)
  111. {
  112. return std::to_string(p.val);
  113. }
  114. template <typename T, size_t N>
  115. inline std::string dump(const VectorParameter<T,N>& v)
  116. {
  117. std::ostringstream oss;
  118. oss << v.val;
  119. return oss.str();
  120. }
  121. using f32Parameter = Parameter<f32, 1>;
  122. using v2fParameter = VectorParameter<v2f, 2>;
  123. using v3fParameter = VectorParameter<v3f, 3>;
  124. // Add more parameter types here if you need them ...
  125. // Bound limits information based on "Parameter" types
  126. template <typename T>
  127. struct RangedParameter
  128. {
  129. using ValType = T;
  130. using This = RangedParameter<T>;
  131. T min, max;
  132. f32 bias = 0;
  133. RangedParameter() = default;
  134. RangedParameter(T _min, T _max) : min(_min), max(_max) {}
  135. template <typename M> RangedParameter(M b) : min(b), max(b) {}
  136. // Binary format must not be changed. Function is to be deprecated.
  137. void legacySerialize(std::ostream &os) const
  138. {
  139. min.serialize(os);
  140. max.serialize(os);
  141. }
  142. void legacyDeSerialize(std::istream &is)
  143. {
  144. min.deSerialize(is);
  145. max.deSerialize(is);
  146. }
  147. void serialize(std::ostream &os) const;
  148. void deSerialize(std::istream &is);
  149. This interpolate(float fac, const This against) const
  150. {
  151. This r;
  152. r.min = min.interpolate(fac, against.min);
  153. r.max = max.interpolate(fac, against.max);
  154. r.bias = bias;
  155. return r;
  156. }
  157. // Pick a random value (e.g. position) within bounds
  158. T pickWithin() const;
  159. };
  160. template <typename T>
  161. inline std::string dump(const RangedParameter<T>& r)
  162. {
  163. std::ostringstream s;
  164. s << "range<" << dump(r.min) << " ~ " << dump(r.max);
  165. if (r.bias != 0)
  166. s << " :: " << r.bias;
  167. s << ">";
  168. return s.str();
  169. }
  170. // Animation styles (fwd is normal, linear interpolation)
  171. // TweenStyle_END is a dummy value for validity check
  172. enum class TweenStyle : u8 { fwd, rev, pulse, flicker, TweenStyle_END};
  173. // "Tweened" pretty much means "animated" in this context
  174. template <typename T>
  175. struct TweenedParameter
  176. {
  177. using ValType = T;
  178. using This = TweenedParameter<T>;
  179. TweenStyle style = TweenStyle::fwd;
  180. u16 reps = 1; // Blending repetitions (same pattern)
  181. f32 beginning = 0.0f; // Blending start offset
  182. T start, end;
  183. TweenedParameter() = default;
  184. TweenedParameter(T _start, T _end) : start(_start), end(_end) {}
  185. // For initializer lists and assignment
  186. template <typename M> TweenedParameter(M b) : start(b), end(b) {}
  187. // Blend (or animate) the current value
  188. T blend(float fac) const;
  189. void serialize(std::ostream &os) const;
  190. void deSerialize(std::istream &is);
  191. };
  192. template <typename T>
  193. inline std::string dump(const TweenedParameter<T>& t)
  194. {
  195. std::ostringstream s;
  196. const char* icon;
  197. switch (t.style) {
  198. case TweenStyle::fwd: icon = "→"; break;
  199. case TweenStyle::rev: icon = "←"; break;
  200. case TweenStyle::pulse: icon = "↔"; break;
  201. case TweenStyle::flicker: icon = "↯"; break;
  202. }
  203. s << "tween<";
  204. if (t.reps != 1)
  205. s << t.reps << "x ";
  206. s << dump(t.start) << " "<<icon<<" " << dump(t.end) << ">";
  207. return s.str();
  208. }
  209. enum class AttractorKind : u8 { none, point, line, plane };
  210. enum class BlendMode : u8 { alpha, add, sub, screen };
  211. // these are consistently-named convenience aliases to make code more readable without `using ParticleParamTypes` declarations
  212. using v3fRange = RangedParameter<v3fParameter>;
  213. using f32Range = RangedParameter<f32Parameter>;
  214. using v2fTween = TweenedParameter<v2fParameter>;
  215. using v3fTween = TweenedParameter<v3fParameter>;
  216. using f32Tween = TweenedParameter<f32Parameter>;
  217. using v3fRangeTween = TweenedParameter<v3fRange>;
  218. using f32RangeTween = TweenedParameter<f32Range>;
  219. #undef DECL_PARAM_SRZRS
  220. #undef DECL_PARAM_OVERLOADS
  221. }
  222. struct ParticleTexture
  223. {
  224. bool animated = false;
  225. ParticleParamTypes::BlendMode blendmode = ParticleParamTypes::BlendMode::alpha;
  226. TileAnimationParams animation;
  227. ParticleParamTypes::f32Tween alpha{1.0f};
  228. ParticleParamTypes::v2fTween scale{v2f(1.0f)};
  229. };
  230. struct ServerParticleTexture : public ParticleTexture
  231. {
  232. std::string string;
  233. void serialize(std::ostream &os, u16 protocol_ver, bool newPropertiesOnly = false) const;
  234. void deSerialize(std::istream &is, u16 protocol_ver, bool newPropertiesOnly = false);
  235. };
  236. struct CommonParticleParams
  237. {
  238. bool collisiondetection = false;
  239. bool collision_removal = false;
  240. bool object_collision = false;
  241. bool vertical = false;
  242. ServerParticleTexture texture;
  243. struct TileAnimationParams animation;
  244. u8 glow = 0;
  245. MapNode node;
  246. u8 node_tile = 0;
  247. CommonParticleParams() {
  248. animation.type = TAT_NONE;
  249. node.setContent(CONTENT_IGNORE);
  250. }
  251. /* This helper is useful for copying params from
  252. * ParticleSpawnerParameters to ParticleParameters */
  253. inline void copyCommon(CommonParticleParams &to) const {
  254. to.collisiondetection = collisiondetection;
  255. to.collision_removal = collision_removal;
  256. to.object_collision = object_collision;
  257. to.vertical = vertical;
  258. to.texture = texture;
  259. to.animation = animation;
  260. to.glow = glow;
  261. to.node = node;
  262. to.node_tile = node_tile;
  263. }
  264. };
  265. struct ParticleParameters : CommonParticleParams
  266. {
  267. v3f pos, vel, acc, drag;
  268. f32 size = 1, expirationtime = 1;
  269. ParticleParamTypes::f32Range bounce;
  270. ParticleParamTypes::v3fRange jitter;
  271. void serialize(std::ostream &os, u16 protocol_ver) const;
  272. void deSerialize(std::istream &is, u16 protocol_ver);
  273. };
  274. struct ParticleSpawnerParameters : CommonParticleParams
  275. {
  276. u16 amount = 1;
  277. f32 time = 1;
  278. std::vector<ServerParticleTexture> texpool;
  279. ParticleParamTypes::v3fRangeTween
  280. pos, vel, acc, drag, radius, jitter;
  281. ParticleParamTypes::AttractorKind
  282. attractor_kind;
  283. ParticleParamTypes::v3fTween
  284. attractor_origin, attractor_direction;
  285. // object IDs
  286. u16 attractor_attachment = 0,
  287. attractor_direction_attachment = 0;
  288. // do particles disappear when they cross the attractor threshold?
  289. bool attractor_kill = true;
  290. ParticleParamTypes::f32RangeTween
  291. exptime{1.0f},
  292. size {1.0f},
  293. attract{0.0f},
  294. bounce {0.0f};
  295. // For historical reasons no (de-)serialization methods here
  296. };