// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "MeshDescription.h" #include "BoneWeights.h" namespace Internal { struct FAttributesRefAdapterConst { using FBoneWeight = UE::AnimationCore::FBoneWeight; using ContainerType = const TArrayAttribute; static int32 Num(const ContainerType& InContainer) { return InContainer.Num(); } static FBoneWeight Get(const ContainerType& InContainer, int32 InIndex) { return FBoneWeight::FromInt32(InContainer.GetData()[InIndex]); } template static int32 IndexOf(const ContainerType& InContainer, Predicate InPredicate) { auto ProxyPredicate = [InPredicate](const int32 InV) -> bool { return InPredicate(FBoneWeight::FromInt32(InV)); }; return InContainer.IndexOfByPredicate(ProxyPredicate); } }; struct FAttributesRefAdapter { using FBoneWeight = UE::AnimationCore::FBoneWeight; using ContainerType = TArrayAttribute; static void SetNum(ContainerType& InContainer, int32 InNum) { InContainer.SetNumUninitialized(InNum); } static int32 Num(const ContainerType& InContainer) { return InContainer.Num(); } static FBoneWeight Get(const ContainerType& InContainer, int32 InIndex) { return FBoneWeight::FromInt32(InContainer.GetData()[InIndex]); } static void Set(ContainerType& InContainer, int32 InIndex, FBoneWeight InBoneWeight) { InContainer.GetData()[InIndex] = InBoneWeight.ToInt32(); } static void Add(ContainerType& InContainer, FBoneWeight InBoneWeight) { InContainer.Add(InBoneWeight.ToInt32()); } static void Remove(ContainerType& InContainer, int32 InIndex) { InContainer.RemoveAt(InIndex, 1); } template static void Sort(ContainerType& InContainer, Predicate InPredicate) { auto ProxyPredicate = [InPredicate](const int32 InA, const int32 InB) -> bool { return InPredicate(FBoneWeight::FromInt32(InA), FBoneWeight::FromInt32(InB)); }; InContainer.SortByPredicate(ProxyPredicate); } template static int32 IndexOf(const ContainerType& InContainer, Predicate InPredicate) { auto ProxyPredicate = [InPredicate](const int32 InV) -> bool { return InPredicate(FBoneWeight::FromInt32(InV)); }; return InContainer.IndexOfByPredicate(ProxyPredicate); } }; template class TVertexBoneWeightsBase : public UE::AnimationCore::TBoneWeights { using Super = UE::AnimationCore::TBoneWeights; public: explicit TVertexBoneWeightsBase(const TArrayAttribute InContainer) : Super(Container), Container(InContainer) {} // For compatibility with range-based for loops. class const_iterator { public: const_iterator& operator++() { ++Index; return *this; } bool operator!=(const const_iterator &InOther) const { return Weights != InOther.Weights || Index != InOther.Index; } UE::AnimationCore::FBoneWeight operator*() const { return Weights->Get(Index); } protected: friend class TVertexBoneWeightsBase; const_iterator() = delete; explicit const_iterator(const TVertexBoneWeightsBase *InWeights, int32 InIndex) : Weights(InWeights), Index(InIndex) { check(InWeights); check(InIndex > INDEX_NONE && InIndex <= InWeights->Num()); } const TVertexBoneWeightsBase *Weights = nullptr; int32 Index = INDEX_NONE; }; const_iterator begin() const { return const_iterator(this, 0); } const_iterator end() const { return const_iterator(this, this->Num()); } private: TArrayAttribute Container; }; } // namespace Internal using FVertexBoneWeights = Internal::TVertexBoneWeightsBase; using FVertexBoneWeightsConst = Internal::TVertexBoneWeightsBase; // Merge these two. class FSkinWeightsVertexAttributesRef { public: FSkinWeightsVertexAttributesRef() = default; FSkinWeightsVertexAttributesRef(const FSkinWeightsVertexAttributesRef &) = default; FSkinWeightsVertexAttributesRef(FSkinWeightsVertexAttributesRef &&) noexcept = default; FSkinWeightsVertexAttributesRef& operator=(const FSkinWeightsVertexAttributesRef &InAttributesRef) { AttributesRef = InAttributesRef.AttributesRef; return *this; } FSkinWeightsVertexAttributesRef& operator=(FSkinWeightsVertexAttributesRef &&InAttributesRef) noexcept { AttributesRef = MoveTemp(InAttributesRef.AttributesRef); InAttributesRef.AttributesRef = TVertexAttributesRef>(); return *this; } bool IsValid() const { return AttributesRef.IsValid(); } FVertexBoneWeights Get(const FVertexID InVertexIndex) const { return FVertexBoneWeights(AttributesRef.Get(InVertexIndex)); } void Set(const FVertexID InVertexIndex, const UE::AnimationCore::FBoneWeights &InWeights) { // FBoneWeights guarantees ordering and normalization, so we just copy the raw data. TArrayAttribute Weights = AttributesRef.Get(InVertexIndex); Weights.SetNumUninitialized(InWeights.Num()); for (int32 Index = 0; Index < InWeights.Num(); Index++) { Weights[Index] = InWeights[Index].ToInt32(); } } void Set( const FVertexID InVertexIndex, TArrayView InWeights, const UE::AnimationCore::FBoneWeightsSettings& InSettings = {} ) { // Proxy through FVertexBoneWeights so we get proper sorting and normalization of the weights. FVertexBoneWeights BoneWeights(AttributesRef.Get(InVertexIndex)); BoneWeights.SetBoneWeights(InWeights, InSettings); } protected: friend class FSkeletalMeshAttributes; FSkinWeightsVertexAttributesRef(TVertexAttributesRef> InAttributesRef) : AttributesRef(InAttributesRef) {} private: friend class FSkinWeightsVertexAttributesConstRef; TVertexAttributesRef> AttributesRef; }; class FSkinWeightsVertexAttributesConstRef { public: FSkinWeightsVertexAttributesConstRef() = default; FSkinWeightsVertexAttributesConstRef(const FSkinWeightsVertexAttributesConstRef &) = default; FSkinWeightsVertexAttributesConstRef(FSkinWeightsVertexAttributesConstRef &&) noexcept = default; FSkinWeightsVertexAttributesConstRef& operator=(const FSkinWeightsVertexAttributesConstRef &InAttributesRef) { AttributesConstRef = InAttributesRef.AttributesConstRef; return *this; } FSkinWeightsVertexAttributesConstRef& operator=(FSkinWeightsVertexAttributesConstRef &&InAttributesRef) noexcept { AttributesConstRef = MoveTemp(InAttributesRef.AttributesConstRef); InAttributesRef.AttributesConstRef = TVertexAttributesConstRef>(); return *this; } // Converting constructors from the non-const variant explicit FSkinWeightsVertexAttributesConstRef(const FSkinWeightsVertexAttributesRef &InAttribs) : AttributesConstRef(InAttribs.AttributesRef) {} FSkinWeightsVertexAttributesConstRef& operator=(const FSkinWeightsVertexAttributesRef &InAttribs) { AttributesConstRef = InAttribs.AttributesRef; return *this; } bool IsValid() const { return AttributesConstRef.IsValid(); } FVertexBoneWeightsConst Get(FVertexID InVertexIndex) const { return FVertexBoneWeightsConst(AttributesConstRef.Get(InVertexIndex)); } protected: friend class FSkeletalMeshAttributes; friend class FSkeletalMeshAttributesShared; FSkinWeightsVertexAttributesConstRef(TVertexAttributesRef> InAttributesConstRef) : AttributesConstRef(InAttributesConstRef) {} FSkinWeightsVertexAttributesConstRef(TVertexAttributesRef> InAttributesConstRef) : AttributesConstRef(InAttributesConstRef) {} private: TVertexAttributesConstRef> AttributesConstRef; };