diff --git a/src/engine/animation/skeleton.cpp b/src/engine/animation/skeleton.cpp index 227c769..0841234 100644 --- a/src/engine/animation/skeleton.cpp +++ b/src/engine/animation/skeleton.cpp @@ -18,6 +18,7 @@ */ #include +#include skeleton::skeleton(std::size_t bone_count): m_bone_parents(bone_count, 0), @@ -33,10 +34,55 @@ void skeleton::update_rest_pose() m_rest_pose.update(); } -void skeleton::set_bone_count(std::size_t bone_count) +bone_index_type skeleton::add_bones(std::size_t bone_count) { - m_bone_parents.resize(bone_count, 0); + const bone_index_type first_bone_index = static_cast(m_bone_parents.size()); + + m_bone_parents.resize(m_bone_parents.size() + bone_count, 0); m_rest_pose.resize(); + + return first_bone_index; +} + +bone_index_type skeleton::add_bone(hash::fnv1a32_t name) +{ + const bone_index_type bone_index = add_bone(); + + set_bone_name(bone_index, name); + + return bone_index; +} + +void skeleton::remove_bones() +{ + m_bone_parents.clear(); + m_bone_map.clear(); + m_rest_pose.resize(); +} + +void skeleton::set_bone_parent(bone_index_type child_index, bone_index_type parent_index) +{ + if (child_index < parent_index) + { + throw std::invalid_argument("Child bone index precedes parent bone index"); + } + + m_bone_parents[child_index] = parent_index; +} + +void skeleton::set_bone_name(bone_index_type index, hash::fnv1a32_t name) +{ + if (auto i = m_bone_map.find(name); i != m_bone_map.end()) + { + if (i->second != index) + { + throw std::invalid_argument("Duplicate bone name"); + } + } + else + { + m_bone_map[name] = index; + } } std::optional skeleton::get_bone_index(hash::fnv1a32_t name) const diff --git a/src/engine/animation/skeleton.hpp b/src/engine/animation/skeleton.hpp index b99f00a..5c27434 100644 --- a/src/engine/animation/skeleton.hpp +++ b/src/engine/animation/skeleton.hpp @@ -49,11 +49,39 @@ public: void update_rest_pose(); /** - * Sets the number of bones in the skeleton. + * Add one or more bones to the skeleton. * - * @param size Number of bones in the skeleton. + * @param bone_count Number of bones to add. + * + * @return Index of the first added bone. + */ + bone_index_type add_bones(std::size_t bone_count); + + /** + * Adds a single bone to the skeleton. + * + * @return Index of the added bone. */ - void set_bone_count(std::size_t size); + inline bone_index_type add_bone() + { + return add_bones(1); + } + + /** + * Adds a single named bone to the skeleton. + * + * @param name Name of the bone. + * + * @return Index of the added bone. + * + * @throw std::invalid_argument Duplicate bone name. + */ + bone_index_type add_bone(hash::fnv1a32_t name); + + /** + * Removes all bones from the skeleton. + */ + void remove_bones(); /** * Sets the parent of a bone. @@ -61,12 +89,11 @@ public: * @param child_index Index of the child bone. * @param parent_index Index of the parent bone. * - * @warning The index of a child bone must be greater than the index of its parent. Failure to properly index bones will result in incorrect pose concatenation. + * @warning The index of a child bone must be greater than the index of its parent. + * + * @throw std::invalid_argument Child bone index precedes parent bone index. */ - inline void set_bone_parent(bone_index_type child_index, bone_index_type parent_index) - { - m_bone_parents[child_index] = parent_index; - } + void set_bone_parent(bone_index_type child_index, bone_index_type parent_index); /** * Sets the transform of a bone, relative to its parent bone. @@ -84,11 +111,10 @@ public: * * @param index Index of a bone. * @param name Name of the bone. + * + * @throw std::invalid_argument Duplicate bone name. */ - inline void set_bone_name(bone_index_type index, hash::fnv1a32_t name) - { - m_bone_map[name] = index; - } + void set_bone_name(bone_index_type index, hash::fnv1a32_t name); /** * Returns the number of bones in the skeleton. diff --git a/src/engine/render/model.cpp b/src/engine/render/model.cpp index 1fcf486..0c05f2e 100644 --- a/src/engine/render/model.cpp +++ b/src/engine/render/model.cpp @@ -289,7 +289,7 @@ std::unique_ptr resource_loader::load(::resource_m ctx.read16(reinterpret_cast(&bone_count), 1); // Resize skeleton - skeleton.set_bone_count(bone_count); + skeleton.add_bones(bone_count); // Read bones for (std::uint16_t i = 0; i < bone_count; ++i) diff --git a/src/game/ant/ant-morphogenesis.cpp b/src/game/ant/ant-morphogenesis.cpp index f977a40..4079393 100644 --- a/src/game/ant/ant-morphogenesis.cpp +++ b/src/game/ant/ant-morphogenesis.cpp @@ -277,7 +277,7 @@ void reskin_vertices void build_ant_skeleton(const ant_phenome& phenome, ::skeleton& skeleton, ant_bone_set& bones) { // Allocate bones - skeleton.set_bone_count(count_ant_skeleton_bones(phenome)); + skeleton.add_bones(count_ant_skeleton_bones(phenome)); // Construct ant bone set bone_index_type bone_index = 0;