// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Core/Math/Transform.h" #include "Engine/Core/Math/Matrix.h" #include "Engine/Core/Types/String.h" #include "Engine/Core/Types/StringView.h" #include "Engine/Core/Collections/Array.h" /// /// Describes a single skeleton node data. Used by the runtime. /// API_STRUCT() struct SkeletonNode { DECLARE_SCRIPTING_TYPE_MINIMAL(SkeletonNode); /// /// The parent node index. The root node uses value -1. /// API_FIELD() int32 ParentIndex; /// /// The local transformation of the node, relative to the parent node. /// API_FIELD() Transform LocalTransform; /// /// The name of this node. /// API_FIELD() String Name; }; /// /// Describes a single skeleton bone data. Used by the runtime. Skeleton bones are subset of the skeleton nodes collection that are actually used by the skinned model meshes. /// API_STRUCT() struct SkeletonBone { DECLARE_SCRIPTING_TYPE_MINIMAL(SkeletonBone); /// /// The parent bone index. The root bone uses value -1. /// API_FIELD() int32 ParentIndex; /// /// The index of the skeleton node where bone is 'attached'. Used as a animation transformation source. /// API_FIELD() int32 NodeIndex; /// /// The local transformation of the bone, relative to the parent bone (in bind pose). /// API_FIELD() Transform LocalTransform; /// /// The matrix that transforms from mesh space to bone space in bind pose (inverse bind pose). /// API_FIELD() Matrix OffsetMatrix; }; template<> struct TIsPODType { enum { Value = true }; }; /// /// Describes hierarchical bones in a flattened array. /// /// /// Bones are ordered so that parents always come first, allowing for hierarchical updates in a simple loop. /// class SkeletonData { public: /// /// The nodes in this hierarchy. The root node is always at the index 0. /// Array Nodes; /// /// The bones in this hierarchy. /// Array Bones; public: /// /// Gets the root node reference. /// /// The root node. FORCE_INLINE SkeletonNode& RootNode() { ASSERT(Nodes.HasItems()); return Nodes[0]; } /// /// Gets the root node reference. /// /// The root node. FORCE_INLINE const SkeletonNode& RootNode() const { ASSERT(Nodes.HasItems()); return Nodes[0]; } /// /// Swaps the contents of object with the other object without copy operation. Performs fast internal data exchange. /// /// The other object. void Swap(SkeletonData& other) { Nodes.Swap(other.Nodes); Bones.Swap(other.Bones); } int32 FindNode(const StringView& name) { for (int32 i = 0; i < Nodes.Count(); i++) { if (Nodes[i].Name == name) return i; } return -1; } int32 FindBone(int32 nodeIndex) { for (int32 i = 0; i < Bones.Count(); i++) { if (Bones[i].NodeIndex == nodeIndex) return i; } return -1; } /// /// Releases data. /// void Dispose() { Nodes.Resize(0); Bones.Resize(0); } };