mirror of
https://github.com/minetest/minetest.git
synced 2024-08-18 20:44:16 +02:00
Someone of these are probably actual bugs and gcc totally doesn't care to warn about them, wtf? This issue seems to be new with the IrrlichtMt update.
295 lines
8.1 KiB
C++
295 lines
8.1 KiB
C++
/*
|
|
Minetest
|
|
Copyright (C) 2020 sfan5 <sfan5@live.de>
|
|
|
|
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.
|
|
*/
|
|
|
|
#include "particles.h"
|
|
#include <type_traits>
|
|
|
|
using namespace ParticleParamTypes;
|
|
|
|
template<typename T>
|
|
void RangedParameter<T>::serialize(std::ostream &os) const
|
|
{
|
|
min.serialize(os);
|
|
max.serialize(os);
|
|
writeF32(os, bias);
|
|
}
|
|
|
|
template<typename T>
|
|
void RangedParameter<T>::deSerialize(std::istream &is)
|
|
{
|
|
min.deSerialize(is);
|
|
max.deSerialize(is);
|
|
bias = readF32(is);
|
|
}
|
|
|
|
|
|
template<typename T>
|
|
T RangedParameter<T>::pickWithin() const
|
|
{
|
|
typename T::pickFactors values;
|
|
auto p = numericAbsolute(bias) + 1;
|
|
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); ++i) {
|
|
if (bias < 0)
|
|
values[i] = 1.0f - std::pow(myrand_float(), p);
|
|
else
|
|
values[i] = std::pow(myrand_float(), p);
|
|
}
|
|
return T::pick(values, min, max);
|
|
}
|
|
|
|
|
|
template<typename T>
|
|
T TweenedParameter<T>::blend(float fac) const
|
|
{
|
|
// warp time coordinates in accordance w/ settings
|
|
if (fac > beginning) {
|
|
// remap for beginning offset
|
|
auto len = 1 - beginning;
|
|
fac -= beginning;
|
|
fac /= len;
|
|
|
|
// remap for repetitions
|
|
fac *= reps;
|
|
if (fac > 1) // poor man's modulo
|
|
fac -= (decltype(reps))fac;
|
|
|
|
// remap for style
|
|
switch (style) {
|
|
case TweenStyle::fwd: /* do nothing */ break;
|
|
case TweenStyle::rev: fac = 1.0f - fac; break;
|
|
case TweenStyle::pulse:
|
|
case TweenStyle::flicker: {
|
|
if (fac > 0.5f) {
|
|
fac = 1.f - (fac*2.f - 1.f);
|
|
} else {
|
|
fac = fac * 2;
|
|
}
|
|
if (style == TweenStyle::flicker) {
|
|
fac *= myrand_range(0.7f, 1.0f);
|
|
}
|
|
}
|
|
case TweenStyle::TweenStyle_END:
|
|
break;
|
|
}
|
|
if (fac>1.f)
|
|
fac = 1.f;
|
|
else if (fac<0.f)
|
|
fac = 0.f;
|
|
} else {
|
|
fac = (style == TweenStyle::rev) ? 1.f : 0.f;
|
|
}
|
|
|
|
return start.interpolate(fac, end);
|
|
}
|
|
|
|
template<typename T>
|
|
void TweenedParameter<T>::serialize(std::ostream &os) const
|
|
{
|
|
writeU8(os, static_cast<u8>(style));
|
|
writeU16(os, reps);
|
|
writeF32(os, beginning);
|
|
start.serialize(os);
|
|
end.serialize(os);
|
|
}
|
|
|
|
template<typename T>
|
|
void TweenedParameter<T>::deSerialize(std::istream &is)
|
|
{
|
|
style = static_cast<TweenStyle>(readU8(is));
|
|
if (style >= TweenStyle::TweenStyle_END)
|
|
style = TweenStyle::fwd;
|
|
reps = readU16(is);
|
|
beginning = readF32(is);
|
|
start.deSerialize(is);
|
|
end.deSerialize(is);
|
|
}
|
|
|
|
namespace ParticleParamTypes {
|
|
// For function definitions
|
|
template struct RangedParameter<v3fParameter>;
|
|
template struct RangedParameter<f32Parameter>;
|
|
|
|
template struct TweenedParameter<v2fParameter>;
|
|
template struct TweenedParameter<v3fParameter>;
|
|
template struct TweenedParameter<f32Parameter>;
|
|
template struct TweenedParameter<v3fRange>;
|
|
template struct TweenedParameter<f32Range>;
|
|
}
|
|
|
|
// Linear interpolation
|
|
template <typename T>
|
|
static T numericalBlend(float fac, T min, T max)
|
|
{
|
|
return min + ((max - min) * fac);
|
|
}
|
|
|
|
#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
|
|
{
|
|
writeV3F32(os, pos);
|
|
writeV3F32(os, vel);
|
|
writeV3F32(os, acc);
|
|
writeF32(os, expirationtime);
|
|
writeF32(os, size);
|
|
writeU8(os, collisiondetection);
|
|
os << serializeString32(texture.string);
|
|
writeU8(os, vertical);
|
|
writeU8(os, collision_removal);
|
|
animation.serialize(os, protocol_ver);
|
|
writeU8(os, glow);
|
|
writeU8(os, object_collision);
|
|
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)
|
|
{
|
|
pos = readV3F32(is);
|
|
vel = readV3F32(is);
|
|
acc = readV3F32(is);
|
|
expirationtime = readF32(is);
|
|
size = readF32(is);
|
|
collisiondetection = readU8(is);
|
|
texture.string = deSerializeString32(is);
|
|
vertical = readU8(is);
|
|
collision_removal = readU8(is);
|
|
animation.deSerialize(is, protocol_ver);
|
|
glow = readU8(is);
|
|
object_collision = readU8(is);
|
|
|
|
if (streamEndsBeforeParam<u16, readU16>(node.param0, is))
|
|
return;
|
|
node.param2 = readU8(is);
|
|
node_tile = readU8(is);
|
|
|
|
if (streamEndsBeforeParam<v3f, readV3F32>(drag, is))
|
|
return;
|
|
jitter.deSerialize(is);
|
|
bounce.deSerialize(is);
|
|
}
|