diff options
Diffstat (limited to 'src/particles.cpp')
-rw-r--r-- | src/particles.cpp | 127 |
1 files changed, 120 insertions, 7 deletions
diff --git a/src/particles.cpp b/src/particles.cpp index 14c987958..19b3418b7 100644 --- a/src/particles.cpp +++ b/src/particles.cpp @@ -18,7 +18,103 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "particles.h" -#include "util/serialize.h" +#include <type_traits> +using namespace ParticleParamTypes; + +#define PARAM_PVFN(n) ParticleParamTypes::n##ParameterValue +v2f PARAM_PVFN(pick) (float* f, const v2f a, const v2f b) { + return v2f( + numericalBlend(f[0], a.X, b.X), + numericalBlend(f[1], a.Y, b.Y) + ); +} + +v3f PARAM_PVFN(pick) (float* f, const v3f a, const v3f b) { + return v3f( + numericalBlend(f[0], a.X, b.X), + numericalBlend(f[1], a.Y, b.Y), + numericalBlend(f[2], a.Z, b.Z) + ); +} + +v2f PARAM_PVFN(interpolate) (float fac, const v2f a, const v2f b) + { return b.getInterpolated(a, fac); } +v3f PARAM_PVFN(interpolate) (float fac, const v3f a, const v3f b) + { return b.getInterpolated(a, fac); } + +#define PARAM_DEF_SRZR(T, wr, rd) \ + void PARAM_PVFN(serialize) (std::ostream& os, T v) {wr(os,v); } \ + void PARAM_PVFN(deSerialize)(std::istream& is, T& v) {v = rd(is);} + + +#define PARAM_DEF_NUM(T, wr, rd) PARAM_DEF_SRZR(T, wr, rd) \ + T PARAM_PVFN(interpolate)(float fac, const T a, const T b) \ + { return numericalBlend<T>(fac,a,b); } \ + T PARAM_PVFN(pick) (float* f, const T a, const T b) \ + { return numericalBlend<T>(f[0],a,b); } + +PARAM_DEF_NUM(u8, writeU8, readU8); PARAM_DEF_NUM(s8, writeS8, readS8); +PARAM_DEF_NUM(u16, writeU16, readU16); PARAM_DEF_NUM(s16, writeS16, readS16); +PARAM_DEF_NUM(u32, writeU32, readU32); PARAM_DEF_NUM(s32, writeS32, readS32); +PARAM_DEF_NUM(f32, writeF32, readF32); +PARAM_DEF_SRZR(v2f, writeV2F32, readV2F32); +PARAM_DEF_SRZR(v3f, writeV3F32, readV3F32); + +enum class ParticleTextureFlags : u8 { + /* each value specifies a bit in a bitmask; if the maximum value + * goes above 1<<7 the type of the flags field must be changed + * from u8, which will necessitate a protocol change! */ + + // the first bit indicates whether the texture is animated + animated = 1, + + /* the next three bits indicate the blending mode of the texture + * blendmode is encoded by (flags |= (u8)blend << 1); retrieve with + * (flags & ParticleTextureFlags::blend) >> 1. note that the third + * bit is currently reserved for adding more blend modes in the future */ + blend = 0x7 << 1, +}; + +/* define some shorthand so we don't have to repeat ourselves or use + * decltype everywhere */ +using FlagT = std::underlying_type_t<ParticleTextureFlags>; + +void ServerParticleTexture::serialize(std::ostream &os, u16 protocol_ver, bool newPropertiesOnly) const +{ + /* newPropertiesOnly is used to de/serialize parameters of the legacy texture + * field, which are encoded separately from the texspec string */ + FlagT flags = 0; + if (animated) + flags |= FlagT(ParticleTextureFlags::animated); + if (blendmode != BlendMode::alpha) + flags |= FlagT(blendmode) << 1; + serializeParameterValue(os, flags); + + alpha.serialize(os); + scale.serialize(os); + if (!newPropertiesOnly) + os << serializeString32(string); + + if (animated) + animation.serialize(os, protocol_ver); +} + +void ServerParticleTexture::deSerialize(std::istream &is, u16 protocol_ver, bool newPropertiesOnly) +{ + FlagT flags = 0; + deSerializeParameterValue(is, flags); + + animated = !!(flags & FlagT(ParticleTextureFlags::animated)); + blendmode = BlendMode((flags & FlagT(ParticleTextureFlags::blend)) >> 1); + + alpha.deSerialize(is); + scale.deSerialize(is); + if (!newPropertiesOnly) + string = deSerializeString32(is); + + if (animated) + animation.deSerialize(is, protocol_ver); +} void ParticleParameters::serialize(std::ostream &os, u16 protocol_ver) const { @@ -28,7 +124,7 @@ void ParticleParameters::serialize(std::ostream &os, u16 protocol_ver) const writeF32(os, expirationtime); writeF32(os, size); writeU8(os, collisiondetection); - os << serializeString32(texture); + os << serializeString32(texture.string); writeU8(os, vertical); writeU8(os, collision_removal); animation.serialize(os, 6); /* NOT the protocol ver */ @@ -37,6 +133,20 @@ void ParticleParameters::serialize(std::ostream &os, u16 protocol_ver) const writeU16(os, node.param0); writeU8(os, node.param2); writeU8(os, node_tile); + writeV3F32(os, drag); + jitter.serialize(os); + bounce.serialize(os); +} + +template <typename T, T (reader)(std::istream& is)> +inline bool streamEndsBeforeParam(T& val, std::istream& is) +{ + // This is kinda awful + T tmp = reader(is); + if (is.eof()) + return true; + val = tmp; + return false; } void ParticleParameters::deSerialize(std::istream &is, u16 protocol_ver) @@ -47,17 +157,20 @@ void ParticleParameters::deSerialize(std::istream &is, u16 protocol_ver) expirationtime = readF32(is); size = readF32(is); collisiondetection = readU8(is); - texture = deSerializeString32(is); + texture.string = deSerializeString32(is); vertical = readU8(is); collision_removal = readU8(is); animation.deSerialize(is, 6); /* NOT the protocol ver */ glow = readU8(is); object_collision = readU8(is); - // This is kinda awful - u16 tmp_param0 = readU16(is); - if (is.eof()) + + if (streamEndsBeforeParam<u16, readU16>(node.param0, is)) return; - node.param0 = tmp_param0; node.param2 = readU8(is); node_tile = readU8(is); + + if (streamEndsBeforeParam<v3f, readV3F32>(drag, is)) + return; + jitter.deSerialize(is); + bounce.deSerialize(is); } |