// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE #pragma once #include #include #include namespace anki { /// @addtogroup resource /// @{ const U32 MAX_CHILDREN_PER_BONE = 8; /// Skeleton bone class Bone { friend class SkeletonResource; ///< For loading public: Bone() = default; ~Bone() = default; const String& getName() const { return m_name; } const Mat4& getTransform() const { return m_transform; } const Mat4& getVertexTransform() const { return m_vertTrf; } U32 getIndex() const { return m_idx; } ConstWeakArray getChildren() const { return ConstWeakArray((m_childrenCount) ? &m_children[0] : nullptr, m_childrenCount); } const Bone* getParent() const { return m_parent; } private: String m_name; ///< The name of the bone Mat4 m_transform; ///< See the class notes. Mat4 m_vertTrf; U32 m_idx; Bone* m_parent = nullptr; Array m_children = {}; U8 m_childrenCount = 0; void destroy(ResourceAllocator alloc) { m_name.destroy(alloc); } }; /// It contains the bones with their position and hierarchy /// /// XML file format: /// /// @code /// /// /// /// X /// 16 floats /// 16 floats /// [bone_name] /// /// ... /// /// /// @endcode class SkeletonResource : public ResourceObject { public: SkeletonResource(ResourceManager* manager) : ResourceObject(manager) { } ~SkeletonResource(); /// Load file ANKI_USE_RESULT Error load(const ResourceFilename& filename, Bool async); const DynamicArray& getBones() const { return m_bones; } const Bone* tryFindBone(CString name) const { // TODO Optimize for(const Bone& b : m_bones) { if(b.m_name == name) { return &b; } } return nullptr; } const Bone& getRootBone() const { return m_bones[m_rootBoneIdx]; } private: DynamicArray m_bones; U32 m_rootBoneIdx = MAX_U32; }; /// @} } // end namespace anki