diff options
Diffstat (limited to 'src/script/lua_api/l_particleparams.h')
-rw-r--r-- | src/script/lua_api/l_particleparams.h | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/src/script/lua_api/l_particleparams.h b/src/script/lua_api/l_particleparams.h new file mode 100644 index 000000000..4fefc5e3a --- /dev/null +++ b/src/script/lua_api/l_particleparams.h @@ -0,0 +1,279 @@ +/* +Minetest +Copyright (C) 2021 velartrill, Lexi Hale <lexi@hale.su> + +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 "lua_api/l_particles.h" +#include "lua_api/l_object.h" +#include "lua_api/l_internal.h" +#include "common/c_converter.h" +#include "common/c_content.h" +#include "server.h" +#include "particles.h" + +namespace LuaParticleParams +{ + using namespace ParticleParamTypes; + + template<typename T> + inline void readNumericLuaValue(lua_State* L, T& ret) + { + if (lua_isnil(L,-1)) + return; + + if (std::is_integral<T>()) + ret = lua_tointeger(L, -1); + else + ret = lua_tonumber(L, -1); + } + + template <typename T, size_t N> + inline void readNumericLuaValue(lua_State* L, Parameter<T,N>& ret) + { + readNumericLuaValue<T>(L, ret.val); + } + + // these are unfortunately necessary as C++ intentionally disallows function template + // specialization and there's no way to make template overloads reliably resolve correctly + inline void readLuaValue(lua_State* L, f32Parameter& ret) { readNumericLuaValue(L, ret); } + inline void readLuaValue(lua_State* L, f32& ret) { readNumericLuaValue(L, ret); } + inline void readLuaValue(lua_State* L, u16& ret) { readNumericLuaValue(L, ret); } + inline void readLuaValue(lua_State* L, u8& ret) { readNumericLuaValue(L, ret); } + + inline void readLuaValue(lua_State* L, v3fParameter& ret) + { + if (lua_isnil(L, -1)) + return; + + if (lua_isnumber(L, -1)) { // shortcut for uniform vectors + auto n = lua_tonumber(L, -1); + ret = v3fParameter(n,n,n); + } else { + ret = (v3fParameter)check_v3f(L, -1); + } + } + + inline void readLuaValue(lua_State* L, v2fParameter& ret) + { + if (lua_isnil(L, -1)) + return; + + if (lua_isnumber(L, -1)) { // shortcut for uniform vectors + auto n = lua_tonumber(L, -1); + ret = v2fParameter(n,n); + } else { + ret = (v2fParameter)check_v2f(L, -1); + } + } + + inline void readLuaValue(lua_State* L, TweenStyle& ret) + { + if (lua_isnil(L, -1)) + return; + + static const EnumString opts[] = { + {(int)TweenStyle::fwd, "fwd"}, + {(int)TweenStyle::rev, "rev"}, + {(int)TweenStyle::pulse, "pulse"}, + {(int)TweenStyle::flicker, "flicker"}, + {0, nullptr}, + }; + + luaL_checktype(L, -1, LUA_TSTRING); + int v = (int)TweenStyle::fwd; + if (!string_to_enum(opts, v, lua_tostring(L, -1))) { + throw LuaError("tween style must be one of ('fwd', 'rev', 'pulse', 'flicker')"); + } + ret = (TweenStyle)v; + } + + inline void readLuaValue(lua_State* L, AttractorKind& ret) + { + if (lua_isnil(L, -1)) + return; + + static const EnumString opts[] = { + {(int)AttractorKind::none, "none"}, + {(int)AttractorKind::point, "point"}, + {(int)AttractorKind::line, "line"}, + {(int)AttractorKind::plane, "plane"}, + {0, nullptr}, + }; + + luaL_checktype(L, -1, LUA_TSTRING); + int v = (int)AttractorKind::none; + if (!string_to_enum(opts, v, lua_tostring(L, -1))) { + throw LuaError("attractor kind must be one of ('none', 'point', 'line', 'plane')"); + } + ret = (AttractorKind)v; + } + + inline void readLuaValue(lua_State* L, BlendMode& ret) + { + if (lua_isnil(L, -1)) + return; + + static const EnumString opts[] = { + {(int)BlendMode::alpha, "alpha"}, + {(int)BlendMode::add, "add"}, + {(int)BlendMode::sub, "sub"}, + {(int)BlendMode::screen, "screen"}, + {0, nullptr}, + }; + + luaL_checktype(L, -1, LUA_TSTRING); + int v = (int)BlendMode::alpha; + if (!string_to_enum(opts, v, lua_tostring(L, -1))) { + throw LuaError("blend mode must be one of ('alpha', 'add', 'sub', 'screen')"); + } + ret = (BlendMode)v; + } + + template <typename T> void + readLuaValue(lua_State* L, RangedParameter<T>& field) + { + if (lua_isnil(L,-1)) + return; + if (!lua_istable(L,-1)) // is this is just a literal value? + goto set_uniform; + + lua_getfield(L, -1, "min"); + // handle convenience syntax for non-range values + if (lua_isnil(L,-1)) { + lua_pop(L, 1); + goto set_uniform; + } + readLuaValue(L,field.min); + lua_pop(L, 1); + + lua_getfield(L, -1, "max"); + readLuaValue(L,field.max); + lua_pop(L, 1); + + lua_getfield(L, -1, "bias"); + if (!lua_isnil(L,-1)) + readLuaValue(L,field.bias); + lua_pop(L, 1); + return; + + set_uniform: + readLuaValue(L, field.min); + readLuaValue(L, field.max); + } + + template <typename T> void + readLegacyValue(lua_State* L, const char* name, T& field) {} + + template <typename T> void + readLegacyValue(lua_State* L, const char* name, RangedParameter<T>& field) + { + int tbl = lua_gettop(L); + lua_pushliteral(L, "min"); + lua_pushstring(L, name); + lua_concat(L, 2); + lua_gettable(L, tbl); + if (!lua_isnil(L, -1)) { + readLuaValue(L, field.min); + } + lua_settop(L, tbl); + + lua_pushliteral(L, "max"); + lua_pushstring(L, name); + lua_concat(L, 2); + lua_gettable(L, tbl); + if (!lua_isnil(L, -1)) { + readLuaValue(L, field.max); + } + lua_settop(L, tbl); + } + + template <typename T> void + readTweenTable(lua_State* L, const char* name, TweenedParameter<T>& field) + { + int tbl = lua_gettop(L); + + lua_pushstring(L, name); + lua_pushliteral(L, "_tween"); + lua_concat(L, 2); + lua_gettable(L, tbl); + if(lua_istable(L, -1)) { + int tween = lua_gettop(L); + // get the starting value + lua_pushinteger(L, 1), lua_gettable(L, tween); + readLuaValue(L, field.start); + lua_pop(L, 1); + + // get the final value -- use len instead of 2 so that this + // gracefully degrades if keyframe support is later added + lua_pushinteger(L, (lua_Integer)lua_objlen(L, -1)), lua_gettable(L, tween); + readLuaValue(L, field.end); + lua_pop(L, 1); + + // get the effect settings + lua_getfield(L, -1, "style"); + lua_isnil(L,-1) || (readLuaValue(L, field.style), true); + lua_pop(L, 1); + + lua_getfield(L, -1, "reps"); + lua_isnil(L,-1) || (readLuaValue(L, field.reps), true); + lua_pop(L, 1); + + lua_getfield(L, -1, "start"); + lua_isnil(L,-1) || (readLuaValue(L, field.beginning), true); + lua_pop(L, 1); + + goto done; + } else { + lua_pop(L,1); + } + // the table is not present; check for nonanimated values + + lua_getfield(L, tbl, name); + if(!lua_isnil(L, -1)) { + readLuaValue(L, field.start); + lua_settop(L, tbl); + goto set_uniform; + } else { + lua_pop(L,1); + } + + // the goto did not trigger, so this table is not present either + // check for pre-5.6.0 legacy values + readLegacyValue(L, name, field.start); + + set_uniform: + field.end = field.start; + done: + lua_settop(L, tbl); // clean up after ourselves + } + + inline u16 readAttachmentID(lua_State* L, const char* name) + { + u16 id = 0; + lua_getfield(L, -1, name); + if (!lua_isnil(L, -1)) { + ObjectRef *ref = ObjectRef::checkobject(L, -1); + if (auto obj = ObjectRef::getobject(ref)) + id = obj->getId(); + } + lua_pop(L, 1); + return id; + } + + void readTexValue(lua_State* L, ServerParticleTexture& tex); +} |