123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- /*
- Minetest
- Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
- #pragma once
- #include <string>
- #include <sstream>
- #include <vector>
- #include <ctgmath>
- #include <type_traits>
- #include "irrlicht_changes/printing.h"
- #include "irrlichttypes_bloated.h"
- #include "tileanimation.h"
- #include "mapnode.h"
- #include "util/serialize.h"
- #include "util/numeric.h"
- // This file defines the particle-related structures that both the server and
- // client need. The ParticleManager and rendering is in client/particles.h
- namespace ParticleParamTypes
- {
- template <bool cond, typename T>
- using enableIf = typename std::enable_if<cond, T>::type;
- // std::enable_if_t does not appear to be present in GCC????
- // std::is_enum_v also missing. wtf. these are supposed to be
- // present as of c++14
- template<typename T> using BlendFunction = T(float,T,T);
- #define DECL_PARAM_SRZRS(type) \
- void serializeParameterValue (std::ostream& os, type v); \
- void deSerializeParameterValue(std::istream& is, type& r);
- #define DECL_PARAM_OVERLOADS(type) DECL_PARAM_SRZRS(type) \
- type interpolateParameterValue(float fac, const type a, const type b); \
- type pickParameterValue (float* facs, const type a, const type b);
- // Function definition: see "particles.cpp"
- DECL_PARAM_OVERLOADS(u8); DECL_PARAM_OVERLOADS(s8);
- DECL_PARAM_OVERLOADS(u16); DECL_PARAM_OVERLOADS(s16);
- DECL_PARAM_OVERLOADS(u32); DECL_PARAM_OVERLOADS(s32);
- DECL_PARAM_OVERLOADS(f32);
- DECL_PARAM_OVERLOADS(v2f);
- DECL_PARAM_OVERLOADS(v3f);
- /* C++ is a strongly typed language. this means that enums cannot be implicitly
- * cast to integers, as they can be in C. while this may sound good in principle,
- * it means that our normal serialization functions cannot be called on
- * enumerations unless they are explicitly cast to a particular type first. this
- * is problematic, because in C++ enums can have any integral type as an underlying
- * type, and that type would need to be named everywhere an enumeration is
- * de/serialized.
- *
- * this is obviously not cool, both in terms of writing legible, succinct code,
- * and in terms of robustness: the underlying type might be changed at some point,
- * e.g. if a bitmask gets too big for its britches. we could use an equivalent of
- * `std::to_underlying(value)` everywhere we need to deal with enumerations, but
- * that's hideous and unintuitive. instead, we supply the following functions to
- * transparently map enumeration types to their underlying values. */
- template <typename E, enableIf<std::is_enum<E>::value, bool> = true>
- void serializeParameterValue(std::ostream& os, E k) {
- serializeParameterValue(os, (std::underlying_type_t<E>)k);
- }
- template <typename E, enableIf<std::is_enum<E>::value, bool> = true>
- void deSerializeParameterValue(std::istream& is, E& k) {
- std::underlying_type_t<E> v;
- deSerializeParameterValue(is, v);
- k = (E)v;
- }
- // Describes a single value
- template <typename T, size_t PN>
- struct Parameter
- {
- using ValType = T;
- using pickFactors = float[PN];
- T val = T();
- using This = Parameter<T, PN>;
- Parameter() = default;
- template <typename... Args>
- Parameter(Args... args) : val(args...) {}
- virtual void serialize(std::ostream &os) const
- { serializeParameterValue (os, this->val); }
- virtual void deSerialize(std::istream &is)
- { deSerializeParameterValue(is, this->val); }
- virtual T interpolate(float fac, const This& against) const
- {
- return interpolateParameterValue(fac, this->val, against.val);
- }
- static T pick(float* f, const This& a, const This& b)
- {
- return pickParameterValue(f, a.val, b.val);
- }
- operator T() const { return val; }
- T operator=(T b) { return val = b; }
- };
- // New struct required to differentiate between core::vectorNd-compatible
- // structs for proper value dumping (debugging)
- template <typename T, size_t N>
- struct VectorParameter : public Parameter<T,N> {
- using This = VectorParameter<T,N>;
- template <typename... Args>
- VectorParameter(Args... args) : Parameter<T,N>(args...) {}
- };
- template <typename T, size_t PN>
- inline std::string dump(const Parameter<T,PN>& p)
- {
- return std::to_string(p.val);
- }
- template <typename T, size_t N>
- inline std::string dump(const VectorParameter<T,N>& v)
- {
- std::ostringstream oss;
- oss << v.val;
- return oss.str();
- }
- using f32Parameter = Parameter<f32, 1>;
- using v2fParameter = VectorParameter<v2f, 2>;
- using v3fParameter = VectorParameter<v3f, 3>;
- // Add more parameter types here if you need them ...
- // Bound limits information based on "Parameter" types
- template <typename T>
- struct RangedParameter
- {
- using ValType = T;
- using This = RangedParameter<T>;
- T min, max;
- f32 bias = 0;
- RangedParameter() = default;
- RangedParameter(T _min, T _max) : min(_min), max(_max) {}
- template <typename M> RangedParameter(M b) : min(b), max(b) {}
- // Binary format must not be changed. Function is to be deprecated.
- void legacySerialize(std::ostream &os) const
- {
- min.serialize(os);
- max.serialize(os);
- }
- void legacyDeSerialize(std::istream &is)
- {
- min.deSerialize(is);
- max.deSerialize(is);
- }
- void serialize(std::ostream &os) const;
- void deSerialize(std::istream &is);
- This interpolate(float fac, const This against) const
- {
- This r;
- r.min = min.interpolate(fac, against.min);
- r.max = max.interpolate(fac, against.max);
- r.bias = bias;
- return r;
- }
- // Pick a random value (e.g. position) within bounds
- T pickWithin() const;
- };
- template <typename T>
- inline std::string dump(const RangedParameter<T>& r)
- {
- std::ostringstream s;
- s << "range<" << dump(r.min) << " ~ " << dump(r.max);
- if (r.bias != 0)
- s << " :: " << r.bias;
- s << ">";
- return s.str();
- }
- // Animation styles (fwd is normal, linear interpolation)
- // TweenStyle_END is a dummy value for validity check
- enum class TweenStyle : u8 { fwd, rev, pulse, flicker, TweenStyle_END};
- // "Tweened" pretty much means "animated" in this context
- template <typename T>
- struct TweenedParameter
- {
- using ValType = T;
- using This = TweenedParameter<T>;
- TweenStyle style = TweenStyle::fwd;
- u16 reps = 1; // Blending repetitions (same pattern)
- f32 beginning = 0.0f; // Blending start offset
- T start, end;
- TweenedParameter() = default;
- TweenedParameter(T _start, T _end) : start(_start), end(_end) {}
- // For initializer lists and assignment
- template <typename M> TweenedParameter(M b) : start(b), end(b) {}
- // Blend (or animate) the current value
- T blend(float fac) const;
- void serialize(std::ostream &os) const;
- void deSerialize(std::istream &is);
- };
- template <typename T>
- inline std::string dump(const TweenedParameter<T>& t)
- {
- std::ostringstream s;
- const char* icon;
- switch (t.style) {
- case TweenStyle::fwd: icon = "→"; break;
- case TweenStyle::rev: icon = "←"; break;
- case TweenStyle::pulse: icon = "↔"; break;
- case TweenStyle::flicker: icon = "↯"; break;
- }
- s << "tween<";
- if (t.reps != 1)
- s << t.reps << "x ";
- s << dump(t.start) << " "<<icon<<" " << dump(t.end) << ">";
- return s.str();
- }
- enum class AttractorKind : u8 { none, point, line, plane };
- enum class BlendMode : u8 { alpha, add, sub, screen };
- // these are consistently-named convenience aliases to make code more readable without `using ParticleParamTypes` declarations
- using v3fRange = RangedParameter<v3fParameter>;
- using f32Range = RangedParameter<f32Parameter>;
- using v2fTween = TweenedParameter<v2fParameter>;
- using v3fTween = TweenedParameter<v3fParameter>;
- using f32Tween = TweenedParameter<f32Parameter>;
- using v3fRangeTween = TweenedParameter<v3fRange>;
- using f32RangeTween = TweenedParameter<f32Range>;
- #undef DECL_PARAM_SRZRS
- #undef DECL_PARAM_OVERLOADS
- }
- struct ParticleTexture
- {
- bool animated = false;
- ParticleParamTypes::BlendMode blendmode = ParticleParamTypes::BlendMode::alpha;
- TileAnimationParams animation;
- ParticleParamTypes::f32Tween alpha{1.0f};
- ParticleParamTypes::v2fTween scale{v2f(1.0f)};
- };
- struct ServerParticleTexture : public ParticleTexture
- {
- std::string string;
- void serialize(std::ostream &os, u16 protocol_ver, bool newPropertiesOnly = false) const;
- void deSerialize(std::istream &is, u16 protocol_ver, bool newPropertiesOnly = false);
- };
- struct CommonParticleParams
- {
- bool collisiondetection = false;
- bool collision_removal = false;
- bool object_collision = false;
- bool vertical = false;
- ServerParticleTexture texture;
- struct TileAnimationParams animation;
- u8 glow = 0;
- MapNode node;
- u8 node_tile = 0;
- CommonParticleParams() {
- animation.type = TAT_NONE;
- node.setContent(CONTENT_IGNORE);
- }
- /* This helper is useful for copying params from
- * ParticleSpawnerParameters to ParticleParameters */
- inline void copyCommon(CommonParticleParams &to) const {
- to.collisiondetection = collisiondetection;
- to.collision_removal = collision_removal;
- to.object_collision = object_collision;
- to.vertical = vertical;
- to.texture = texture;
- to.animation = animation;
- to.glow = glow;
- to.node = node;
- to.node_tile = node_tile;
- }
- };
- struct ParticleParameters : CommonParticleParams
- {
- v3f pos, vel, acc, drag;
- f32 size = 1, expirationtime = 1;
- ParticleParamTypes::f32Range bounce;
- ParticleParamTypes::v3fRange jitter;
- void serialize(std::ostream &os, u16 protocol_ver) const;
- void deSerialize(std::istream &is, u16 protocol_ver);
- };
- struct ParticleSpawnerParameters : CommonParticleParams
- {
- u16 amount = 1;
- f32 time = 1;
- std::vector<ServerParticleTexture> texpool;
- ParticleParamTypes::v3fRangeTween
- pos, vel, acc, drag, radius, jitter;
- ParticleParamTypes::AttractorKind
- attractor_kind;
- ParticleParamTypes::v3fTween
- attractor_origin, attractor_direction;
- // object IDs
- u16 attractor_attachment = 0,
- attractor_direction_attachment = 0;
- // do particles disappear when they cross the attractor threshold?
- bool attractor_kill = true;
- ParticleParamTypes::f32RangeTween
- exptime{1.0f},
- size {1.0f},
- attract{0.0f},
- bounce {0.0f};
- // For historical reasons no (de-)serialization methods here
- };
|