From cb9f6838cd937d89af34fac920b4e86b29ad3f04 Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Thu, 23 Mar 2023 08:22:17 +0800 Subject: [PATCH] Revise skeleton and skeleton poses. Add rigged mesh scene object --- src/engine/animation/bone.hpp | 124 ---- src/engine/animation/pose.cpp | 55 -- src/engine/animation/pose.hpp | 59 -- src/engine/animation/skeleton-bind-pose.cpp | 57 ++ src/engine/animation/skeleton-bind-pose.hpp | 42 ++ src/engine/animation/skeleton-pose.cpp | 80 +++ src/engine/animation/skeleton-pose.hpp | 138 ++++ src/engine/animation/skeleton.cpp | 29 + src/engine/animation/skeleton.hpp | 120 +++- src/engine/geom/primitives/point.hpp | 43 ++ src/engine/gl/vertex-array.cpp | 33 +- src/engine/math/interpolation.hpp | 2 +- src/engine/math/math.hpp | 14 - src/engine/math/projection.hpp | 66 +- src/engine/render/model.cpp | 40 +- src/engine/render/operation.hpp | 3 +- src/engine/render/passes/material-pass.cpp | 7 + src/engine/render/passes/material-pass.hpp | 2 + src/engine/render/passes/shadow-map-pass.cpp | 6 +- src/engine/scene/rigged-mesh.cpp | 123 ++++ src/engine/scene/rigged-mesh.hpp | 109 +++ src/engine/scene/static-mesh.cpp | 3 - src/engine/scene/static-mesh.hpp | 20 +- src/game/ant/ant-morphogenesis.cpp | 674 ++++++++++--------- src/game/states/nest-selection-state.cpp | 25 +- 25 files changed, 1191 insertions(+), 683 deletions(-) delete mode 100644 src/engine/animation/bone.hpp delete mode 100644 src/engine/animation/pose.cpp delete mode 100644 src/engine/animation/pose.hpp create mode 100644 src/engine/animation/skeleton-bind-pose.cpp create mode 100644 src/engine/animation/skeleton-bind-pose.hpp create mode 100644 src/engine/animation/skeleton-pose.cpp create mode 100644 src/engine/animation/skeleton-pose.hpp create mode 100644 src/engine/geom/primitives/point.hpp create mode 100644 src/engine/scene/rigged-mesh.cpp create mode 100644 src/engine/scene/rigged-mesh.hpp diff --git a/src/engine/animation/bone.hpp b/src/engine/animation/bone.hpp deleted file mode 100644 index f3e696d..0000000 --- a/src/engine/animation/bone.hpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2023 Christopher J. Howard - * - * This file is part of Antkeeper source code. - * - * Antkeeper source code is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Antkeeper source code 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Antkeeper source code. If not, see . - */ - -#ifndef ANTKEEPER_ANIMATION_BONE_HPP -#define ANTKEEPER_ANIMATION_BONE_HPP - -#include - -/** - * Skeletal animation bone identifier, consisting of a bone index in the lower half, and a parent bone index in the upper half. - */ -using bone = std::uint32_t; - -/// Mask to extract the index of a bone. -inline constexpr bone bone_index_mask = 0xffff; - -/** - * Bone index comparison function object. - */ -struct bone_index_compare -{ - /** - * Compares the indices of two bones. - * - * @param lhs First bone. - * @param rhs Second bone. - * - * @return Comparison result. - */ - [[nodiscard]] inline bool operator()(const bone& lhs, const bone& rhs) const noexcept - { - return (lhs & bone_index_mask) < (rhs & bone_index_mask); - } -}; - -/** - * Constructs a bone identifier. - * - * @param index Index of the bone. - * @param parent_index Index of the parent bone. - * - * @return Bone identifier. - */ -[[nodiscard]] inline bone make_bone(std::uint16_t index, std::uint16_t parent_index) noexcept -{ - return (static_cast(parent_index) << 16) | index; -} - -/** - * Sets the parent of a bone. - * - * @param[out] child Bone to reparent. - * @param[in] parent New parent bone. - */ -inline void reparent_bone(bone& child, bone parent) noexcept -{ - child = ((parent & bone_index_mask) << 16) | (child & bone_index_mask); -} - -/** - * Constructs an orphan bone identifier. - * - * @param index Index of the orphan bone. - * - * @return Orphan bone identifier. - */ -[[nodiscard]] inline bone make_bone(std::uint16_t index) noexcept -{ - return make_bone(index, index); -} - -/** - * Returns the index of a bone. - * - * @param x Bone identifier. - * - * @return Index of the bone. - */ -[[nodiscard]] inline std::uint16_t bone_index(bone x) noexcept -{ - return static_cast(x & bone_index_mask); -} - -/** - * Returns the parent index of a bone. - * - * @param x Bone identifier. - * - * @return Index of the parent bone. - */ -[[nodiscard]] inline std::uint16_t bone_parent_index(bone x) noexcept -{ - return static_cast(x >> 16); -} - -/** - * Returns `true` if a bone has a parent, `false` otherwise. - * - * @param x Bone identifier. - * - * @return Bone parent status. - */ -[[nodiscard]] inline bool bone_has_parent(bone x) noexcept -{ - return (x & bone_index_mask) != (x >> 16); -} - -#endif // ANTKEEPER_ANIMATION_BONE_HPP diff --git a/src/engine/animation/pose.cpp b/src/engine/animation/pose.cpp deleted file mode 100644 index 2684d61..0000000 --- a/src/engine/animation/pose.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2023 Christopher J. Howard - * - * This file is part of Antkeeper source code. - * - * Antkeeper source code is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Antkeeper source code 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Antkeeper source code. If not, see . - */ - -#include - -void concatenate(const pose& bone_space, pose& skeleton_space) -{ - for (auto&& [bone, transform]: bone_space) - { - auto parent_index = bone_parent_index(bone); - - if (parent_index != bone_index(bone)) - { - auto parent = skeleton_space.find(parent_index); - skeleton_space[bone] = (parent != skeleton_space.end()) ? parent->second * transform : transform; - } - else - { - skeleton_space[bone] = transform; - } - } -} - -void inverse(const pose& x, pose& y) -{ - for (auto&& [bone, transform]: x) - { - y[bone] = math::inverse(transform); - } -} - -void matrix_palette(const pose& inverse_bind_pose, const pose& pose, float4x4* palette) -{ - for (auto&& [bone, transform]: pose) - { - auto index = ::bone_index(bone); - palette[index] = (inverse_bind_pose.at(bone) * transform).matrix(); - } -} diff --git a/src/engine/animation/pose.hpp b/src/engine/animation/pose.hpp deleted file mode 100644 index 671f4d6..0000000 --- a/src/engine/animation/pose.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2023 Christopher J. Howard - * - * This file is part of Antkeeper source code. - * - * Antkeeper source code is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Antkeeper source code 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Antkeeper source code. If not, see . - */ - -#ifndef ANTKEEPER_ANIMATION_POSE_HPP -#define ANTKEEPER_ANIMATION_POSE_HPP - -#include -#include -#include -#include - -/** - * Skeletal animation pose. - */ -typedef std::map, bone_index_compare> pose; - -/** - * Transforms a pose from bone-space into skeleton-space. - * - * @param[in] bone_space Bone-space pose. - * @param[out] skeleton_space Skeleton-space pose. - * - * @warning If the index of any child bone is greater than its parent index, the concatenated pose may be incorrect. - */ -void concatenate(const pose& bone_space, pose& skeleton_space); - -/** - * Inverses each transform in a pose. - * - * @param[in] x Input pose. - * @param[out] y Output pose. - */ -void inverse(const pose& x, pose& y); - -/** - * Generates a skinning matrix palette from a pose. - * - * @param inverse_bind_pose Inverse of the skeleton-space bind pose. - * @param pose Bone-space Skeleton-space pose. - */ -void matrix_palette(const pose& inverse_bind_pose, const pose& pose, float4x4* palette); - -#endif // ANTKEEPER_ANIMATION_POSE_HPP diff --git a/src/engine/animation/skeleton-bind-pose.cpp b/src/engine/animation/skeleton-bind-pose.cpp new file mode 100644 index 0000000..c42d82f --- /dev/null +++ b/src/engine/animation/skeleton-bind-pose.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2023 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#include +#include + +skeleton_bind_pose::skeleton_bind_pose(const skeleton& skeleton): + skeleton_pose(skeleton) +{} + +void skeleton_bind_pose::update() +{ + const std::size_t bone_count = m_relative_transforms.size(); + + for (std::size_t i = 0; i < bone_count; ++i) + { + const bone_index_type parent_index = m_skeleton->get_bone_parent(static_cast(i)); + + if (parent_index != i) + { + m_absolute_transforms[i] = m_absolute_transforms[parent_index] * m_relative_transforms[i]; + } + else + { + m_absolute_transforms[i] = m_relative_transforms[i]; + } + + m_matrix_palette[i] = math::inverse(m_absolute_transforms[i]).matrix(); + } +} + +void skeleton_bind_pose::reset_bone_transforms() +{ + const std::size_t bone_count = m_relative_transforms.size(); + for (std::size_t i = 0; i < bone_count; ++i) + { + m_relative_transforms[i] = bone_transform_type::identity(); + m_absolute_transforms[i] = bone_transform_type::identity(); + m_matrix_palette[i] = bone_matrix_type::identity(); + } +} diff --git a/src/engine/animation/skeleton-bind-pose.hpp b/src/engine/animation/skeleton-bind-pose.hpp new file mode 100644 index 0000000..8b72bd1 --- /dev/null +++ b/src/engine/animation/skeleton-bind-pose.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#ifndef ANTKEEPER_ANIMATION_SKELETON_BIND_POSE_HPP +#define ANTKEEPER_ANIMATION_SKELETON_BIND_POSE_HPP + +#include + +/** + * Skeleton bind pose. + */ +class skeleton_bind_pose: public skeleton_pose +{ +public: + /** + * Constructs a skeleton bind pose. + * + * @param skeleton Skeleton with which to associate the bind pose. + */ + skeleton_bind_pose(const skeleton& skeleton); + + void update() override; + void reset_bone_transforms() override; +}; + +#endif // ANTKEEPER_ANIMATION_SKELETON_BIND_POSE_HPP diff --git a/src/engine/animation/skeleton-pose.cpp b/src/engine/animation/skeleton-pose.cpp new file mode 100644 index 0000000..a972905 --- /dev/null +++ b/src/engine/animation/skeleton-pose.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2023 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#include +#include + +skeleton_pose::skeleton_pose(const skeleton& skeleton): + m_skeleton(&skeleton), + m_relative_transforms(skeleton.get_bone_count()), + m_absolute_transforms(skeleton.get_bone_count()), + m_matrix_palette(skeleton.get_bone_count()) +{} + +void skeleton_pose::update() +{ + const auto& bind_pose_inverse_absolute_transforms = m_skeleton->get_bind_pose().get_matrix_palette(); + + const std::size_t bone_count = m_relative_transforms.size(); + for (std::size_t i = 0; i < bone_count; ++i) + { + const bone_index_type parent_index = m_skeleton->get_bone_parent(static_cast(i)); + + if (parent_index != i) + { + m_absolute_transforms[i] = m_absolute_transforms[parent_index] * m_relative_transforms[i]; + } + else + { + m_absolute_transforms[i] = m_relative_transforms[i]; + } + + m_matrix_palette[i] = m_absolute_transforms[i].matrix() * bind_pose_inverse_absolute_transforms[i]; + } +} + +void skeleton_pose::reset_bone_transforms() +{ + if (m_skeleton) + { + const auto& bind_pose = m_skeleton->get_bind_pose(); + const auto& bind_pose_inverse_absolute_transforms = bind_pose.get_matrix_palette(); + + const std::size_t bone_count = m_relative_transforms.size(); + for (std::size_t i = 0; i < bone_count; ++i) + { + m_relative_transforms[i] = bind_pose.get_relative_transform(static_cast(i)); + m_absolute_transforms[i] = bind_pose.get_absolute_transform(static_cast(i)); + m_matrix_palette[i] = bind_pose_inverse_absolute_transforms[i] * m_absolute_transforms[i].matrix(); + } + } +} + +void skeleton_pose::set_skeleton(const skeleton* skeleton) +{ + m_skeleton = skeleton; + + const std::size_t bone_count = (m_skeleton) ? m_skeleton->get_bone_count() : 0; + + m_relative_transforms.resize(bone_count); + m_absolute_transforms.resize(bone_count); + m_matrix_palette.resize(bone_count); + + reset_bone_transforms(); +} diff --git a/src/engine/animation/skeleton-pose.hpp b/src/engine/animation/skeleton-pose.hpp new file mode 100644 index 0000000..bf98c00 --- /dev/null +++ b/src/engine/animation/skeleton-pose.hpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2023 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#ifndef ANTKEEPER_ANIMATION_SKELETON_POSE_HPP +#define ANTKEEPER_ANIMATION_SKELETON_POSE_HPP + +#include +#include +#include +#include + +class skeleton; + +/** + * Skeleton pose. + */ +class skeleton_pose +{ +public: + /// Bone index type. + using bone_index_type = std::uint16_t; + + /// Bone transform type. + using bone_transform_type = math::transform; + + /// Matrix type. + using bone_matrix_type = math::matrix; + + /** + * Constructs a skeleton pose. + * + * @param skeleton Skeleton with which to associate the pose. + */ + explicit skeleton_pose(const skeleton& skeleton); + + /// Constructs an empty skeleton pose. + skeleton_pose() noexcept = default; + + /** + * Updates the absolute transforms and matrix palette of the pose. + */ + virtual void update(); + + /** + * Resets all bone transforms to identity transforms. + */ + virtual void reset_bone_transforms(); + + /** + * Sets the number of bones in the pose. + * + * @param skeleton Skeleton with which to associate the pose. + */ + void set_skeleton(const skeleton* skeleton); + + /** + * Sets the relative transform describing a bone pose. + * + * @param index Index of a bone. + * @param transform Relative transform describing the bone pose. + */ + inline void set_relative_transform(bone_index_type index, const bone_transform_type& transform) + { + m_relative_transforms[index] = transform; + } + + /// Returns the skeleton with which the pose is associated. + [[nodiscard]] inline const skeleton* get_skeleton() const noexcept + { + return m_skeleton; + } + + /** + * Returns the relative transform describing a bone pose. + * + * @param index Index of a bone. + * + * @return Relative transform describing the bone pose. + */ + [[nodiscard]] inline const bone_transform_type& get_relative_transform(bone_index_type index) const + { + return m_relative_transforms[index]; + } + + /** + * Returns the absolute transform describing a bone pose. + * + * @param index Index of a bone. + * + * @return Absolute transform describing the bone pose. + */ + [[nodiscard]] inline const bone_transform_type& get_absolute_transform(bone_index_type index) const + { + return m_absolute_transforms[index]; + } + + /** + * Returns the matrix palette of the pose. + * + * @note The matrix palette of a standard skeleton pose will contain its skinning matrices. + * @note The matrix palette of a skeleton bind pose will contain the inverses of its absolute transforms. + */ + [[nodiscard]] inline const std::vector& get_matrix_palette() const noexcept + { + return m_matrix_palette; + } + +protected: + /// Skeleton with which the pose is associated. + const skeleton* m_skeleton{nullptr}; + + /// Relative ransforms for each bone in a skeleton. + std::vector m_relative_transforms; + + /// Absolute transforms for each bone in a skeleton. + std::vector m_absolute_transforms; + + /// Skinning matrix palette. + std::vector m_matrix_palette; +}; + +#endif // ANTKEEPER_ANIMATION_SKELETON_POSE_HPP diff --git a/src/engine/animation/skeleton.cpp b/src/engine/animation/skeleton.cpp index 543cbfe..c24abcd 100644 --- a/src/engine/animation/skeleton.cpp +++ b/src/engine/animation/skeleton.cpp @@ -19,3 +19,32 @@ #include +skeleton::skeleton(std::size_t bone_count): + m_bone_parents(bone_count, 0), + m_bind_pose(*this) +{} + +skeleton::skeleton(): + skeleton(0) +{} + +void skeleton::update_bind_pose() +{ + m_bind_pose.update(); +} + +void skeleton::set_bone_count(std::size_t bone_count) +{ + m_bone_parents.resize(bone_count, 0); + m_bind_pose.set_skeleton(this); +} + +std::optional skeleton::get_bone_index(hash::fnv1a32_t name) const +{ + if (auto i = m_bone_map.find(name); i != m_bone_map.end()) + { + return i->second; + } + + return std::nullopt; +} diff --git a/src/engine/animation/skeleton.hpp b/src/engine/animation/skeleton.hpp index da2e371..861385c 100644 --- a/src/engine/animation/skeleton.hpp +++ b/src/engine/animation/skeleton.hpp @@ -20,28 +20,126 @@ #ifndef ANTKEEPER_ANIMATION_SKELETON_HPP #define ANTKEEPER_ANIMATION_SKELETON_HPP -#include -#include +#include #include -#include #include #include +#include +#include /** * Skeletal animation skeleton. */ -struct skeleton +class skeleton { - /// Bone-space bind pose of the skeleton. - pose bind_pose; +public: + /// Bone index type. + using bone_index_type = std::uint16_t; - /// Inverse skeleton-space bind pose of the skeleton. - pose inverse_bind_pose; + /// Bone transform type. + using bone_transform_type = skeleton_pose::bone_transform_type; - std::vector bones; + /** + * Constructs a skeleton. + * + * @param bone_count Number of bones in the skeleton. + */ + explicit skeleton(std::size_t bone_count); - /// Maps bone names to bone identifiers. - std::unordered_map bone_map; + /// Constructs an empty skeleton. + skeleton(); + + /** + * Updates the bind pose of the skeleton. + */ + void update_bind_pose(); + + /** + * Sets the number of bones in the skeleton. + * + * @param size Number of bones in the skeleton. + */ + void set_bone_count(std::size_t size); + + /** + * Sets the parent of a bone. + * + * @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. + */ + inline void set_bone_parent(bone_index_type child_index, bone_index_type parent_index) + { + m_bone_parents[child_index] = parent_index; + } + + /** + * Sets the transform of a bone, relative to its parent bone. + * + * @param index Index of a bone. + * @param transform Bone transform, relative to the parent bone. + */ + inline void set_bone_transform(bone_index_type index, const bone_transform_type& transform) + { + m_bind_pose.set_relative_transform(index, transform); + } + + /** + * Sets the name of a bone. + * + * @param index Index of a bone. + * @param name Name of the bone. + */ + inline void set_bone_name(bone_index_type index, hash::fnv1a32_t name) + { + m_bone_map[name] = index; + } + + /** + * Returns the number of bones in the skeleton. + */ + [[nodiscard]] inline std::size_t get_bone_count() const noexcept + { + return m_bone_parents.size(); + } + + /** + * Returns the index of the parent of a bone. + * + * @param child_index Index of the child bone. + * + * @return Index of the child bone's parent, or @p index if the child bone has no parent. + */ + [[nodiscard]] inline bone_index_type get_bone_parent(bone_index_type child_index) const + { + return m_bone_parents[child_index]; + } + + /** + * Finds the index of a bone from the bone's name. + * + * @param name Name of a bone. + * + * @return Index of the bone, or `std::nullopt` if no bone with the given name was found. + */ + [[nodiscard]] std::optional get_bone_index(hash::fnv1a32_t name) const; + + /// Returns the skeleton's bind pose. + [[nodiscard]] inline const skeleton_bind_pose& get_bind_pose() const noexcept + { + return m_bind_pose; + } + +private: + /// Indices of bone parents. + std::vector m_bone_parents; + + /// Bind pose of the skeleton. + skeleton_bind_pose m_bind_pose; + + /// Map of bone names to bone indices. + std::unordered_map m_bone_map; }; #endif // ANTKEEPER_ANIMATION_SKELETON_HPP diff --git a/src/engine/geom/primitives/point.hpp b/src/engine/geom/primitives/point.hpp new file mode 100644 index 0000000..978731c --- /dev/null +++ b/src/engine/geom/primitives/point.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2023 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#ifndef ANTKEEPER_GEOM_PRIMITIVES_POINT_HPP +#define ANTKEEPER_GEOM_PRIMITIVES_POINT_HPP + +#include + +namespace geom { +namespace primitives { + +/** + * *n*-dimensional point. + * + * @tparam T Real type. + * @tparam N Number of dimensions. + */ +template +using point = vector; + +} // namespace primitives + +using namespace primitives; + +} // namespace geom + +#endif // ANTKEEPER_GEOM_PRIMITIVES_POINT_HPP diff --git a/src/engine/gl/vertex-array.cpp b/src/engine/gl/vertex-array.cpp index 079d49d..f5ffa34 100644 --- a/src/engine/gl/vertex-array.cpp +++ b/src/engine/gl/vertex-array.cpp @@ -65,15 +65,30 @@ void vertex_array::bind(attribute_location_type location, const vertex_attribute GLenum gl_type = vertex_attribute_type_lut[static_cast(attribute.type)]; glBindVertexArray(gl_array_id); glBindBuffer(GL_ARRAY_BUFFER, attribute.buffer->gl_buffer_id); - glVertexAttribPointer - ( - static_cast(location), - static_cast(attribute.components), - gl_type, - GL_FALSE, - static_cast(attribute.stride), - reinterpret_cast(attribute.offset) - ); + + if (gl_type == GL_FLOAT || gl_type == GL_HALF_FLOAT || gl_type == GL_DOUBLE) + { + glVertexAttribPointer + ( + static_cast(location), + static_cast(attribute.components), + gl_type, + GL_FALSE, + static_cast(attribute.stride), + reinterpret_cast(attribute.offset) + ); + } + else + { + glVertexAttribIPointer + ( + static_cast(location), + static_cast(attribute.components), + gl_type, + static_cast(attribute.stride), + reinterpret_cast(attribute.offset) + ); + } glEnableVertexAttribArray(static_cast(location)); } diff --git a/src/engine/math/interpolation.hpp b/src/engine/math/interpolation.hpp index 4333187..88f2ca0 100644 --- a/src/engine/math/interpolation.hpp +++ b/src/engine/math/interpolation.hpp @@ -38,7 +38,7 @@ namespace math { * @tparam S Scalar type. */ template -[[nodiscard]] constexpr T lerp(const T& x, const T& y, S a) +[[nodiscard]] constexpr T lerp(const T& x, const T& y, S a) noexcept { return x + (y - x) * a; } diff --git a/src/engine/math/math.hpp b/src/engine/math/math.hpp index d69579e..7ecb1d0 100644 --- a/src/engine/math/math.hpp +++ b/src/engine/math/math.hpp @@ -23,18 +23,4 @@ /// Mathematical functions and data types. namespace math {} -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - #endif // ANTKEEPER_MATH_HPP diff --git a/src/engine/math/projection.hpp b/src/engine/math/projection.hpp index 531c1fc..3ee3051 100644 --- a/src/engine/math/projection.hpp +++ b/src/engine/math/projection.hpp @@ -58,7 +58,7 @@ template } /** - * Creates an orthographic projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively. + * Constructs an orthographic projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively. * * @param left Signed distance to the left clipping plane. * @param right Signed distance to the right clipping plane. @@ -73,16 +73,16 @@ template [[nodiscard]] constexpr matrix ortho(T left, T right, T bottom, T top, T z_near, T z_far) noexcept { return - {{ - {T(2) / (right - left), T(0), T(0), T(0)}, - {T(0), T(2) / (top - bottom), T(0), T(0)}, - {T(0), T(0), T(-2) / (z_far - z_near), T(0)}, - {-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((z_far + z_near) / (z_far - z_near)), T(1)} - }}; + {{ + {T{2} / (right - left), T{0}, T{0}, T{0}}, + {T{0}, T{2} / (top - bottom), T{0}, T{0}}, + {T{0}, T{0}, T{-2} / (z_far - z_near), T{0}}, + {-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((z_far + z_near) / (z_far - z_near)), T{1}} + }}; } /** - * Creates an orthographic projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively. + * Constructs an orthographic projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively. * * @param left Signed distance to the left clipping plane. * @param right Signed distance to the right clipping plane. @@ -97,16 +97,16 @@ template [[nodiscard]] constexpr matrix ortho_half_z(T left, T right, T bottom, T top, T z_near, T z_far) noexcept { return - {{ - {T(2) / (right - left), T(0), T(0), T(0)}, - {T(0), T(2) / (top - bottom), T(0), T(0)}, - {T(0), T(0), T(-1) / (z_far - z_near), T(0)}, - {-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -z_near / (z_far - z_near), T(1)} - }}; + {{ + {T{2} / (right - left), T{0}, T{0}, T{0}}, + {T{0}, T{2} / (top - bottom), T{0}, T{0}}, + {T{0}, T{0}, T{-1} / (z_far - z_near), T{0}}, + {-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -z_near / (z_far - z_near), T{1}} + }}; } /** - * Creates a perspective projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively. + * Constructs a perspective projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively. * * @param vertical_fov Vertical field of view angle, in radians. * @param aspect_ratio Aspect ratio which determines the horizontal field of view. @@ -118,20 +118,20 @@ template template [[nodiscard]] matrix perspective(T vertical_fov, T aspect_ratio, T z_near, T z_far) { - T half_fov = vertical_fov * T(0.5); - T f = std::cos(half_fov) / std::sin(half_fov); - + const T half_fov = vertical_fov * T{0.5}; + const T f = std::cos(half_fov) / std::sin(half_fov); + return - {{ - {f / aspect_ratio, T(0), T(0), T(0)}, - {T(0), f, T(0), T(0)}, - {T(0), T(0), (z_far + z_near) / (z_near - z_far), T(-1)}, - {T(0), T(0), (T(2) * z_far * z_near) / (z_near - z_far), T(0)} - }}; + {{ + {f / aspect_ratio, T{0}, T{0}, T{0}}, + {T{0}, f, T{0}, T{0}}, + {T{0}, T{0}, (z_far + z_near) / (z_near - z_far), T{-1}}, + {T{0}, T{0}, (T{2} * z_far * z_near) / (z_near - z_far), T{0}} + }}; } /** - * Creates a perspective projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively. + * Constructs a perspective projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively. * * @param vertical_fov Vertical field of view angle, in radians. * @param aspect_ratio Aspect ratio which determines the horizontal field of view. @@ -143,16 +143,16 @@ template template [[nodiscard]] matrix perspective_half_z(T vertical_fov, T aspect_ratio, T z_near, T z_far) { - T half_fov = vertical_fov * T(0.5); - T f = std::cos(half_fov) / std::sin(half_fov); + const T half_fov = vertical_fov * T{0.5}; + const T f = std::cos(half_fov) / std::sin(half_fov); return - {{ - {f / aspect_ratio, T(0), T(0), T(0)}, - {T(0), f, T(0), T(0)}, - {T(0), T(0), z_far / (z_near - z_far), T(-1)}, - {T(0), T(0), -(z_far * z_near) / (z_far - z_near), T(0)} - }}; + {{ + {f / aspect_ratio, T{0}, T{0}, T{0}}, + {T{0}, f, T{0}, T{0}}, + {T{0}, T{0}, z_far / (z_near - z_far), T{-1}}, + {T{0}, T{0}, -(z_far * z_near) / (z_far - z_near), T{0}} + }}; } } // namespace math diff --git a/src/engine/render/model.cpp b/src/engine/render/model.cpp index 61978c5..01741d7 100644 --- a/src/engine/render/model.cpp +++ b/src/engine/render/model.cpp @@ -213,7 +213,7 @@ std::unique_ptr resource_loader::load(::resource_m } if (vertex_format_flags & vertex_attribute_bone) { - attribute.type = gl::vertex_attribute_type::uint_16; + attribute.type = gl::vertex_attribute_type::uint_32; attribute.components = bones_per_vertex; vao.bind(render::vertex_attribute::bone_index, attribute); attribute.offset += sizeof(std::uint32_t) * attribute.components; @@ -235,7 +235,7 @@ std::unique_ptr resource_loader::load(::resource_m attribute.type = gl::vertex_attribute_type::float_32; attribute.components = 3; vao.bind(render::vertex_attribute::target, attribute); - attribute.offset += sizeof(float) * attribute.components; + //attribute.offset += sizeof(float) * attribute.components; } // Read model bounds @@ -283,31 +283,27 @@ std::unique_ptr resource_loader::load(::resource_m if (vertex_format_flags & vertex_attribute_bone) { ::skeleton& skeleton = model->get_skeleton(); - pose& bind_pose = skeleton.bind_pose; // Read bone count std::uint16_t bone_count = 0; ctx.read16(reinterpret_cast(&bone_count), 1); + // Resize skeleton + skeleton.set_bone_count(bone_count); + // Read bones for (std::uint16_t i = 0; i < bone_count; ++i) { - // Read bone key - hash::fnv1a32_t bone_key = {}; - ctx.read32(reinterpret_cast(&bone_key), 1); - - // Read parent bone index - std::uint16_t parent_bone_index = i; - ctx.read16(reinterpret_cast(&parent_bone_index), 1); + // Read bone name + hash::fnv1a32_t bone_name = {}; + ctx.read32(reinterpret_cast(&bone_name), 1); - // Construct bone identifier - ::bone bone = make_bone(i, parent_bone_index); + // Read bone parent index + std::uint16_t bone_parent_index = i; + ctx.read16(reinterpret_cast(&bone_parent_index), 1); - // Add bone to bone map - skeleton.bone_map[bone_key] = bone; - - // Get reference to the bone's bind pose transform - auto& bone_transform = bind_pose[bone]; + // Construct bone transform + skeleton::bone_transform_type bone_transform; // Read bone translation ctx.read32(reinterpret_cast(bone_transform.translation.data()), 3); @@ -322,11 +318,15 @@ std::unique_ptr resource_loader::load(::resource_m // Read bone length float bone_length = 0.0f; ctx.read32(reinterpret_cast(&bone_length), 1); + + // Set bone properties + skeleton.set_bone_name(i, bone_name); + skeleton.set_bone_parent(i, bone_parent_index); + skeleton.set_bone_transform(i, bone_transform); } - // Calculate inverse skeleton-space bind pose - ::concatenate(skeleton.bind_pose, skeleton.inverse_bind_pose); - ::inverse(skeleton.inverse_bind_pose, skeleton.inverse_bind_pose); + // Update skeleton + skeleton.update_bind_pose(); } return model; diff --git a/src/engine/render/operation.hpp b/src/engine/render/operation.hpp index fcd0575..99f7ee7 100644 --- a/src/engine/render/operation.hpp +++ b/src/engine/render/operation.hpp @@ -21,7 +21,6 @@ #define ANTKEEPER_RENDER_OPERATION_HPP #include -#include #include #include #include @@ -46,7 +45,7 @@ struct operation float depth{0.0f}; std::size_t instance_count{0}; - std::span skinning_palette{}; + std::span matrix_palette{}; }; } // namespace render diff --git a/src/engine/render/passes/material-pass.cpp b/src/engine/render/passes/material-pass.cpp index 9eba3a9..ed41852 100644 --- a/src/engine/render/passes/material-pass.cpp +++ b/src/engine/render/passes/material-pass.cpp @@ -267,6 +267,7 @@ void material_pass::render(render::context& ctx) // Update geometry-dependent shader variables model = &operation->transform; + matrix_palette = operation->matrix_palette; for (const auto& command: active_cache_entry->geometry_command_buffer) { command(); @@ -722,6 +723,12 @@ void material_pass::build_geometry_command_buffer(std::vectorupdate((*view_projection) * (*model));}); } + + // Update matrix palette variable + if (auto matrix_palette_var = shader_program.variable("matrix_palette")) + { + command_buffer.emplace_back([&, matrix_palette_var](){matrix_palette_var->update(matrix_palette);}); + } } void material_pass::build_material_command_buffer(std::vector>& command_buffer, const gl::shader_program& shader_program, const material& material) const diff --git a/src/engine/render/passes/material-pass.hpp b/src/engine/render/passes/material-pass.hpp index 41eee8d..f3f5126 100644 --- a/src/engine/render/passes/material-pass.hpp +++ b/src/engine/render/passes/material-pass.hpp @@ -28,6 +28,7 @@ #include #include #include +#include class resource_manager; @@ -131,6 +132,7 @@ private: // Geometry const float4x4* model; + std::span matrix_palette; /// Hash of the lighting state. std::size_t lighting_state_hash; diff --git a/src/engine/render/passes/shadow-map-pass.cpp b/src/engine/render/passes/shadow-map-pass.cpp index 70074d9..0caf9e7 100644 --- a/src/engine/render/passes/shadow-map-pass.cpp +++ b/src/engine/render/passes/shadow-map-pass.cpp @@ -288,7 +288,7 @@ void shadow_map_pass::render_csm(const scene::directional_light& light, render:: } // Switch shader programs if necessary - gl::shader_program* shader_program = (operation->skinning_palette.empty()) ? unskinned_shader_program.get() : skinned_shader_program.get(); + gl::shader_program* shader_program = (operation->matrix_palette.empty()) ? unskinned_shader_program.get() : skinned_shader_program.get(); if (active_shader_program != shader_program) { active_shader_program = shader_program; @@ -316,8 +316,8 @@ void shadow_map_pass::render_csm(const scene::directional_light& light, render:: bool operation_compare(const render::operation* a, const render::operation* b) { - const bool skinned_a = !a->skinning_palette.empty(); - const bool skinned_b = !b->skinning_palette.empty(); + const bool skinned_a = !a->matrix_palette.empty(); + const bool skinned_b = !b->matrix_palette.empty(); const bool two_sided_a = (a->material) ? a->material->is_two_sided() : false; const bool two_sided_b = (b->material) ? b->material->is_two_sided() : false; diff --git a/src/engine/scene/rigged-mesh.cpp b/src/engine/scene/rigged-mesh.cpp new file mode 100644 index 0000000..e401748 --- /dev/null +++ b/src/engine/scene/rigged-mesh.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2023 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#include +#include + +namespace scene { + +rigged_mesh::rigged_mesh(std::shared_ptr model) +{ + set_model(model); +} + +void rigged_mesh::set_model(std::shared_ptr model) +{ + m_model = model; + + if (m_model) + { + m_pose.set_skeleton(&model->get_skeleton()); + + m_operations.resize(m_model->get_groups().size()); + for (std::size_t i = 0; i < m_operations.size(); ++i) + { + const auto& group = m_model->get_groups()[i]; + + auto& operation = m_operations[i]; + operation.vertex_array = m_model->get_vertex_array().get(); + operation.drawing_mode = group.drawing_mode; + operation.start_index = group.start_index; + operation.index_count = group.index_count; + operation.material = group.material; + operation.matrix_palette = m_pose.get_matrix_palette(); + } + + } + else + { + m_operations.clear(); + } + + transformed(); +} + +void rigged_mesh::set_material(std::size_t index, std::shared_ptr material) +{ + if (material) + { + m_operations[index].material = material; + } + else + { + m_operations[index].material = m_model->get_groups()[index].material; + } +} + +void rigged_mesh::reset_materials() +{ + for (std::size_t i = 0; i < m_operations.size(); ++i) + { + m_operations[i].material = m_model->get_groups()[i].material; + } +} + +void rigged_mesh::update_bounds() +{ + if (m_model) + { + // Get model bounds + const auto& model_bounds = m_model->get_bounds(); + + // Naive algorithm: transform each corner of the model AABB + m_bounds.min = {std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()}; + m_bounds.max = {-std::numeric_limits::infinity(), -std::numeric_limits::infinity(), -std::numeric_limits::infinity()}; + for (std::size_t i = 0; i < 8; ++i) + { + m_bounds.extend(get_transform() * model_bounds.corner(i)); + } + } + else + { + m_bounds = {get_translation(), get_translation()}; + } +} + +void rigged_mesh::transformed() +{ + update_bounds(); + + const float4x4 transform_matrix = get_transform().matrix(); + for (auto& operation: m_operations) + { + operation.transform = transform_matrix; + } +} + +void rigged_mesh::render(render::context& ctx) const +{ + const float depth = ctx.camera->get_view_frustum().near().distance(get_translation()); + for (auto& operation: m_operations) + { + operation.depth = depth; + ctx.operations.push_back(&operation); + } +} + +} // namespace scene diff --git a/src/engine/scene/rigged-mesh.hpp b/src/engine/scene/rigged-mesh.hpp new file mode 100644 index 0000000..fdd0146 --- /dev/null +++ b/src/engine/scene/rigged-mesh.hpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2023 Christopher J. Howard + * + * This file is part of Antkeeper source code. + * + * Antkeeper source code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper source code 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper source code. If not, see . + */ + +#ifndef ANTKEEPER_SCENE_RIGGED_MESH_HPP +#define ANTKEEPER_SCENE_RIGGED_MESH_HPP + +#include +#include +#include +#include +#include + +namespace scene { + +/** + * + */ +class rigged_mesh: public object +{ +public: + /** + * Constructs a rigged mesh from a model. + * + * @param model Model from which the rigged mesh will be constructed. + */ + explicit rigged_mesh(std::shared_ptr model); + + /** + * Constructs a model instance. + */ + rigged_mesh() = default; + + /** + * Sets the model with which this model instance is associated. + * + * @warning This will reset all overwritten materials. + */ + void set_model(std::shared_ptr model); + + /** + * Overwrites the material of a model group for this model instance. + * + * @param index Index of a model group. + * @param material Pointer to the material which should overwrite the model group's material. A value of `nullptr` indicates the material will not be overwritten. + */ + void set_material(std::size_t index, std::shared_ptr material); + + /** + * Resets all overwritten materials. + */ + void reset_materials(); + + [[nodiscard]] inline const aabb_type& get_bounds() const noexcept override + { + return m_bounds; + } + + /** + * Returns the model of the model instance. + */ + [[nodiscard]] inline const std::shared_ptr& get_model() const noexcept + { + return m_model; + } + + void render(render::context& ctx) const override; + + /// Returns the pose of the rigged mesh. + /// @{ + [[nodiscard]] inline const skeleton_pose& get_pose() const noexcept + { + return m_pose; + } + + [[nodiscard]] inline skeleton_pose& get_pose() noexcept + { + return m_pose; + } + /// @} + +private: + void update_bounds(); + void transformed() override; + + std::shared_ptr m_model; + mutable std::vector m_operations; + aabb_type m_bounds{{0, 0, 0}, {0, 0, 0}}; + skeleton_pose m_pose; +}; + +} // namespace scene + +#endif // ANTKEEPER_SCENE_RIGGED_MESH_HPP diff --git a/src/engine/scene/static-mesh.cpp b/src/engine/scene/static-mesh.cpp index 9918d2a..1a176ec 100644 --- a/src/engine/scene/static-mesh.cpp +++ b/src/engine/scene/static-mesh.cpp @@ -47,13 +47,10 @@ void static_mesh::set_model(std::shared_ptr model) operation.index_count = group.index_count; operation.material = group.material; } - - ::concatenate(m_model->get_skeleton().bind_pose, m_pose); } else { m_operations.clear(); - m_pose.clear(); } transformed(); diff --git a/src/engine/scene/static-mesh.hpp b/src/engine/scene/static-mesh.hpp index c26c78d..6e9c17e 100644 --- a/src/engine/scene/static-mesh.hpp +++ b/src/engine/scene/static-mesh.hpp @@ -21,7 +21,6 @@ #define ANTKEEPER_SCENE_STATIC_MESH_HPP #include -#include #include #include #include @@ -47,7 +46,9 @@ public: static_mesh() = default; /** - * Sets the model with which this model instance is associated. This will reset the pose and all overwritten materials. + * Sets the model with which this model instance is associated. + * + * @warning This will reset all overwritten materials. */ void set_model(std::shared_ptr model); @@ -77,20 +78,6 @@ public: return m_model; } - /** - * Returns the skeletal animation pose of this model instance. - */ - /// @{ - [[nodiscard]] inline const pose& get_pose() const noexcept - { - return m_pose; - } - [[nodiscard]] inline pose& get_pose() noexcept - { - return m_pose; - } - /// @} - void render(render::context& ctx) const override; private: @@ -99,7 +86,6 @@ private: std::shared_ptr m_model; mutable std::vector m_operations; - ::pose m_pose; aabb_type m_bounds{{0, 0, 0}, {0, 0, 0}}; }; diff --git a/src/game/ant/ant-morphogenesis.cpp b/src/game/ant/ant-morphogenesis.cpp index 04116de..c4c4a89 100644 --- a/src/game/ant/ant-morphogenesis.cpp +++ b/src/game/ant/ant-morphogenesis.cpp @@ -24,52 +24,55 @@ #include #include #include +#include + +using bone_index_type = skeleton::bone_index_type; namespace { /// Set of pointers to all possible ant skeleton bones. struct ant_bone_set { - ::bone* mesosoma{nullptr}; - ::bone* procoxa_l{nullptr}; - ::bone* profemur_l{nullptr}; - ::bone* protibia_l{nullptr}; - ::bone* protarsus_l{nullptr}; - ::bone* procoxa_r{nullptr}; - ::bone* profemur_r{nullptr}; - ::bone* protibia_r{nullptr}; - ::bone* protarsus_r{nullptr}; - ::bone* mesocoxa_l{nullptr}; - ::bone* mesofemur_l{nullptr}; - ::bone* mesotibia_l{nullptr}; - ::bone* mesotarsus_l{nullptr}; - ::bone* mesocoxa_r{nullptr}; - ::bone* mesofemur_r{nullptr}; - ::bone* mesotibia_r{nullptr}; - ::bone* mesotarsus_r{nullptr}; - ::bone* metacoxa_l{nullptr}; - ::bone* metafemur_l{nullptr}; - ::bone* metatibia_l{nullptr}; - ::bone* metatarsus_l{nullptr}; - ::bone* metacoxa_r{nullptr}; - ::bone* metafemur_r{nullptr}; - ::bone* metatibia_r{nullptr}; - ::bone* metatarsus_r{nullptr}; - ::bone* head{nullptr}; - ::bone* mandible_l{nullptr}; - ::bone* mandible_r{nullptr}; - ::bone* antennomere1_l{nullptr}; - ::bone* antennomere2_l{nullptr}; - ::bone* antennomere1_r{nullptr}; - ::bone* antennomere2_r{nullptr}; - ::bone* petiole{nullptr}; - ::bone* postpetiole{nullptr}; - ::bone* gaster{nullptr}; - ::bone* sting{nullptr}; - ::bone* forewing_l{nullptr}; - ::bone* forewing_r{nullptr}; - ::bone* hindwing_l{nullptr}; - ::bone* hindwing_r{nullptr}; + std::optional mesosoma; + std::optional procoxa_l; + std::optional profemur_l; + std::optional protibia_l; + std::optional protarsus_l; + std::optional procoxa_r; + std::optional profemur_r; + std::optional protibia_r; + std::optional protarsus_r; + std::optional mesocoxa_l; + std::optional mesofemur_l; + std::optional mesotibia_l; + std::optional mesotarsus_l; + std::optional mesocoxa_r; + std::optional mesofemur_r; + std::optional mesotibia_r; + std::optional mesotarsus_r; + std::optional metacoxa_l; + std::optional metafemur_l; + std::optional metatibia_l; + std::optional metatarsus_l; + std::optional metacoxa_r; + std::optional metafemur_r; + std::optional metatibia_r; + std::optional metatarsus_r; + std::optional head; + std::optional mandible_l; + std::optional mandible_r; + std::optional antennomere1_l; + std::optional antennomere2_l; + std::optional antennomere1_r; + std::optional antennomere2_r; + std::optional petiole; + std::optional postpetiole; + std::optional gaster; + std::optional sting; + std::optional forewing_l; + std::optional forewing_r; + std::optional hindwing_l; + std::optional hindwing_r; }; /** @@ -91,7 +94,7 @@ void reskin_vertices const gl::vertex_attribute& normal_attribute, const gl::vertex_attribute& tangent_attribute, const gl::vertex_attribute& bone_index_attribute, - const std::unordered_map*>>& reskin_map + const std::unordered_map*>>& reskin_map ) { std::byte* position_data = vertex_data + position_attribute.offset; @@ -105,7 +108,7 @@ void reskin_vertices std::uint32_t& bone_index = reinterpret_cast(*(bone_index_data + bone_index_attribute.stride * i)); // Ignore vertices with unmapped bone indices - auto entry = reskin_map.find(static_cast(bone_index)); + auto entry = reskin_map.find(static_cast(bone_index)); if (entry == reskin_map.end()) { continue; @@ -239,11 +242,11 @@ void reskin_vertices * * sting * */ -[[nodiscard]] std::uint16_t count_ant_skeleton_bones(const ant_phenome& phenome) noexcept +[[nodiscard]] std::size_t count_ant_skeleton_bones(const ant_phenome& phenome) noexcept { - constexpr std::uint16_t minimum_bone_count = 33; + constexpr std::size_t minimum_bone_count = 33; - std::uint16_t bone_count = minimum_bone_count; + std::size_t bone_count = minimum_bone_count; if (phenome.waist->petiole_present) { @@ -275,189 +278,199 @@ void reskin_vertices void build_ant_skeleton(const ant_phenome& phenome, ::skeleton& skeleton, ant_bone_set& bones) { // Allocate bones - const std::uint16_t bone_count = count_ant_skeleton_bones(phenome); - skeleton.bones.resize(bone_count); + skeleton.set_bone_count(count_ant_skeleton_bones(phenome)); + + // Construct ant bone set + bone_index_type bone_index = 0; + bones.mesosoma = bone_index; + bones.procoxa_l = ++bone_index; + bones.profemur_l = ++bone_index; + bones.protibia_l = ++bone_index; + bones.protarsus_l = ++bone_index; + bones.procoxa_r = ++bone_index; + bones.profemur_r = ++bone_index; + bones.protibia_r = ++bone_index; + bones.protarsus_r = ++bone_index; + bones.mesocoxa_l = ++bone_index; + bones.mesofemur_l = ++bone_index; + bones.mesotibia_l = ++bone_index; + bones.mesotarsus_l = ++bone_index; + bones.mesocoxa_r = ++bone_index; + bones.mesofemur_r = ++bone_index; + bones.mesotibia_r = ++bone_index; + bones.mesotarsus_r = ++bone_index; + bones.metacoxa_l = ++bone_index; + bones.metafemur_l = ++bone_index; + bones.metatibia_l = ++bone_index; + bones.metatarsus_l = ++bone_index; + bones.metacoxa_r = ++bone_index; + bones.metafemur_r = ++bone_index; + bones.metatibia_r = ++bone_index; + bones.metatarsus_r = ++bone_index; + bones.head = ++bone_index; + bones.mandible_l = ++bone_index; + bones.mandible_r = ++bone_index; + bones.antennomere1_l = ++bone_index; + bones.antennomere2_l = ++bone_index; + bones.antennomere1_r = ++bone_index; + bones.antennomere2_r = ++bone_index; - // Assign bone indices - for (std::uint16_t i = 0; i < bone_count; ++i) + if (phenome.waist->petiole_present) { - skeleton.bones[i] = i; + bones.petiole = ++bone_index; } - // Construct ant bone set - ::bone* current_bone = skeleton.bones.data(); - bones.mesosoma = current_bone; - bones.procoxa_l = ++current_bone; - bones.profemur_l = ++current_bone; - bones.protibia_l = ++current_bone; - bones.protarsus_l = ++current_bone; - bones.procoxa_r = ++current_bone; - bones.profemur_r = ++current_bone; - bones.protibia_r = ++current_bone; - bones.protarsus_r = ++current_bone; - bones.mesocoxa_l = ++current_bone; - bones.mesofemur_l = ++current_bone; - bones.mesotibia_l = ++current_bone; - bones.mesotarsus_l = ++current_bone; - bones.mesocoxa_r = ++current_bone; - bones.mesofemur_r = ++current_bone; - bones.mesotibia_r = ++current_bone; - bones.mesotarsus_r = ++current_bone; - bones.metacoxa_l = ++current_bone; - bones.metafemur_l = ++current_bone; - bones.metatibia_l = ++current_bone; - bones.metatarsus_l = ++current_bone; - bones.metacoxa_r = ++current_bone; - bones.metafemur_r = ++current_bone; - bones.metatibia_r = ++current_bone; - bones.metatarsus_r = ++current_bone; - bones.head = ++current_bone; - bones.mandible_l = ++current_bone; - bones.mandible_r = ++current_bone; - bones.antennomere1_l = ++current_bone; - bones.antennomere2_l = ++current_bone; - bones.antennomere1_r = ++current_bone; - bones.antennomere2_r = ++current_bone; - bones.petiole = phenome.waist->petiole_present ? ++current_bone : nullptr; - bones.postpetiole = phenome.waist->postpetiole_present ? ++current_bone : nullptr; - bones.gaster = ++current_bone; - bones.sting = phenome.sting->present ? ++current_bone : nullptr; - bones.forewing_l = phenome.wings->present ? ++current_bone : nullptr; - bones.forewing_r = phenome.wings->present ? ++current_bone : nullptr; - bones.hindwing_l = phenome.wings->present ? ++current_bone : nullptr; - bones.hindwing_r = phenome.wings->present ? ++current_bone : nullptr; + if (phenome.waist->postpetiole_present) + { + bones.postpetiole = ++bone_index; + } + + bones.gaster = ++bone_index; + + if (phenome.sting->present) + { + bones.sting = ++bone_index; + } + + if (phenome.wings->present) + { + bones.forewing_l = ++bone_index; + bones.forewing_r = ++bone_index; + bones.hindwing_l = ++bone_index; + bones.hindwing_r = ++bone_index; + } // Assign bone parents - reparent_bone(*bones.mesosoma, *bones.mesosoma); - reparent_bone(*bones.procoxa_l, *bones.mesosoma); - reparent_bone(*bones.profemur_l, *bones.procoxa_l); - reparent_bone(*bones.protibia_l, *bones.profemur_l); - reparent_bone(*bones.protarsus_l, *bones.protibia_l); - reparent_bone(*bones.procoxa_r, *bones.mesosoma); - reparent_bone(*bones.profemur_r, *bones.procoxa_r); - reparent_bone(*bones.protibia_r, *bones.profemur_r); - reparent_bone(*bones.protarsus_r, *bones.protibia_r); - reparent_bone(*bones.mesocoxa_l, *bones.mesosoma); - reparent_bone(*bones.mesofemur_l, *bones.mesocoxa_l); - reparent_bone(*bones.mesotibia_l, *bones.mesofemur_l); - reparent_bone(*bones.mesotarsus_l, *bones.mesotibia_l); - reparent_bone(*bones.mesocoxa_r, *bones.mesosoma); - reparent_bone(*bones.mesofemur_r, *bones.mesocoxa_r); - reparent_bone(*bones.mesotibia_r, *bones.mesofemur_r); - reparent_bone(*bones.mesotarsus_r, *bones.mesotibia_r); - reparent_bone(*bones.metacoxa_l, *bones.mesosoma); - reparent_bone(*bones.metafemur_l, *bones.metacoxa_l); - reparent_bone(*bones.metatibia_l, *bones.metafemur_l); - reparent_bone(*bones.metatarsus_l, *bones.metatibia_l); - reparent_bone(*bones.metacoxa_r, *bones.mesosoma); - reparent_bone(*bones.metafemur_r, *bones.metacoxa_r); - reparent_bone(*bones.metatibia_r, *bones.metafemur_r); - reparent_bone(*bones.metatarsus_r, *bones.metatibia_r); - reparent_bone(*bones.head, *bones.mesosoma); - reparent_bone(*bones.mandible_l, *bones.head); - reparent_bone(*bones.mandible_r, *bones.head); - reparent_bone(*bones.antennomere1_l, *bones.head); - reparent_bone(*bones.antennomere2_l, *bones.antennomere1_l); - reparent_bone(*bones.antennomere1_r, *bones.head); - reparent_bone(*bones.antennomere2_r, *bones.antennomere1_r); + skeleton.set_bone_parent(*bones.mesosoma, *bones.mesosoma); + skeleton.set_bone_parent(*bones.procoxa_l, *bones.mesosoma); + skeleton.set_bone_parent(*bones.profemur_l, *bones.procoxa_l); + skeleton.set_bone_parent(*bones.protibia_l, *bones.profemur_l); + skeleton.set_bone_parent(*bones.protarsus_l, *bones.protibia_l); + skeleton.set_bone_parent(*bones.procoxa_r, *bones.mesosoma); + skeleton.set_bone_parent(*bones.profemur_r, *bones.procoxa_r); + skeleton.set_bone_parent(*bones.protibia_r, *bones.profemur_r); + skeleton.set_bone_parent(*bones.protarsus_r, *bones.protibia_r); + skeleton.set_bone_parent(*bones.mesocoxa_l, *bones.mesosoma); + skeleton.set_bone_parent(*bones.mesofemur_l, *bones.mesocoxa_l); + skeleton.set_bone_parent(*bones.mesotibia_l, *bones.mesofemur_l); + skeleton.set_bone_parent(*bones.mesotarsus_l, *bones.mesotibia_l); + skeleton.set_bone_parent(*bones.mesocoxa_r, *bones.mesosoma); + skeleton.set_bone_parent(*bones.mesofemur_r, *bones.mesocoxa_r); + skeleton.set_bone_parent(*bones.mesotibia_r, *bones.mesofemur_r); + skeleton.set_bone_parent(*bones.mesotarsus_r, *bones.mesotibia_r); + skeleton.set_bone_parent(*bones.metacoxa_l, *bones.mesosoma); + skeleton.set_bone_parent(*bones.metafemur_l, *bones.metacoxa_l); + skeleton.set_bone_parent(*bones.metatibia_l, *bones.metafemur_l); + skeleton.set_bone_parent(*bones.metatarsus_l, *bones.metatibia_l); + skeleton.set_bone_parent(*bones.metacoxa_r, *bones.mesosoma); + skeleton.set_bone_parent(*bones.metafemur_r, *bones.metacoxa_r); + skeleton.set_bone_parent(*bones.metatibia_r, *bones.metafemur_r); + skeleton.set_bone_parent(*bones.metatarsus_r, *bones.metatibia_r); + skeleton.set_bone_parent(*bones.head, *bones.mesosoma); + skeleton.set_bone_parent(*bones.mandible_l, *bones.head); + skeleton.set_bone_parent(*bones.mandible_r, *bones.head); + skeleton.set_bone_parent(*bones.antennomere1_l, *bones.head); + skeleton.set_bone_parent(*bones.antennomere2_l, *bones.antennomere1_l); + skeleton.set_bone_parent(*bones.antennomere1_r, *bones.head); + skeleton.set_bone_parent(*bones.antennomere2_r, *bones.antennomere1_r); if (bones.petiole) { - reparent_bone(*bones.petiole, *bones.mesosoma); + skeleton.set_bone_parent(*bones.petiole, *bones.mesosoma); } if (bones.postpetiole) { if (bones.petiole) { - reparent_bone(*bones.postpetiole, *bones.petiole); + skeleton.set_bone_parent(*bones.postpetiole, *bones.petiole); } else { - reparent_bone(*bones.postpetiole, *bones.mesosoma); + skeleton.set_bone_parent(*bones.postpetiole, *bones.mesosoma); } } if (bones.postpetiole) { - reparent_bone(*bones.gaster, *bones.postpetiole); + skeleton.set_bone_parent(*bones.gaster, *bones.postpetiole); } else { if (bones.petiole) { - reparent_bone(*bones.gaster, *bones.petiole); + skeleton.set_bone_parent(*bones.gaster, *bones.petiole); } else { - reparent_bone(*bones.gaster, *bones.mesosoma); + skeleton.set_bone_parent(*bones.gaster, *bones.mesosoma); } } if (bones.sting) { - reparent_bone(*bones.sting, *bones.gaster); + skeleton.set_bone_parent(*bones.sting, *bones.gaster); } if (bones.forewing_l) { - reparent_bone(*bones.forewing_l, *bones.mesosoma); - reparent_bone(*bones.forewing_r, *bones.mesosoma); - reparent_bone(*bones.hindwing_l, *bones.mesosoma); - reparent_bone(*bones.hindwing_r, *bones.mesosoma); + skeleton.set_bone_parent(*bones.forewing_l, *bones.mesosoma); + skeleton.set_bone_parent(*bones.forewing_r, *bones.mesosoma); + skeleton.set_bone_parent(*bones.hindwing_l, *bones.mesosoma); + skeleton.set_bone_parent(*bones.hindwing_r, *bones.mesosoma); } // Map bone names to bones - skeleton.bone_map["mesosoma"] = *bones.mesosoma; - skeleton.bone_map["procoxa_l"] = *bones.procoxa_l; - skeleton.bone_map["profemur_l"] = *bones.profemur_l; - skeleton.bone_map["protibia_l"] = *bones.protibia_l; - skeleton.bone_map["protarsus_l"] = *bones.protarsus_l; - skeleton.bone_map["procoxa_r"] = *bones.procoxa_r; - skeleton.bone_map["profemur_r"] = *bones.profemur_r; - skeleton.bone_map["protibia_r"] = *bones.protibia_r; - skeleton.bone_map["protarsus_r"] = *bones.protarsus_r; - skeleton.bone_map["mesocoxa_l"] = *bones.mesocoxa_l; - skeleton.bone_map["mesofemur_l"] = *bones.mesofemur_l; - skeleton.bone_map["mesotibia_l"] = *bones.mesotibia_l; - skeleton.bone_map["mesotarsus_l"] = *bones.mesotarsus_l; - skeleton.bone_map["mesocoxa_r"] = *bones.mesocoxa_r; - skeleton.bone_map["mesofemur_r"] = *bones.mesofemur_r; - skeleton.bone_map["mesotibia_r"] = *bones.mesotibia_r; - skeleton.bone_map["mesotarsus_r"] = *bones.mesotarsus_r; - skeleton.bone_map["metacoxa_l"] = *bones.metacoxa_l; - skeleton.bone_map["metafemur_l"] = *bones.metafemur_l; - skeleton.bone_map["metatibia_l"] = *bones.metatibia_l; - skeleton.bone_map["metatarsus_l"] = *bones.metatarsus_l; - skeleton.bone_map["metacoxa_r"] = *bones.metacoxa_r; - skeleton.bone_map["metafemur_r"] = *bones.metafemur_r; - skeleton.bone_map["metatibia_r"] = *bones.metatibia_r; - skeleton.bone_map["metatarsus_r"] = *bones.metatarsus_r; - skeleton.bone_map["head"] = *bones.head; - skeleton.bone_map["mandible_l"] = *bones.mandible_l; - skeleton.bone_map["mandible_r"] = *bones.mandible_r; - skeleton.bone_map["antennomere1_l"] = *bones.antennomere1_l; - skeleton.bone_map["antennomere2_l"] = *bones.antennomere2_l; - skeleton.bone_map["antennomere1_r"] = *bones.antennomere1_r; - skeleton.bone_map["antennomere2_r"] = *bones.antennomere2_r; + skeleton.set_bone_name(*bones.mesosoma, "mesosoma"); + skeleton.set_bone_name(*bones.procoxa_l, "procoxa_l"); + skeleton.set_bone_name(*bones.profemur_l, "profemur_l"); + skeleton.set_bone_name(*bones.protibia_l, "protibia_l"); + skeleton.set_bone_name(*bones.protarsus_l, "protarsus_l"); + skeleton.set_bone_name(*bones.procoxa_r, "procoxa_r"); + skeleton.set_bone_name(*bones.profemur_r, "profemur_r"); + skeleton.set_bone_name(*bones.protibia_r, "protibia_r"); + skeleton.set_bone_name(*bones.protarsus_r, "protarsus_r"); + skeleton.set_bone_name(*bones.mesocoxa_l, "mesocoxa_l"); + skeleton.set_bone_name(*bones.mesofemur_l, "mesofemur_l"); + skeleton.set_bone_name(*bones.mesotibia_l, "mesotibia_l"); + skeleton.set_bone_name(*bones.mesotarsus_l, "mesotarsus_l"); + skeleton.set_bone_name(*bones.mesocoxa_r, "mesocoxa_r"); + skeleton.set_bone_name(*bones.mesofemur_r, "mesofemur_r"); + skeleton.set_bone_name(*bones.mesotibia_r, "mesotibia_r"); + skeleton.set_bone_name(*bones.mesotarsus_r, "mesotarsus_r"); + skeleton.set_bone_name(*bones.metacoxa_l, "metacoxa_l"); + skeleton.set_bone_name(*bones.metafemur_l, "metafemur_l"); + skeleton.set_bone_name(*bones.metatibia_l, "metatibia_l"); + skeleton.set_bone_name(*bones.metatarsus_l, "metatarsus_l"); + skeleton.set_bone_name(*bones.metacoxa_r, "metacoxa_r"); + skeleton.set_bone_name(*bones.metafemur_r, "metafemur_r"); + skeleton.set_bone_name(*bones.metatibia_r, "metatibia_r"); + skeleton.set_bone_name(*bones.metatarsus_r, "metatarsus_r"); + skeleton.set_bone_name(*bones.head, "head"); + skeleton.set_bone_name(*bones.mandible_l, "mandible_l"); + skeleton.set_bone_name(*bones.mandible_r, "mandible_r"); + skeleton.set_bone_name(*bones.antennomere1_l, "antennomere1_l"); + skeleton.set_bone_name(*bones.antennomere2_l, "antennomere2_l"); + skeleton.set_bone_name(*bones.antennomere1_r, "antennomere1_r"); + skeleton.set_bone_name(*bones.antennomere2_r, "antennomere2_r"); if (bones.petiole) { - skeleton.bone_map["petiole"] = *bones.petiole; + skeleton.set_bone_name(*bones.petiole, "petiole"); } if (bones.postpetiole) { - skeleton.bone_map["postpetiole"] = *bones.postpetiole; + skeleton.set_bone_name(*bones.postpetiole, "postpetiole"); } - skeleton.bone_map["gaster"] = *bones.gaster; + skeleton.set_bone_name(*bones.gaster, "gaster"); if (bones.sting) { - skeleton.bone_map["sting"] = *bones.sting; + skeleton.set_bone_name(*bones.sting, "sting"); } if (bones.forewing_l) { - skeleton.bone_map["forewing_l"] = *bones.forewing_l; - skeleton.bone_map["forewing_r"] = *bones.forewing_r; - skeleton.bone_map["hindwing_l"] = *bones.hindwing_l; - skeleton.bone_map["hindwing_r"] = *bones.hindwing_r; + skeleton.set_bone_name(*bones.forewing_l, "forewing_l"); + skeleton.set_bone_name(*bones.forewing_r, "forewing_r"); + skeleton.set_bone_name(*bones.hindwing_l, "hindwing_l"); + skeleton.set_bone_name(*bones.hindwing_r, "hindwing_r"); } } @@ -469,7 +482,7 @@ void build_ant_skeleton(const ant_phenome& phenome, ::skeleton& skeleton, ant_bo * @param[in,out] skeleton Ant skeleton. * @param[out] bind_pose_ss Skeleton-space bind pose. */ -void build_ant_bind_pose(const ant_phenome& phenome, const ant_bone_set& bones, ::skeleton& skeleton, ::pose& bind_pose_ss) +void build_ant_bind_pose(const ant_phenome& phenome, const ant_bone_set& bones, ::skeleton& skeleton) { // Get body part skeletons const ::skeleton& mesosoma_skeleton = phenome.mesosoma->model->get_skeleton(); @@ -483,80 +496,78 @@ void build_ant_bind_pose(const ant_phenome& phenome, const ant_bone_set& bones, const ::skeleton* forewings_skeleton = (phenome.wings->present) ? &phenome.wings->forewings_model->get_skeleton() : nullptr; const ::skeleton* hindwings_skeleton = (phenome.wings->present) ? &phenome.wings->hindwings_model->get_skeleton() : nullptr; - // Get reference to skeleton bind pose - pose& bind_pose = skeleton.bind_pose; + auto get_bone_transform = [](const ::skeleton& skeleton, hash::fnv1a32_t bone_name) + { + return skeleton.get_bind_pose().get_relative_transform(*skeleton.get_bone_index(bone_name)); + }; // Build skeleton bind pose - bind_pose[*bones.mesosoma] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("mesosoma")); - bind_pose[*bones.procoxa_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("procoxa_l")); - bind_pose[*bones.profemur_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("profemur_l")); - bind_pose[*bones.protibia_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("protibia_l")); - bind_pose[*bones.protarsus_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("protarsus1_l")); - bind_pose[*bones.procoxa_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("procoxa_r")); - bind_pose[*bones.profemur_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("profemur_r")); - bind_pose[*bones.protibia_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("protibia_r")); - bind_pose[*bones.protarsus_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("protarsus1_r")); - bind_pose[*bones.mesocoxa_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesocoxa_l")); - bind_pose[*bones.mesofemur_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesofemur_l")); - bind_pose[*bones.mesotibia_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesotibia_l")); - bind_pose[*bones.mesotarsus_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesotarsus1_l")); - bind_pose[*bones.mesocoxa_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesocoxa_r")); - bind_pose[*bones.mesofemur_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesofemur_r")); - bind_pose[*bones.mesotibia_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesotibia_r")); - bind_pose[*bones.mesotarsus_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesotarsus1_r")); - bind_pose[*bones.metacoxa_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metacoxa_l")); - bind_pose[*bones.metafemur_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metafemur_l")); - bind_pose[*bones.metatibia_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metatibia_l")); - bind_pose[*bones.metatarsus_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metatarsus1_l")); - bind_pose[*bones.metacoxa_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metacoxa_r")); - bind_pose[*bones.metafemur_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metafemur_r")); - bind_pose[*bones.metatibia_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metatibia_r")); - bind_pose[*bones.metatarsus_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metatarsus1_r")); - bind_pose[*bones.head] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("head")) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("head")); - bind_pose[*bones.mandible_l] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("mandible_l")) * mandibles_skeleton.bind_pose.at(mandibles_skeleton.bone_map.at("mandible_l")); - bind_pose[*bones.mandible_r] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("mandible_r")) * mandibles_skeleton.bind_pose.at(mandibles_skeleton.bone_map.at("mandible_r")); - bind_pose[*bones.antennomere1_l] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("antenna_l")) * antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("antennomere1_l")); - bind_pose[*bones.antennomere2_l] = antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("antennomere2_l")); - bind_pose[*bones.antennomere1_r] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("antenna_r")) * antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("antennomere1_r")); - bind_pose[*bones.antennomere2_r] = antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("antennomere2_r")); + skeleton.set_bone_transform(*bones.mesosoma, get_bone_transform(mesosoma_skeleton, "mesosoma")); + skeleton.set_bone_transform(*bones.procoxa_l, get_bone_transform(legs_skeleton, "procoxa_l")); + skeleton.set_bone_transform(*bones.profemur_l, get_bone_transform(legs_skeleton, "profemur_l")); + skeleton.set_bone_transform(*bones.protibia_l, get_bone_transform(legs_skeleton, "protibia_l")); + skeleton.set_bone_transform(*bones.protarsus_l, get_bone_transform(legs_skeleton, "protarsus1_l")); + skeleton.set_bone_transform(*bones.procoxa_r, get_bone_transform(legs_skeleton, "procoxa_r")); + skeleton.set_bone_transform(*bones.profemur_r, get_bone_transform(legs_skeleton, "profemur_r")); + skeleton.set_bone_transform(*bones.protibia_r, get_bone_transform(legs_skeleton, "protibia_r")); + skeleton.set_bone_transform(*bones.protarsus_r, get_bone_transform(legs_skeleton, "protarsus1_r")); + skeleton.set_bone_transform(*bones.mesocoxa_l, get_bone_transform(legs_skeleton, "mesocoxa_l")); + skeleton.set_bone_transform(*bones.mesofemur_l, get_bone_transform(legs_skeleton, "mesofemur_l")); + skeleton.set_bone_transform(*bones.mesotibia_l, get_bone_transform(legs_skeleton, "mesotibia_l")); + skeleton.set_bone_transform(*bones.mesotarsus_l, get_bone_transform(legs_skeleton, "mesotarsus1_l")); + skeleton.set_bone_transform(*bones.mesocoxa_r, get_bone_transform(legs_skeleton, "mesocoxa_r")); + skeleton.set_bone_transform(*bones.mesofemur_r, get_bone_transform(legs_skeleton, "mesofemur_r")); + skeleton.set_bone_transform(*bones.mesotibia_r, get_bone_transform(legs_skeleton, "mesotibia_r")); + skeleton.set_bone_transform(*bones.mesotarsus_r, get_bone_transform(legs_skeleton, "mesotarsus1_r")); + skeleton.set_bone_transform(*bones.metacoxa_l, get_bone_transform(legs_skeleton, "metacoxa_l")); + skeleton.set_bone_transform(*bones.metafemur_l, get_bone_transform(legs_skeleton, "metafemur_l")); + skeleton.set_bone_transform(*bones.metatibia_l, get_bone_transform(legs_skeleton, "metatibia_l")); + skeleton.set_bone_transform(*bones.metatarsus_l, get_bone_transform(legs_skeleton, "metatarsus1_l")); + skeleton.set_bone_transform(*bones.metacoxa_r, get_bone_transform(legs_skeleton, "metacoxa_r")); + skeleton.set_bone_transform(*bones.metafemur_r, get_bone_transform(legs_skeleton, "metafemur_r")); + skeleton.set_bone_transform(*bones.metatibia_r, get_bone_transform(legs_skeleton, "metatibia_r")); + skeleton.set_bone_transform(*bones.metatarsus_r, get_bone_transform(legs_skeleton, "metatarsus1_r")); + skeleton.set_bone_transform(*bones.head, get_bone_transform(mesosoma_skeleton, "head") * get_bone_transform(head_skeleton, "head")); + skeleton.set_bone_transform(*bones.mandible_l, get_bone_transform(head_skeleton, "mandible_l") * get_bone_transform(mandibles_skeleton, "mandible_l")); + skeleton.set_bone_transform(*bones.mandible_r, get_bone_transform(head_skeleton, "mandible_r") * get_bone_transform(mandibles_skeleton, "mandible_r")); + skeleton.set_bone_transform(*bones.antennomere1_l, get_bone_transform(head_skeleton, "antenna_l") * get_bone_transform(antennae_skeleton, "antennomere1_l")); + skeleton.set_bone_transform(*bones.antennomere2_l, get_bone_transform(antennae_skeleton, "antennomere2_l")); + skeleton.set_bone_transform(*bones.antennomere1_r, get_bone_transform(head_skeleton, "antenna_r") * get_bone_transform(antennae_skeleton, "antennomere1_r")); + skeleton.set_bone_transform(*bones.antennomere2_r, get_bone_transform(antennae_skeleton, "antennomere2_r")); if (bones.petiole) { - bind_pose[*bones.petiole] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("petiole")) * waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("petiole")); + skeleton.set_bone_transform(*bones.petiole, get_bone_transform(mesosoma_skeleton, "petiole") * get_bone_transform(waist_skeleton, "petiole")); } if (bones.postpetiole) { - bind_pose[*bones.postpetiole] = waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("postpetiole")); - bind_pose[*bones.gaster] = waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("postpetiole")) * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("gaster")); + skeleton.set_bone_transform(*bones.postpetiole, get_bone_transform(waist_skeleton, "postpetiole")); + skeleton.set_bone_transform(*bones.gaster, get_bone_transform(waist_skeleton, "postpetiole") * get_bone_transform(gaster_skeleton, "gaster")); } else if (bones.petiole) { - bind_pose[*bones.gaster] = waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("petiole")) * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("gaster")); + skeleton.set_bone_transform(*bones.gaster, get_bone_transform(waist_skeleton, "petiole") * get_bone_transform(gaster_skeleton, "gaster")); } else { - bind_pose[*bones.gaster] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("petiole")) * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("gaster")); + skeleton.set_bone_transform(*bones.gaster, get_bone_transform(mesosoma_skeleton, "petiole") * get_bone_transform(gaster_skeleton, "gaster")); } if (bones.sting) { - bind_pose[*bones.sting] = gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("sting")) * sting_skeleton->bind_pose.at(sting_skeleton->bone_map.at("sting")); + skeleton.set_bone_transform(*bones.sting, get_bone_transform(gaster_skeleton, "sting") * get_bone_transform(*sting_skeleton, "sting")); } if (bones.forewing_l) { - bind_pose[*bones.forewing_l] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("forewing_l")) * forewings_skeleton->bind_pose.at(forewings_skeleton->bone_map.at("forewing_l")); - bind_pose[*bones.forewing_r] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("forewing_r")) * forewings_skeleton->bind_pose.at(forewings_skeleton->bone_map.at("forewing_r")); - bind_pose[*bones.hindwing_l] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("hindwing_l")) * hindwings_skeleton->bind_pose.at(hindwings_skeleton->bone_map.at("hindwing_l")); - bind_pose[*bones.hindwing_r] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("hindwing_r")) * hindwings_skeleton->bind_pose.at(hindwings_skeleton->bone_map.at("hindwing_r")); + skeleton.set_bone_transform(*bones.forewing_l, get_bone_transform(mesosoma_skeleton, "forewing_l") * get_bone_transform(*forewings_skeleton, "forewing_l")); + skeleton.set_bone_transform(*bones.forewing_r, get_bone_transform(mesosoma_skeleton, "forewing_r") * get_bone_transform(*forewings_skeleton, "forewing_r")); + skeleton.set_bone_transform(*bones.hindwing_l, get_bone_transform(mesosoma_skeleton, "hindwing_l") * get_bone_transform(*hindwings_skeleton, "hindwing_l")); + skeleton.set_bone_transform(*bones.hindwing_r, get_bone_transform(mesosoma_skeleton, "hindwing_r") * get_bone_transform(*hindwings_skeleton, "hindwing_r")); } - // Calculate the skeleton-space bind pose - ::concatenate(bind_pose, bind_pose_ss); - - // Calculate inverse skeleton-space bind pose - ::inverse(bind_pose_ss, skeleton.inverse_bind_pose); + skeleton.update_bind_pose(); } } // namespace @@ -772,8 +783,8 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome) build_ant_skeleton(phenome, skeleton, bones); // Build ant bind pose - pose bind_pose_ss; - build_ant_bind_pose(phenome, bones, skeleton, bind_pose_ss); + build_ant_bind_pose(phenome, bones, skeleton); + const auto& bind_pose = skeleton.get_bind_pose(); // Get number of vertices for each body part const std::uint32_t mesosoma_vertex_count = (mesosoma_model->get_groups()).front().index_count; @@ -814,41 +825,46 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome) const ::skeleton* forewings_skeleton = (phenome.wings->present) ? &phenome.wings->forewings_model->get_skeleton() : nullptr; const ::skeleton* hindwings_skeleton = (phenome.wings->present) ? &phenome.wings->hindwings_model->get_skeleton() : nullptr; + auto get_bone_transform = [](const ::skeleton& skeleton, hash::fnv1a32_t bone_name) + { + return skeleton.get_bind_pose().get_relative_transform(*skeleton.get_bone_index(bone_name)); + }; + // Calculate transformations from part space to body space const math::transform legs_to_body = math::transform::identity(); - const math::transform head_to_body = bind_pose_ss.at(*bones.mesosoma) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("head")); - const math::transform mandible_l_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("mandible_l")); - const math::transform mandible_r_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("mandible_r")); - const math::transform antenna_l_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("antenna_l")); - const math::transform antenna_r_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("antenna_r")); - const math::transform waist_to_body = bind_pose_ss.at(*bones.mesosoma) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("petiole")); + const math::transform head_to_body = bind_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "head"); + const math::transform mandible_l_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "mandible_l"); + const math::transform mandible_r_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "mandible_r"); + const math::transform antenna_l_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "antenna_l"); + const math::transform antenna_r_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "antenna_r"); + const math::transform waist_to_body = bind_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "petiole"); math::transform gaster_to_body; if (phenome.waist->postpetiole_present) { - gaster_to_body = bind_pose_ss.at(*bones.postpetiole) * waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("gaster")); + gaster_to_body = bind_pose.get_absolute_transform(*bones.postpetiole) * get_bone_transform(waist_skeleton, "gaster"); } else if (phenome.waist->petiole_present) { - gaster_to_body = bind_pose_ss.at(*bones.petiole) * waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("gaster")); + gaster_to_body = bind_pose.get_absolute_transform(*bones.petiole) * get_bone_transform(waist_skeleton, "gaster"); } else { - gaster_to_body = bind_pose_ss.at(*bones.mesosoma) * waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("gaster")); + gaster_to_body = bind_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(waist_skeleton, "gaster"); } math::transform sting_to_body; if (phenome.sting->present) { - sting_to_body = gaster_to_body * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("sting")); + sting_to_body = gaster_to_body * get_bone_transform(gaster_skeleton, "sting"); } math::transform eye_l_to_body; math::transform eye_r_to_body; if (phenome.eyes->present) { - eye_l_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("eye_l")); - eye_r_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("eye_r")); + eye_l_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "eye_l"); + eye_r_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "eye_r"); } math::transform ocellus_l_to_body; @@ -856,12 +872,12 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome) math::transform ocellus_m_to_body; if (phenome.ocelli->lateral_ocelli_present) { - ocellus_l_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("ocellus_l")); - ocellus_r_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("ocellus_r")); + ocellus_l_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "ocellus_l"); + ocellus_r_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "ocellus_r"); } if (phenome.ocelli->median_ocellus_present) { - ocellus_m_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("ocellus_m")); + ocellus_m_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "ocellus_m"); } math::transform forewing_l_to_body; @@ -870,85 +886,85 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome) math::transform hindwing_r_to_body; if (phenome.wings->present) { - forewing_l_to_body = bind_pose_ss.at(*bones.mesosoma) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("forewing_l")); - forewing_r_to_body = bind_pose_ss.at(*bones.mesosoma) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("forewing_r")); - hindwing_l_to_body = bind_pose_ss.at(*bones.mesosoma) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("hindwing_l")); - hindwing_r_to_body = bind_pose_ss.at(*bones.mesosoma) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("hindwing_r")); + forewing_l_to_body = bind_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "forewing_l"); + forewing_r_to_body = bind_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "forewing_r"); + hindwing_l_to_body = bind_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "hindwing_l"); + hindwing_r_to_body = bind_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "hindwing_r"); } // Build legs vertex reskin map - const std::unordered_map*>> legs_reskin_map - { - {bone_index(legs_skeleton.bone_map.at("procoxa_l")), {bone_index(*bones.procoxa_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("profemur_l")), {bone_index(*bones.profemur_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("protibia_l")), {bone_index(*bones.protibia_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("protarsus1_l")), {bone_index(*bones.protarsus_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("protarsus2_l")), {bone_index(*bones.protarsus_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("protarsus3_l")), {bone_index(*bones.protarsus_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("protarsus4_l")), {bone_index(*bones.protarsus_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("protarsus5_l")), {bone_index(*bones.protarsus_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("procoxa_r")), {bone_index(*bones.procoxa_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("profemur_r")), {bone_index(*bones.profemur_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("protibia_r")), {bone_index(*bones.protibia_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("protarsus1_r")), {bone_index(*bones.protarsus_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("protarsus2_r")), {bone_index(*bones.protarsus_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("protarsus3_r")), {bone_index(*bones.protarsus_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("protarsus4_r")), {bone_index(*bones.protarsus_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("protarsus5_r")), {bone_index(*bones.protarsus_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesocoxa_l")), {bone_index(*bones.mesocoxa_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesofemur_l")), {bone_index(*bones.mesofemur_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesotibia_l")), {bone_index(*bones.mesotibia_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesotarsus1_l")), {bone_index(*bones.mesotarsus_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesotarsus2_l")), {bone_index(*bones.mesotarsus_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesotarsus3_l")), {bone_index(*bones.mesotarsus_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesotarsus4_l")), {bone_index(*bones.mesotarsus_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesotarsus5_l")), {bone_index(*bones.mesotarsus_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesocoxa_r")), {bone_index(*bones.mesocoxa_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesofemur_r")), {bone_index(*bones.mesofemur_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesotibia_r")), {bone_index(*bones.mesotibia_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesotarsus1_r")), {bone_index(*bones.mesotarsus_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesotarsus2_r")), {bone_index(*bones.mesotarsus_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesotarsus3_r")), {bone_index(*bones.mesotarsus_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesotarsus4_r")), {bone_index(*bones.mesotarsus_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("mesotarsus5_r")), {bone_index(*bones.mesotarsus_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metacoxa_l")), {bone_index(*bones.metacoxa_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metafemur_l")), {bone_index(*bones.metafemur_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metatibia_l")), {bone_index(*bones.metatibia_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metatarsus1_l")), {bone_index(*bones.metatarsus_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metatarsus2_l")), {bone_index(*bones.metatarsus_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metatarsus3_l")), {bone_index(*bones.metatarsus_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metatarsus4_l")), {bone_index(*bones.metatarsus_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metatarsus5_l")), {bone_index(*bones.metatarsus_l), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metacoxa_r")), {bone_index(*bones.metacoxa_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metafemur_r")), {bone_index(*bones.metafemur_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metatibia_r")), {bone_index(*bones.metatibia_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metatarsus1_r")), {bone_index(*bones.metatarsus_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metatarsus2_r")), {bone_index(*bones.metatarsus_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metatarsus3_r")), {bone_index(*bones.metatarsus_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metatarsus4_r")), {bone_index(*bones.metatarsus_r), &legs_to_body}}, - {bone_index(legs_skeleton.bone_map.at("metatarsus5_r")), {bone_index(*bones.metatarsus_r), &legs_to_body}} + const std::unordered_map*>> legs_reskin_map + { + {*legs_skeleton.get_bone_index("procoxa_l"), {*bones.procoxa_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("profemur_l"), {*bones.profemur_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("protibia_l"), {*bones.protibia_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("protarsus1_l"), {*bones.protarsus_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("protarsus2_l"), {*bones.protarsus_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("protarsus3_l"), {*bones.protarsus_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("protarsus4_l"), {*bones.protarsus_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("protarsus5_l"), {*bones.protarsus_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("procoxa_r"), {*bones.procoxa_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("profemur_r"), {*bones.profemur_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("protibia_r"), {*bones.protibia_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("protarsus1_r"), {*bones.protarsus_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("protarsus2_r"), {*bones.protarsus_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("protarsus3_r"), {*bones.protarsus_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("protarsus4_r"), {*bones.protarsus_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("protarsus5_r"), {*bones.protarsus_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesocoxa_l"), {*bones.mesocoxa_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesofemur_l"), {*bones.mesofemur_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesotibia_l"), {*bones.mesotibia_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesotarsus1_l"), {*bones.mesotarsus_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesotarsus2_l"), {*bones.mesotarsus_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesotarsus3_l"), {*bones.mesotarsus_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesotarsus4_l"), {*bones.mesotarsus_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesotarsus5_l"), {*bones.mesotarsus_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesocoxa_r"), {*bones.mesocoxa_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesofemur_r"), {*bones.mesofemur_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesotibia_r"), {*bones.mesotibia_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesotarsus1_r"), {*bones.mesotarsus_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesotarsus2_r"), {*bones.mesotarsus_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesotarsus3_r"), {*bones.mesotarsus_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesotarsus4_r"), {*bones.mesotarsus_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("mesotarsus5_r"), {*bones.mesotarsus_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metacoxa_l"), {*bones.metacoxa_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metafemur_l"), {*bones.metafemur_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metatibia_l"), {*bones.metatibia_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metatarsus1_l"), {*bones.metatarsus_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metatarsus2_l"), {*bones.metatarsus_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metatarsus3_l"), {*bones.metatarsus_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metatarsus4_l"), {*bones.metatarsus_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metatarsus5_l"), {*bones.metatarsus_l, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metacoxa_r"), {*bones.metacoxa_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metafemur_r"), {*bones.metafemur_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metatibia_r"), {*bones.metatibia_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metatarsus1_r"), {*bones.metatarsus_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metatarsus2_r"), {*bones.metatarsus_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metatarsus3_r"), {*bones.metatarsus_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metatarsus4_r"), {*bones.metatarsus_r, &legs_to_body}}, + {*legs_skeleton.get_bone_index("metatarsus5_r"), {*bones.metatarsus_r, &legs_to_body}} }; // Build head vertex reskin map - const std::unordered_map*>> head_reskin_map + const std::unordered_map*>> head_reskin_map { - {bone_index(head_skeleton.bone_map.at("head")), {bone_index(*bones.head), &head_to_body}} + {*head_skeleton.get_bone_index("head"), {*bones.head, &head_to_body}} }; // Build mandibles vertex reskin map - const std::unordered_map*>> mandibles_reskin_map + const std::unordered_map*>> mandibles_reskin_map { - {bone_index(mandibles_skeleton.bone_map.at("mandible_l")), {bone_index(*bones.mandible_l), &mandible_l_to_body}}, - {bone_index(mandibles_skeleton.bone_map.at("mandible_r")), {bone_index(*bones.mandible_r), &mandible_r_to_body}} + {*mandibles_skeleton.get_bone_index("mandible_l"), {*bones.mandible_l, &mandible_l_to_body}}, + {*mandibles_skeleton.get_bone_index("mandible_r"), {*bones.mandible_r, &mandible_r_to_body}} }; // Build antennae vertex reskin map - std::unordered_map*>> antennae_reskin_map + std::unordered_map*>> antennae_reskin_map { - {bone_index(antennae_skeleton.bone_map.at("antennomere1_l")), {bone_index(*bones.antennomere1_l), &antenna_l_to_body}}, - {bone_index(antennae_skeleton.bone_map.at("antennomere2_l")), {bone_index(*bones.antennomere2_l), &antenna_l_to_body}}, - {bone_index(antennae_skeleton.bone_map.at("antennomere1_r")), {bone_index(*bones.antennomere1_r), &antenna_r_to_body}}, - {bone_index(antennae_skeleton.bone_map.at("antennomere2_r")), {bone_index(*bones.antennomere2_r), &antenna_r_to_body}} + {*antennae_skeleton.get_bone_index("antennomere1_l"), {*bones.antennomere1_l, &antenna_l_to_body}}, + {*antennae_skeleton.get_bone_index("antennomere2_l"), {*bones.antennomere2_l, &antenna_l_to_body}}, + {*antennae_skeleton.get_bone_index("antennomere1_r"), {*bones.antennomere1_r, &antenna_r_to_body}}, + {*antennae_skeleton.get_bone_index("antennomere2_r"), {*bones.antennomere2_r, &antenna_r_to_body}} }; for (std::uint8_t i = 3; i <= phenome.antennae->total_antennomere_count; ++i) { @@ -958,66 +974,66 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome) const hash::fnv1a32_t antennomere_l_key = hash::fnv1a32(antennomere_l_name); const hash::fnv1a32_t antennomere_r_key = hash::fnv1a32(antennomere_r_name); - antennae_reskin_map.emplace(bone_index(antennae_skeleton.bone_map.at(antennomere_l_key)), std::tuple(bone_index(*bones.antennomere2_l), &antenna_l_to_body)); - antennae_reskin_map.emplace(bone_index(antennae_skeleton.bone_map.at(antennomere_r_key)), std::tuple(bone_index(*bones.antennomere2_r), &antenna_r_to_body)); + antennae_reskin_map.emplace(*antennae_skeleton.get_bone_index(antennomere_l_key), std::tuple(*bones.antennomere2_l, &antenna_l_to_body)); + antennae_reskin_map.emplace(*antennae_skeleton.get_bone_index(antennomere_r_key), std::tuple(*bones.antennomere2_r, &antenna_r_to_body)); } // Build waist vertex reskin map - std::unordered_map*>> waist_reskin_map; + std::unordered_map*>> waist_reskin_map; if (phenome.waist->petiole_present) { - waist_reskin_map.emplace(bone_index(waist_skeleton.bone_map.at("petiole")), std::tuple(bone_index(*bones.petiole), &waist_to_body)); + waist_reskin_map.emplace(*waist_skeleton.get_bone_index("petiole"), std::tuple(*bones.petiole, &waist_to_body)); } if (phenome.waist->postpetiole_present) { - waist_reskin_map.emplace(bone_index(waist_skeleton.bone_map.at("postpetiole")), std::tuple(bone_index(*bones.postpetiole), &waist_to_body)); + waist_reskin_map.emplace(*waist_skeleton.get_bone_index("postpetiole"), std::tuple(*bones.postpetiole, &waist_to_body)); } // Build gaster vertex reskin map - const std::unordered_map*>> gaster_reskin_map + const std::unordered_map*>> gaster_reskin_map { - {bone_index(gaster_skeleton.bone_map.at("gaster")), {bone_index(*bones.gaster), &gaster_to_body}} + {*gaster_skeleton.get_bone_index("gaster"), {*bones.gaster, &gaster_to_body}} }; // Build sting vertex reskin map - std::unordered_map*>> sting_reskin_map; + std::unordered_map*>> sting_reskin_map; if (phenome.sting->present) { - sting_reskin_map.emplace(bone_index(sting_skeleton->bone_map.at("sting")), std::tuple(bone_index(*bones.sting), &sting_to_body)); + sting_reskin_map.emplace(*sting_skeleton->get_bone_index("sting"), std::tuple(*bones.sting, &sting_to_body)); } // Build eyes vertex reskin map - std::unordered_map*>> eyes_reskin_map; + std::unordered_map*>> eyes_reskin_map; if (phenome.eyes->present) { - eyes_reskin_map.emplace(bone_index(eyes_skeleton->bone_map.at("eye_l")), std::tuple(bone_index(*bones.head), &eye_l_to_body)); - eyes_reskin_map.emplace(bone_index(eyes_skeleton->bone_map.at("eye_r")), std::tuple(bone_index(*bones.head), &eye_r_to_body)); + eyes_reskin_map.emplace(*eyes_skeleton->get_bone_index("eye_l"), std::tuple(*bones.head, &eye_l_to_body)); + eyes_reskin_map.emplace(*eyes_skeleton->get_bone_index("eye_r"), std::tuple(*bones.head, &eye_r_to_body)); } // Build lateral ocelli vertex reskin map - std::unordered_map*>> lateral_ocelli_reskin_map; + std::unordered_map*>> lateral_ocelli_reskin_map; if (phenome.ocelli->lateral_ocelli_present) { - lateral_ocelli_reskin_map.emplace(bone_index(lateral_ocelli_skeleton->bone_map.at("ocellus_l")), std::tuple(bone_index(*bones.head), &ocellus_l_to_body)); - lateral_ocelli_reskin_map.emplace(bone_index(lateral_ocelli_skeleton->bone_map.at("ocellus_r")), std::tuple(bone_index(*bones.head), &ocellus_r_to_body)); + lateral_ocelli_reskin_map.emplace(*lateral_ocelli_skeleton->get_bone_index("ocellus_l"), std::tuple(*bones.head, &ocellus_l_to_body)); + lateral_ocelli_reskin_map.emplace(*lateral_ocelli_skeleton->get_bone_index("ocellus_r"), std::tuple(*bones.head, &ocellus_r_to_body)); } // Build median ocellus vertex reskin map - std::unordered_map*>> median_ocellus_reskin_map; + std::unordered_map*>> median_ocellus_reskin_map; if (phenome.ocelli->median_ocellus_present) { - median_ocellus_reskin_map.emplace(bone_index(median_ocellus_skeleton->bone_map.at("ocellus_m")), std::tuple(bone_index(*bones.head), &ocellus_m_to_body)); + median_ocellus_reskin_map.emplace(*median_ocellus_skeleton->get_bone_index("ocellus_m"), std::tuple(*bones.head, &ocellus_m_to_body)); } // Build wings vertex reskin maps - std::unordered_map*>> forewings_reskin_map; - std::unordered_map*>> hindwings_reskin_map; + std::unordered_map*>> forewings_reskin_map; + std::unordered_map*>> hindwings_reskin_map; if (phenome.wings->present) { - forewings_reskin_map.emplace(bone_index(forewings_skeleton->bone_map.at("forewing_l")), std::tuple(bone_index(*bones.forewing_l), &forewing_l_to_body)); - forewings_reskin_map.emplace(bone_index(forewings_skeleton->bone_map.at("forewing_r")), std::tuple(bone_index(*bones.forewing_r), &forewing_r_to_body)); - hindwings_reskin_map.emplace(bone_index(hindwings_skeleton->bone_map.at("hindwing_l")), std::tuple(bone_index(*bones.hindwing_l), &hindwing_l_to_body)); - hindwings_reskin_map.emplace(bone_index(hindwings_skeleton->bone_map.at("hindwing_r")), std::tuple(bone_index(*bones.hindwing_r), &hindwing_r_to_body)); + forewings_reskin_map.emplace(*forewings_skeleton->get_bone_index("forewing_l"), std::tuple(*bones.forewing_l, &forewing_l_to_body)); + forewings_reskin_map.emplace(*forewings_skeleton->get_bone_index("forewing_r"), std::tuple(*bones.forewing_r, &forewing_r_to_body)); + hindwings_reskin_map.emplace(*hindwings_skeleton->get_bone_index("hindwing_l"), std::tuple(*bones.hindwing_l, &hindwing_l_to_body)); + hindwings_reskin_map.emplace(*hindwings_skeleton->get_bone_index("hindwing_r"), std::tuple(*bones.hindwing_r, &hindwing_r_to_body)); } // Reskin legs vertices diff --git a/src/game/states/nest-selection-state.cpp b/src/game/states/nest-selection-state.cpp index 8278106..a23e4d6 100644 --- a/src/game/states/nest-selection-state.cpp +++ b/src/game/states/nest-selection-state.cpp @@ -71,6 +71,7 @@ #include #include #include +#include nest_selection_state::nest_selection_state(::game& ctx): game_state(ctx) @@ -102,8 +103,6 @@ nest_selection_state::nest_selection_state(::game& ctx): worker_model = ant_morphogenesis(worker_phenome); debug::log::trace("Generated worker model"); - - // Create floor plane auto floor_archetype = ctx.resource_manager->load("desert-scrub-plane.ent"); @@ -128,13 +127,33 @@ nest_selection_state::nest_selection_state(::game& ctx): ctx.entity_registry->emplace(floor_eid, std::move(floor_body)); // Create worker entity(s) + + auto worker_rigged_mesh = std::make_unique(worker_model); + + const auto& worker_skeleton = worker_model->get_skeleton(); + const auto& worker_bind_pose = worker_skeleton.get_bind_pose(); + auto& worker_pose = worker_rigged_mesh->get_pose(); + + const float mandibles_open_angle = math::radians(32.0f); + auto open_left_mandible = math::transform::identity(); + open_left_mandible.rotation = math::angle_axis(-mandibles_open_angle, float3{0, 0, 1}); + auto open_right_mandible = math::transform::identity(); + open_right_mandible.rotation = math::angle_axis(mandibles_open_angle, float3{0, 0, 1}); + + auto mandible_l_bone = *worker_skeleton.get_bone_index("mandible_l"); + auto mandible_r_bone = *worker_skeleton.get_bone_index("mandible_r"); + + worker_pose.set_relative_transform(mandible_l_bone, worker_bind_pose.get_relative_transform(mandible_l_bone) * open_left_mandible); + worker_pose.set_relative_transform(mandible_r_bone, worker_bind_pose.get_relative_transform(mandible_r_bone) * open_right_mandible); + worker_pose.update(); + worker_ant_eid = ctx.entity_registry->create(); transform_component worker_transform_component; worker_transform_component.local = math::transform::identity(); worker_transform_component.local.translation = {0, 0.5f, -4}; worker_transform_component.world = worker_transform_component.local; ctx.entity_registry->emplace(worker_ant_eid, worker_transform_component); - ctx.entity_registry->emplace(worker_ant_eid, std::make_unique(worker_model), std::uint8_t{1}); + ctx.entity_registry->emplace(worker_ant_eid, std::move(worker_rigged_mesh), std::uint8_t{1});