diff --git a/spine-ue4/Content/Maps/example.umap b/spine-ue4/Content/Maps/example.umap index 16fd5f484..568164501 100644 Binary files a/spine-ue4/Content/Maps/example.umap and b/spine-ue4/Content/Maps/example.umap differ diff --git a/spine-ue4/Content/SpineBoy/SpineboyBlueprint.uasset b/spine-ue4/Content/SpineBoy/SpineboyBlueprint.uasset index fc09d402f..c6d6436ca 100644 Binary files a/spine-ue4/Content/SpineBoy/SpineboyBlueprint.uasset and b/spine-ue4/Content/SpineBoy/SpineboyBlueprint.uasset differ diff --git a/spine-ue4/Content/SpineBoy/spineboy.uasset b/spine-ue4/Content/SpineBoy/spineboy.uasset index b4d85df43..9f7dec5ce 100644 Binary files a/spine-ue4/Content/SpineBoy/spineboy.uasset and b/spine-ue4/Content/SpineBoy/spineboy.uasset differ diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonAnimationComponent.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonAnimationComponent.cpp index a850bb707..c0e705f45 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonAnimationComponent.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonAnimationComponent.cpp @@ -4,7 +4,7 @@ void UTrackEntry::SetTrackEntry(spTrackEntry* entry) { this->entry = entry; - entry->rendererObject = (void*)this; + if (entry) entry->rendererObject = (void*)this; } void callback(spAnimationState* state, spEventType type, spTrackEntry* entry, spEvent* event) { @@ -73,7 +73,7 @@ void USpineSkeletonAnimationComponent::CheckState () { if (Atlas && SkeletonData) { spSkeletonData* data = SkeletonData->GetSkeletonData(Atlas->GetAtlas(false), false); skeleton = spSkeleton_create(data); - stateData = spAnimationStateData_create(data); + spAnimationStateData* stateData = SkeletonData->GetAnimationStateData(Atlas->GetAtlas(false)); state = spAnimationState_create(stateData); state->rendererObject = (void*)this; state->listener = callback; @@ -85,12 +85,7 @@ void USpineSkeletonAnimationComponent::CheckState () { } } -void USpineSkeletonAnimationComponent::DisposeState () { - if (stateData) { - spAnimationStateData_dispose(stateData); - stateData = nullptr; - } - +void USpineSkeletonAnimationComponent::DisposeState () { if (state) { spAnimationState_dispose(state); state = nullptr; diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp index 51c59f375..fc5e7e41b 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp @@ -54,6 +54,10 @@ void USpineSkeletonDataAsset::BeginDestroy () { spSkeletonData_dispose(this->skeletonData); this->skeletonData = nullptr; } + if (this->animationStateData) { + spAnimationStateData_dispose(this->animationStateData); + this->animationStateData = nullptr; + } Super::BeginDestroy(); } @@ -62,7 +66,7 @@ spSkeletonData* USpineSkeletonDataAsset::GetSkeletonData (spAtlas* Atlas, bool F if (skeletonData) { spSkeletonData_dispose(skeletonData); skeletonData = nullptr; - } + } int dataLen = rawData.Num(); if (skeletonDataFileName.GetPlainNameString().Contains(TEXT(".json"))) { spSkeletonJson* json = spSkeletonJson_create(Atlas); @@ -73,11 +77,49 @@ spSkeletonData* USpineSkeletonDataAsset::GetSkeletonData (spAtlas* Atlas, bool F this->skeletonData = spSkeletonBinary_readSkeletonData(binary, (const unsigned char*)rawData.GetData(), (int)rawData.Num()); spSkeletonBinary_dispose(binary); } + if (animationStateData) { + spAnimationStateData_dispose(animationStateData); + GetAnimationStateData(Atlas); + } lastAtlas = Atlas; } return this->skeletonData; } +spAnimationStateData* USpineSkeletonDataAsset::GetAnimationStateData(spAtlas* atlas) { + if (!animationStateData) { + spSkeletonData* skeletonData = GetSkeletonData(atlas, false); + animationStateData = spAnimationStateData_create(skeletonData); + } + for (auto& data : MixData) { + if (!data.From.IsEmpty() && !data.To.IsEmpty()) { + const char* fromChar = TCHAR_TO_UTF8(*data.From); + const char* toChar = TCHAR_TO_UTF8(*data.To); + spAnimationStateData_setMixByName(animationStateData, fromChar, toChar, data.Mix); + } + } + animationStateData->defaultMix = DefaultMix; + return this->animationStateData; +} + +void USpineSkeletonDataAsset::SetMix(const FString& from, const FString& to, float mix) { + FSpineAnimationStateMixData data; + data.From = from; + data.To = to; + data.Mix = mix; + this->MixData.Add(data); + if (lastAtlas) { + GetAnimationStateData(lastAtlas); + } +} + +float USpineSkeletonDataAsset::GetMix(const FString& from, const FString& to) { + for (auto& data : MixData) { + if (data.From.Equals(from) && data.To.Equals(to)) return data.Mix; + } + return 0; +} + #endif #undef LOCTEXT_NAMESPACE diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonAnimationComponent.h b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonAnimationComponent.h index 05c1aac2e..83eebd3c8 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonAnimationComponent.h +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonAnimationComponent.h @@ -177,8 +177,6 @@ class SPINEPLUGIN_API USpineSkeletonAnimationComponent: public USpineSkeletonCom GENERATED_BODY() public: - spAnimationStateData* GetAnimationStateData () { return stateData; }; - spAnimationState* GetAnimationState () { return state; }; USpineSkeletonAnimationComponent (); @@ -232,8 +230,7 @@ public: protected: virtual void CheckState () override; virtual void DisposeState () override; - - spAnimationStateData* stateData; + spAnimationState* state; // keep track of track entries so they won't get GCed while diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonDataAsset.h b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonDataAsset.h index c266397ea..b253aae45 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonDataAsset.h +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonDataAsset.h @@ -4,27 +4,53 @@ #include "spine/spine.h" #include "SpineSkeletonDataAsset.generated.h" +USTRUCT(BlueprintType, Category = "Spine") +struct SPINEPLUGIN_API FSpineAnimationStateMixData { + GENERATED_BODY(); + +public: + UPROPERTY(EditAnywhere, BlueprintReadWrite) + FString From; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + FString To; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + float Mix = 0; +}; + UCLASS(ClassGroup=(Spine)) class SPINEPLUGIN_API USpineSkeletonDataAsset: public UObject { GENERATED_BODY() public: spSkeletonData* GetSkeletonData(spAtlas* Atlas, bool ForceReload = false); + + spAnimationStateData* GetAnimationStateData(spAtlas* atlas); + void SetMix(const FString& from, const FString& to, float mix); + float GetMix(const FString& from, const FString& to); FName GetSkeletonDataFileName () const; TArray& GetRawData (); virtual void BeginDestroy () override; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + float DefaultMix = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + TArray MixData; protected: UPROPERTY() - TArray rawData; - - spAtlas* lastAtlas = nullptr; - spSkeletonData* skeletonData = nullptr; + TArray rawData; UPROPERTY() FName skeletonDataFileName; + + spSkeletonData* skeletonData; + spAnimationStateData* animationStateData; + spAtlas* lastAtlas; #if WITH_EDITORONLY_DATA public: