--- /dev/null
+{
+ "configurations": [
+ {
+ "name": "x64-Debug",
+ "generator": "Ninja",
+ "configurationType": "Debug",
+ "inheritEnvironments": [ "msvc_x64_x64" ],
+ "buildRoot": "${projectDir}\\out\\build\\${name}",
+ "installRoot": "${projectDir}\\out\\install\\${name}",
+ "cmakeCommandArgs": "",
+ "buildCommandArgs": "",
+ "ctestCommandArgs": "",
+ "variables": [],
+ "cmakeToolchain": "D:/Code Projects/vcpkg/scripts/buildsystems/vcpkg.cmake"
+ }
+ ]
+}
\ No newline at end of file
serverenvironment.cpp
serverlist.cpp
settings.cpp
+ splinesequence.cpp
staticobject.cpp
terminal_chat_console.cpp
texture_override.cpp
version.cpp
voxel.cpp
voxelalgorithms.cpp
+ wieldanimation.cpp
hud.cpp
${common_network_SRCS}
${JTHREAD_SRCS}
#include "constants.h"
#include "fontengine.h"
#include "script/scripting_client.h"
+#include "wieldanimation.h"
#define CAMERA_OFFSET_STEP 200
#define WIELDMESH_OFFSET_X 55.0f
bool was_under_zero = m_wield_change_timer < 0;
m_wield_change_timer = MYMIN(m_wield_change_timer + dtime, 0.125);
- if (m_wield_change_timer >= 0 && was_under_zero)
+if (m_wield_change_timer >= 0 && was_under_zero) {
m_wieldnode->setItem(m_wield_item_next, m_client);
+ m_wield_animation = m_wield_item_next
+ .getDefinition(m_client->getItemDefManager())
+ .wield_animation;
+}
if (m_view_bobbing_state != 0)
{
}
if (m_digging_button != -1) {
- f32 offset = dtime * 3.5f;
float m_digging_anim_was = m_digging_anim;
- m_digging_anim += offset;
- if (m_digging_anim >= 1)
+ m_digging_anim += dtime;
+ const WieldAnimation &wield_anim = WieldAnimation::getNamed(m_wield_animation);
+ if (m_digging_anim >= wield_anim.getDuration())
{
m_digging_anim = 0;
m_digging_button = -1;
}
- float lim = 0.15;
+ float lim = 0.05f;
if(m_digging_anim_was < lim && m_digging_anim >= lim)
{
if (m_digging_button == 0) {
if (m_arm_inertia)
addArmInertia(player->getYaw());
+ const WieldAnimation &wield_anim = WieldAnimation::getNamed(m_wield_animation);
+
// Position the wielded item
//v3f wield_position = v3f(45, -35, 65);
v3f wield_position = v3f(m_wieldmesh_offset.X, m_wieldmesh_offset.Y, 65);
//v3f wield_rotation = v3f(-100, 120, -100);
v3f wield_rotation = v3f(-100, 120, -100);
+ core::quaternion wield_rotation_q = core::quaternion(wield_rotation * core::DEGTORAD);
wield_position.Y += fabs(m_wield_change_timer)*320 - 40;
+#if 0
if(m_digging_anim < 0.05 || m_digging_anim > 0.5)
{
f32 frac = 1.0;
//wield_rotation.X -= frac * 15.0 * pow(ratiothing2, 1.4f);
//wield_rotation.Z += frac * 15.0 * pow(ratiothing2, 1.0f);
}
+#endif
if (m_digging_button != -1)
{
f32 digfrac = m_digging_anim;
- wield_position.X -= 50 * sin(pow(digfrac, 0.8f) * M_PI);
- wield_position.Y += 24 * sin(digfrac * 1.8 * M_PI);
- wield_position.Z += 25 * 0.5;
+ v3f anim_position = wield_anim.getTranslationAt(digfrac);
+ wield_position.X += anim_position.X;
+ wield_position.Y += anim_position.Y;
+ wield_position.Z += anim_position.Z;
// Euler angles are PURE EVIL, so why not use quaternions?
- core::quaternion quat_begin(wield_rotation * core::DEGTORAD);
- core::quaternion quat_end(v3f(80, 30, 100) * core::DEGTORAD);
- core::quaternion quat_slerp;
- quat_slerp.slerp(quat_begin, quat_end, sin(digfrac * M_PI));
- quat_slerp.toEuler(wield_rotation);
+ core::quaternion quat_rot = wield_anim.getRotationAt(digfrac);
+ // apply rotation to starting rotation
+ wield_rotation_q *= quat_rot;
+ // convert back to euler angles
+ wield_rotation_q.toEuler(wield_rotation);
wield_rotation *= core::RADTODEG;
} else {
f32 bobfrac = my_modf(m_view_bobbing_anim);
+ // std::cout << "Third block, frac = " << bobfrac << std::endl;
wield_position.X -= sin(bobfrac*M_PI*2.0) * 3.0;
wield_position.Y += sin(my_modf(bobfrac*2.0)*M_PI) * 3.0;
+#if 0
+ // to help with finding rotations, change the '0' above
+ // to '1' and recompile, then fly around.
+
+ wield_position.X += -50;
+ wield_position.Y += 20;
+ wield_position.Z += 0;
+
+ float pitch = wrapDegrees_180(player_position.X);
+ float yaw = wrapDegrees_180(player_position.Y);
+ float roll = wrapDegrees_180(player_position.Z);
+ //wield_rotation_q *= core::quaternion(
+ // (pitch) * core::DEGTORAD,
+ // (roll) * core::DEGTORAD,
+ // (yaw) * core::DEGTORAD
+ //);
+ wield_rotation_q *= core::quaternion(pitch * core::DEGTORAD, 0, 0);
+ wield_rotation_q *= core::quaternion(0, yaw * core::DEGTORAD, 0);
+ wield_rotation_q *= core::quaternion(0, 0, roll * core::DEGTORAD);
+ dstream << "Wield rotation " << pitch << ", " << yaw << ", " << roll << std::endl;
+ // -90, 15, -60
+ // convert back to euler angles
+ wield_rotation_q.toEuler(wield_rotation);
+ wield_rotation *= core::RADTODEG;
+#endif
+ }
+ if (!wield_position.equals(v3f(55, -35, 65))) {
+ // std::cout << m_digging_anim << ": " << wield_position.X-55 << ", " << wield_position.Y+35 << ", " << wield_position.Z-65 << std::endl;
}
m_wieldnode->setPosition(wield_position);
m_wieldnode->setRotation(wield_rotation);
// Fall view bobbing
f32 m_view_bobbing_fall = 0.0f;
- // Digging animation frame (0 <= m_digging_anim < 1)
+ // Digging animation frame, in seconds
+ // (0 <= m_digging_anim < m_wield_animation.getDuration())
f32 m_digging_anim = 0.0f;
// If -1, no digging animation
// If 0, left-click digging animation
// If 1, right-click digging animation
s32 m_digging_button = -1;
+ std::string m_wield_animation = "";
// Animation when changing wielded item
f32 m_wield_change_timer = 0.125f;
inventory_overlay = def.inventory_overlay;
wield_image = def.wield_image;
wield_overlay = def.wield_overlay;
+ wield_animation = def.wield_animation;
wield_scale = def.wield_scale;
stack_max = def.stack_max;
usable = def.usable;
inventory_overlay = "";
wield_image = "";
wield_overlay = "";
+ wield_animation = "";
palette_image = "";
color = video::SColor(0xFFFFFFFF);
wield_scale = v3f(1.0, 1.0, 1.0);
writeARGB8(os, color);
os << serializeString16(inventory_overlay);
os << serializeString16(wield_overlay);
+ os << serializeString(wield_animation);
os << serializeString16(short_description);
}
// block to not need to increase the version.
try {
short_description = deSerializeString16(is);
- } catch(SerializationError &e) {};
+ wield_animation = deSerializeString(is);
+ } catch (SerializationError &e) {
+ }
}
#include "itemgroup.h"
#include "sound.h"
#include "texture_override.h" // TextureOverride
+#include <vector>
+#include "wieldanimation.h"
class IGameDef;
class Client;
struct ToolCapabilities;
*/
std::string inventory_image; // Optional for nodes, mandatory for tools/craftitems
std::string inventory_overlay; // Overlay of inventory_image.
+ std::string wield_animation; // Named wield animation
std::string wield_image; // If empty, inventory_image or mesh (only nodes) is used
std::string wield_overlay; // Overlay of wield_image.
std::string palette_image; // If specified, the item will be colorized based on this
video::SColor color; // The fallback color of the node.
v3f wield_scale;
+ WieldAnimation animation;
/*
Item stack and interaction properties
#include "noise.h"
#include "server/player_sao.h"
#include "util/pointedthing.h"
+#include <utility>
+#include <algorithm>
#include "debug.h" // For FATAL_ERROR
#include <json/json.h>
getstringfield(L, index, "inventory_overlay", def.inventory_overlay);
getstringfield(L, index, "wield_image", def.wield_image);
getstringfield(L, index, "wield_overlay", def.wield_overlay);
+ getstringfield(L, index, "wield_animation", def.wield_animation);
getstringfield(L, index, "palette", def.palette_image);
// Read item color.
getstringfield(L, index, "node_placement_prediction",
def.node_placement_prediction);
}
+/******************************************************************************/
+void read_wield_animation(lua_State *L, int index)
+{
+ if (index < 0)
+ index = lua_gettop(L) + 1 + index;
+ std::string name;
+ getstringfield(L, index, "name", name);
+ if (WieldAnimation::repository.size() == 0)
+ WieldAnimation::fillRepository();
+ if (WieldAnimation::repository.find(name) != WieldAnimation::repository.end()) {
+ WieldAnimation::repository.erase(name);
+ }
+ WieldAnimation &anim = WieldAnimation::repository[name];
+ anim.name = name;
+ float totalDuration;
+ getfloatfield(L, index, "duration", totalDuration);
+ lua_getfield(L, index, "translation");
+ if (lua_istable(L, -1)) {
+ int table_translation = lua_gettop(L);
+ lua_pushnil(L);
+ lua_getfield(L, table_translation, "nodes");
+ if (lua_istable(L, -1)) {
+ int table_nodes = lua_gettop(L);
+ lua_pushnil(L);
+ std::vector<std::pair<int, v3f>> nodes;
+ while (lua_next(L, table_nodes) != 0) {
+ int i = luaL_checkinteger(L, -2);
+ v3f node = check_v3f(L, -1);
+ std::pair<int, v3f> unorderedNode(i, node);
+ nodes.push_back(unorderedNode);
+ lua_pop(L, 1);
+ }
+ sort(nodes.begin(), nodes.end());
+ for (std::size_t i = 0; i < nodes.size(); i++) {
+ anim.m_translationspline.addNode(nodes[i].second);
+ }
+ }
+ lua_pop(L, 1);
+ lua_getfield(L, table_translation, "indices");
+ if (lua_istable(L, -1)) {
+ int table_indices = lua_gettop(L);
+ lua_pushnil(L);
+ while (lua_next(L, table_indices) != 0) {
+ if (lua_istable(L, -1)) {
+ float duration;
+ u32 offset = 0;
+ u32 length = 0;
+ getfloatfield(L, -1, "duration", duration);
+ getintfield(L, -1, "offset", offset);
+ getintfield(L, -1, "length", length);
+ anim.m_translationspline.addIndex(duration, offset, length);
+ }
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+
+ lua_getfield(L, index, "rotation");
+ if (lua_istable(L, -1)) {
+ int table_rotation = lua_gettop(L);
+ lua_pushnil(L);
+ lua_getfield(L, table_rotation, "nodes");
+ if (lua_istable(L, -1)) {
+ int table_nodes = lua_gettop(L);
+ lua_pushnil(L);
+ std::vector<std::pair<int, v3f>> nodes;
+ while (lua_next(L, table_nodes) != 0) {
+ int i = luaL_checkinteger(L, -2);
+ v3f node = check_v3f(L, -1);
+ std::pair<int, v3f> unorderedNode(i, node);
+ nodes.push_back(unorderedNode);
+ lua_pop(L, 1);
+ }
+ sort(nodes.begin(), nodes.end());
+ for (std::size_t i = 0; i < nodes.size(); i++) {
+ anim.m_rotationspline.addNode(
+ WieldAnimation::quatFromAngles(
+ nodes[i].second.X,
+ nodes[i].second.Y,
+ nodes[i].second.Z));
+ }
+ }
+ lua_getfield(L, table_rotation, "indices");
+ if (lua_istable(L, -1)) {
+ int table_indices = lua_gettop(L);
+ lua_pushnil(L);
+ while (lua_next(L, table_indices) != 0) {
+ if (lua_istable(L, -1)) {
+ float duration;
+ u32 offset = 0;
+ u32 length = 0;
+ getfloatfield(L, -1, "duration", duration);
+ getintfield(L, -1, "offset", offset);
+ getintfield(L,-1, "length", length);
+ anim.m_rotationspline.addIndex(duration, offset, length);
+ }
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+ }
+ anim.setDuration(totalDuration);
+ lua_pop(L, 1);
+}
/******************************************************************************/
void push_item_definition(lua_State *L, const ItemDefinition &i)
{
#include <iostream>
#include <vector>
-
#include "irrlichttypes_bloated.h"
#include "util/string.h"
#include "itemgroup.h"
struct PointedThing;
struct ItemStack;
struct ItemDefinition;
+
struct ToolCapabilities;
struct ObjectProperties;
struct SimpleSoundSpec;
const ItemDefinition &i);
void push_item_definition_full (lua_State *L,
const ItemDefinition &i);
+void read_wield_animation(lua_State *L, int index);
void read_object_properties (lua_State *L, int index,
ServerActiveObject *sao,
return 1; /* number of results */
}
+int ModApiItemMod::l_register_wield_animation(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ luaL_checktype(L, 1, LUA_TTABLE);
+ int table = 1;
+
+ read_wield_animation(L, table);
+ return 0; /* number of results */
+}
+
void ModApiItemMod::Initialize(lua_State *L, int top)
{
+ API_FCT(register_wield_animation);
API_FCT(register_item_raw);
API_FCT(unregister_item_raw);
API_FCT(register_alias_raw);
static int l_register_alias_raw(lua_State *L);
static int l_get_content_id(lua_State *L);
static int l_get_name_from_content_id(lua_State *L);
+ static int l_register_wield_animation(lua_State *L);
public:
static void Initialize(lua_State *L, int top);
};
--- /dev/null
+/*
+Minetest SplineSequence
+Copyright (C) 2016-2018 Ben Deutsch <ben@bendeutsch.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 "splinesequence.h"
+#include "irrlichttypes_extrabloated.h"
+
+SplineSequence<core::quaternion> quatSplineSequence;
+
+static void fill_it()
+{
+ core::quaternion a_quat;
+ quatSplineSequence.addNode(a_quat);
+ quatSplineSequence.addIndex(0.0, 0, 0);
+ quatSplineSequence.normalizeDurations();
+}
+
+// some specializations
+
+template <>
+core::quaternion SplineSequence<core::quaternion>::_interpolate(
+ core::quaternion &bottom, core::quaternion &top, float alpha) const
+{
+ core::quaternion result;
+ // slerp or lerp? We're dealing with splines anyway...
+ result.slerp(bottom, top, alpha);
+ return result;
+}
--- /dev/null
+/*
+Minetest SplineSequence
+Copyright (C) 2016-2018 Ben Deutsch <ben@bendeutsch.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.
+*/
+
+#pragma once
+
+#include "irrlichttypes_extrabloated.h"
+#include <vector>
+#include <iostream>
+#include <quaternion.h>
+
+struct SplineIndex
+{
+ float duration;
+ unsigned int offset;
+ unsigned int length;
+};
+
+template <typename T> class SplineSequence
+{
+private:
+ std::vector<T> nodes;
+ std::vector<SplineIndex> indices;
+ float m_totalDuration;
+
+public:
+ SplineSequence();
+ ~SplineSequence();
+
+ std::vector<T> getNodes();
+ std::vector<SplineIndex> getIndices();
+ SplineSequence<T> &addNode(T node);
+ SplineSequence<T> &addIndex(
+ float duration, unsigned int offset, unsigned int length);
+ // after this, all durations are non-negative, and sum to 1.0
+ // or passed number
+ SplineSequence<T> &normalizeDurations(float total = 1.0f);
+
+ inline float getTotalDuration() { return m_totalDuration; };
+
+ void interpolate(T &result, float alpha) const;
+
+ T _interpolate(T &bottom, T &top, float alpha) const;
+};
+
+template <typename T> SplineSequence<T>::SplineSequence() : m_totalDuration(0.0f)
+{
+ // noop
+}
+
+template <typename T> SplineSequence<T>::~SplineSequence()
+{
+ // noop
+}
+
+template <typename T> inline std::vector<T> SplineSequence<T>::getNodes()
+{
+ return this->nodes;
+}
+
+template <typename T>
+inline std::vector<SplineIndex> SplineSequence<T>::getIndices()
+{
+ return this->indices;
+}
+
+template <typename T> SplineSequence<T> &SplineSequence<T>::addNode(T node)
+{
+ nodes.push_back(node);
+ return *this;
+}
+
+template <typename T>
+SplineSequence<T> &SplineSequence<T>::addIndex(
+ float duration, unsigned int offset, unsigned int length)
+{
+ // TODO: in-place constructor for structs?
+ // TODO: sanity checks for durations
+ SplineIndex index;
+ index.duration = duration;
+ index.offset = offset;
+ index.length = length;
+ indices.push_back(index);
+ m_totalDuration += duration;
+ return *this;
+}
+
+template <typename T>
+SplineSequence<T> &SplineSequence<T>::normalizeDurations(float target)
+{
+ float sum = 0.0;
+ for (std::vector<SplineIndex>::iterator i = indices.begin(); i != indices.end();
+ i++) {
+ float d = i->duration;
+ if (d < 0.0)
+ d = 0.0; // TODO: sanity check in addIndex
+ sum += d;
+ }
+
+ if (sum == 0.0) {
+ // TODO: throw exception or similar
+ }
+ float adjust = target / sum;
+
+ for (std::vector<SplineIndex>::iterator i = indices.begin(); i != indices.end();
+ i++) {
+ float d = i->duration;
+ if (d < 0.0)
+ d = 0.0;
+ d = d * adjust;
+ i->duration = d;
+ }
+ m_totalDuration = target;
+ return *this;
+}
+
+template <typename T> void SplineSequence<T>::interpolate(T &result, float alpha) const
+{
+
+ // find the index
+ std::vector<SplineIndex>::const_iterator index = indices.begin();
+ while (index != indices.end() && index->duration <= alpha) {
+ alpha -= index->duration;
+ index++;
+ }
+ if (index == indices.end()) {
+ // search unsuccessful?
+ return;
+ }
+ // std::cout << "Found index " << index->offset << ", " << index->length <<
+ // std::endl;
+ /*
+ 0.3 0.3 0.4 , 0.0 -> 1st, 0.0 rem -> 0.0
+ 0.3 0.3 0.4 , 0.5 -> 2nd, 0.2 rem -> 0.66
+ */
+ alpha = alpha / index->duration;
+ // std::cout << "Remaining alpha " << alpha << std::endl;
+
+ typename std::vector<T>::const_iterator start = nodes.begin();
+ start += index->offset;
+ typename std::vector<T>::const_iterator end = start;
+ end += index->length;
+ // std::cout << "Start: " << start->X << " " << start->Y << " " << start->Z <<
+ // std::endl; std::cout << "End: " << end->X << " " << end->Y << " " << end->Z <<
+ // std::endl; std::cout << "Ends: " << *start << " " << *end << std::endl;
+ // these are both inclusive, but vector's range constructor
+ // excludes the end -> advance by one
+ end++;
+
+ std::vector<T> workspace(start, end);
+ for (unsigned int degree = index->length; degree > 0; degree--) {
+ for (unsigned int i = 0; i < degree; i++) {
+ // std::cout << "Interpolating alpha " << alpha << ", degree " <<
+ // degree << ", step " << i << std::endl; std::cout << "Before " <<
+ // workspace[i] << " onto " << workspace[i+1] << std::endl;
+ workspace[i] = _interpolate(
+ workspace[i], workspace[i + 1], alpha);
+ //_interpolate(workspace[i], alpha, index->length);
+ // workspace[i] = (1.0-alpha) * workspace[i] + alpha *
+ // workspace[i+1]; std::cout << "After " << workspace[i] << " onto
+ // " << workspace[i+1] << std::endl;
+ }
+ }
+ result = workspace[0];
+
+ // SplineIndex index;
+ // for(
+ // std::vector<SplineIndex>::const_iterator i = indices.begin();
+ // i != indices.end(); i++
+ //) {
+ // if (i->duration >= alpha) {
+ // index = *i;
+ // alpha -= i->duration;
+ // }
+ //}
+ // if (index->duration <= 0.0) {
+ // return;
+ //}
+}
+
+template <typename T>
+T SplineSequence<T>::_interpolate(T &bottom, T &top, float alpha) const
+{
+ return (1.0 - alpha) * bottom + alpha * top;
+}
+
+// declare specializations
+
+// quaternions have a special interpolation
+template <>
+core::quaternion SplineSequence<core::quaternion>::_interpolate(
+ core::quaternion &bottom, core::quaternion &top, float alpha) const;
\ No newline at end of file
--- /dev/null
+/*
+Minetest WieldAnimation
+Copyright (C) 2018 Ben Deutsch <ben@bendeutsch.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 "wieldanimation.h"
+
+v3f WieldAnimation::getTranslationAt(float time) const
+{
+ v3f translation;
+ m_translationspline.interpolate(translation, time);
+ return translation;
+}
+
+core::quaternion WieldAnimation::getRotationAt(float time) const
+{
+ core::quaternion rotation;
+ m_rotationspline.interpolate(rotation, time);
+ return rotation;
+}
+
+float WieldAnimation::getDuration() const
+{
+ return m_duration;
+}
+
+void WieldAnimation::setDuration(float duration)
+{
+ m_duration = duration;
+ m_translationspline.normalizeDurations(duration);
+ m_rotationspline.normalizeDurations(duration);
+}
+
+core::quaternion WieldAnimation::quatFromAngles(float pitch, float yaw, float roll)
+{
+ // the order of angles is important:
+ core::quaternion res;
+ res *= core::quaternion(pitch * core::DEGTORAD, 0, 0);
+ res *= core::quaternion(0, yaw * core::DEGTORAD, 0);
+ res *= core::quaternion(0, 0, roll * core::DEGTORAD);
+ return res;
+}
+
+const WieldAnimation &WieldAnimation::getNamed(const std::string &name)
+{
+ if (repository.size() == 0)
+ fillRepository();
+
+ if (repository.find(name) == repository.end())
+ return repository["punch"];
+
+ return repository[name];
+}
+
+std::unordered_map<std::string, WieldAnimation> WieldAnimation::repository;
+
+void WieldAnimation::fillRepository()
+{
+ // default: "punch"
+ WieldAnimation &punch = repository["punch"];
+ punch.m_translationspline.addNode(v3f(0, 0, 0))
+ .addNode(v3f(-70, 50, 0))
+ .addNode(v3f(-70, -50, 0))
+ .addNode(v3f(0, 0, 0));
+ punch.m_translationspline.addIndex(1.0, 0, 3);
+
+ punch.m_rotationspline.addNode(quatFromAngles(0.0f, 0.0f, 0.0f))
+ .addNode(quatFromAngles(0.0f, 0.0f, 90.0f))
+ .addNode(quatFromAngles(0.0f, 0.0f, 0.0f));
+ punch.m_rotationspline.addIndex(1.0, 0, 2);
+ punch.setDuration(0.3f);
+
+ WieldAnimation &dig = repository["dig"];
+ dig.m_translationspline.addNode(v3f(0, 0, 0))
+ .addNode(v3f(-70, -50, 0))
+ .addNode(v3f(-70, 50, 0))
+ .addNode(v3f(0, 0, 0));
+ dig.m_translationspline.addIndex(1.0, 0, 3);
+
+ dig.m_rotationspline.addNode(quatFromAngles(0.0f, 0.0f, 0.0f))
+ .addNode(quatFromAngles(0.0f, 0.0f, 135.0f))
+ .addNode(quatFromAngles(0.0f, 0.0f, 135.0f))
+ .addNode(quatFromAngles(0.0f, 0.0f, 0.0f))
+ .addNode(quatFromAngles(0.0f, 0.0f, -80.0f))
+ .addNode(quatFromAngles(0.0f, 0.0f, 0.0f));
+ dig.m_rotationspline.addIndex(1.0, 0, 2).addIndex(1.0, 2, 3);
+ dig.setDuration(0.3f);
+
+ // eat (without chewing)
+ WieldAnimation &eat = repository["eat"];
+ eat.m_translationspline.addNode(v3f(0, 0, 0))
+ .addNode(v3f(-35, 20, 0))
+ .addNode(v3f(-55, 10, 0))
+ .addNode(v3f(-55, 10, 0))
+ .addNode(v3f(-55, 15, 0))
+ .addNode(v3f(-55, 10, 0))
+ .addNode(v3f(-55, 15, 0))
+ .addNode(v3f(-55, 10, 0))
+ .addNode(v3f(-30, 0, 0))
+ .addNode(v3f(0, 0, 0))
+ .addNode(v3f(0, 0, 0));
+ eat.m_translationspline.addIndex(1.0, 0, 3)
+ .addIndex(0.5, 3, 1)
+ .addIndex(0.5, 4, 1)
+ .addIndex(0.5, 5, 1)
+ .addIndex(0.5, 6, 1)
+ .addIndex(1.0, 7, 3);
+
+ eat.m_rotationspline.addNode(quatFromAngles(0.0f, 0.0f, 0.0f))
+ .addNode(quatFromAngles(-90.0f, 20.0f, -80.0f))
+ .addNode(quatFromAngles(0.0f, 0.0f, 0.0f));
+ eat.m_rotationspline.addIndex(1.0, 0, 1).addIndex(2.0, 1, 0).addIndex(1.0, 1, 1);
+ eat.setDuration(1.0f);
+
+ // "poke"
+ WieldAnimation &poke = repository["poke"];
+ poke.m_translationspline.addNode(v3f(0, 0, 0))
+ .addNode(v3f(0, -10, 0))
+ .addNode(v3f(-50, 20, 50))
+ .addNode(v3f(0, -10, 0))
+ .addNode(v3f(0, 0, 0));
+ poke.m_translationspline.addIndex(1.0, 0, 2).addIndex(1.0, 2, 2);
+
+ poke.m_rotationspline.addNode(quatFromAngles(0.0f, 0.0f, 0.0f))
+ .addNode(quatFromAngles(0.0f, 0.0f, 90.0f))
+ .addNode(quatFromAngles(0.0f, 0.0f, 90.0f))
+ .addNode(quatFromAngles(0.0f, 0.0f, 90.0f))
+ .addNode(quatFromAngles(0.0f, 0.0f, 0.0f));
+ poke.m_rotationspline.addIndex(1.0, 0, 2).addIndex(1.0, 2, 2);
+ poke.setDuration(0.5f);
+
+}
+
+void WieldAnimation::serialize(std::ostream &os, u16 protocol_version)
+{
+ os << serializeString(name);
+ writeF32(os, m_duration);
+ std::vector<v3f> nodes = m_translationspline.getNodes();
+ writeU16(os, nodes.size());
+ for (const auto &node : nodes) {
+ writeV3F32(os, node);
+ }
+ std::vector<SplineIndex> indices = m_translationspline.getIndices();
+ writeU16(os, indices.size());
+ for (const auto &index : indices) {
+ writeF32(os, index.duration);
+ writeU16(os, index.offset);
+ writeU16(os, index.length);
+ }
+ std::vector<core::quaternion> rnodes = m_rotationspline.getNodes();
+ writeU16(os, rnodes.size());
+ for (const auto &node : rnodes) {
+ v3f out = v3f(node.X, node.Y, node.Z);
+ writeV3F32(os, out);
+ }
+ std::vector<SplineIndex> rindices = m_rotationspline.getIndices();
+ writeU16(os, rindices.size());
+ for (const auto &index : rindices) {
+ writeF32(os, index.duration);
+ writeU16(os, index.offset);
+ writeU16(os, index.length);
+ }
+}
+
+WieldAnimation WieldAnimation::deSerialize(std::istream &is)
+{
+ std::string name = deSerializeString(is);
+ WieldAnimation &anim = repository[name];
+ anim.name = name;
+ m_duration = readF32(is);
+ u32 translationNodes_size = readU32(is);
+ for (u32 i = 0; i < translationNodes_size; i++) {
+ v3f node = readV3F32(is);
+ anim.m_translationspline.addNode(node);
+ }
+
+ u32 translationIndex_size = readU32(is);
+ for (u32 i = 0; i < translationIndex_size; i++) {
+ float duration = readF32(is);
+ u32 offset = readU16(is);
+ u32 length = readU16(is);
+ anim.m_translationspline.addIndex(duration, offset, length);
+ }
+
+ u32 rotationNodes_size = readU32(is);
+ for (u32 i = 0; i < rotationNodes_size; i++) {
+ v3f node = readV3F32(is);
+ anim.m_rotationspline.addNode(quatFromAngles(node.X,node.Y, node.Z));
+ }
+ u32 rotationIndex_size = readU32(is);
+ for (u32 i = 0; i < rotationIndex_size; i++) {
+ float duration = readF32(is);
+ u32 offset = readU16(is);
+ u32 length = readU16(is);
+ anim.m_rotationspline.addIndex(duration, offset, length);
+ }
+ anim.setDuration(m_duration);
+ return anim;
+}
--- /dev/null
+/*
+Minetest WieldAnimation
+Copyright (C) 2018 Ben Deutsch <ben@bendeutsch.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.
+*/
+
+#pragma once
+
+#include "irrlichttypes_extrabloated.h"
+#include <iostream>
+#include "util/serialize.h"
+#include "splinesequence.h"
+#include <unordered_map>
+
+class WieldAnimation
+{
+public:
+ std::string name;
+ v3f getTranslationAt(float time) const;
+ core::quaternion getRotationAt(float time) const;
+ float getDuration() const;
+ // call this *after* filling the splines
+ void setDuration(float duration);
+ static core::quaternion quatFromAngles(float pitch, float yaw, float roll);
+
+ static const WieldAnimation &getNamed(const std::string &name);
+
+ SplineSequence<v3f> m_translationspline;
+ SplineSequence<core::quaternion> m_rotationspline;
+ float m_duration;
+
+ static std::unordered_map<std::string, WieldAnimation> repository;
+ static void fillRepository();
+ WieldAnimation deSerialize(std::istream &is);
+ void serialize(std::ostream &os, u16 protocol_version);
+};
\ No newline at end of file