particles.h 11 KB

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