[ue] Update to new C++ API, WIP

This commit is contained in:
Mario Zechner 2025-09-09 16:07:05 +02:00
parent cf12e9cc19
commit 6f1a3198bb
11 changed files with 75 additions and 64 deletions

View File

@ -131,7 +131,7 @@ void USpineAtlasAssetFactory::LoadAtlas(USpineAtlasAsset *Asset, const FString &
const FString targetTexturePath = LongPackagePath / TEXT("Textures");
Vector<AtlasPage *> &pages = atlas->getPages();
Array<AtlasPage *> &pages = atlas->getPages();
for (size_t i = 0, n = pages.size(); i < n; i++) {
AtlasPage *page = pages[i];
const FString sourceTextureFilename = FPaths::Combine(*CurrentSourcePath, UTF8_TO_TCHAR(page->name.buffer()));

View File

@ -40,7 +40,7 @@ void UTrackEntry::SetTrackEntry(TrackEntry *trackEntry) {
if (entry) entry->setRendererObject((void *) this);
}
void callback(AnimationState *state, spine::EventType type, TrackEntry *entry, Event *event) {
void callback(AnimationState *state, spine::EventType type, TrackEntry *entry, Event *event, void* userData) {
USpineSkeletonAnimationComponent *component = (USpineSkeletonAnimationComponent *) state->getRendererObject();
if (entry->getRendererObject()) {
@ -140,7 +140,7 @@ void USpineSkeletonAnimationComponent::CheckState() {
if (lastSpineAtlas != atlas) {
needsUpdate = true;
}
if (skeleton && skeleton->getData() != SkeletonData->GetSkeletonData(atlas)) {
if (skeleton && &skeleton->getData() != SkeletonData->GetSkeletonData(atlas)) {
needsUpdate = true;
}
}
@ -152,9 +152,9 @@ void USpineSkeletonAnimationComponent::CheckState() {
if (Atlas && SkeletonData) {
spine::SkeletonData *data = SkeletonData->GetSkeletonData(Atlas->GetAtlas());
if (data) {
skeleton = new (__FILE__, __LINE__) Skeleton(data);
skeleton = new (__FILE__, __LINE__) Skeleton(*data);
AnimationStateData *stateData = SkeletonData->GetAnimationStateData(Atlas->GetAtlas());
state = new (__FILE__, __LINE__) AnimationState(stateData);
state = new (__FILE__, __LINE__) AnimationState(*stateData);
state->setRendererObject((void *) this);
state->setListener(callback);
trackEntries.Empty();
@ -194,9 +194,9 @@ void USpineSkeletonAnimationComponent::SetPlaybackTime(float InPlaybackTime, boo
CheckState();
if (state && state->getCurrent(0)) {
spine::Animation *CurrentAnimation = state->getCurrent(0)->getAnimation();
spine::Animation &CurrentAnimation = state->getCurrent(0)->getAnimation();
const float CurrentTime = state->getCurrent(0)->getTrackTime();
InPlaybackTime = FMath::Clamp(InPlaybackTime, 0.0f, CurrentAnimation->getDuration());
InPlaybackTime = FMath::Clamp(InPlaybackTime, 0.0f, CurrentAnimation.getDuration());
const float DeltaTime = InPlaybackTime - CurrentTime;
state->update(DeltaTime);
state->apply(*skeleton);
@ -225,12 +225,12 @@ float USpineSkeletonAnimationComponent::GetTimeScale() {
UTrackEntry *USpineSkeletonAnimationComponent::SetAnimation(int trackIndex, FString animationName, bool loop) {
CheckState();
if (state && skeleton->getData()->findAnimation(TCHAR_TO_UTF8(*animationName))) {
if (state && skeleton->getData().findAnimation(TCHAR_TO_UTF8(*animationName))) {
state->disableQueue();
TrackEntry *entry = state->setAnimation(trackIndex, TCHAR_TO_UTF8(*animationName), loop);
TrackEntry &entry = &state->setAnimation(trackIndex, TCHAR_TO_UTF8(*animationName), loop);
state->enableQueue();
UTrackEntry *uEntry = NewObject<UTrackEntry>();
uEntry->SetTrackEntry(entry);
uEntry->SetTrackEntry(&entry);
trackEntries.Add(uEntry);
return uEntry;
} else
@ -241,10 +241,10 @@ UTrackEntry *USpineSkeletonAnimationComponent::AddAnimation(int trackIndex, FStr
CheckState();
if (state && skeleton->getData()->findAnimation(TCHAR_TO_UTF8(*animationName))) {
state->disableQueue();
TrackEntry *entry = state->addAnimation(trackIndex, TCHAR_TO_UTF8(*animationName), loop, delay);
TrackEntry &entry = state->addAnimation(trackIndex, TCHAR_TO_UTF8(*animationName), loop, delay);
state->enableQueue();
UTrackEntry *uEntry = NewObject<UTrackEntry>();
uEntry->SetTrackEntry(entry);
uEntry->SetTrackEntry(&entry);
trackEntries.Add(uEntry);
return uEntry;
} else
@ -254,9 +254,9 @@ UTrackEntry *USpineSkeletonAnimationComponent::AddAnimation(int trackIndex, FStr
UTrackEntry *USpineSkeletonAnimationComponent::SetEmptyAnimation(int trackIndex, float mixDuration) {
CheckState();
if (state) {
TrackEntry *entry = state->setEmptyAnimation(trackIndex, mixDuration);
TrackEntry &entry = state->setEmptyAnimation(trackIndex, mixDuration);
UTrackEntry *uEntry = NewObject<UTrackEntry>();
uEntry->SetTrackEntry(entry);
uEntry->SetTrackEntry(&entry);
trackEntries.Add(uEntry);
return uEntry;
} else
@ -266,7 +266,7 @@ UTrackEntry *USpineSkeletonAnimationComponent::SetEmptyAnimation(int trackIndex,
UTrackEntry *USpineSkeletonAnimationComponent::AddEmptyAnimation(int trackIndex, float mixDuration, float delay) {
CheckState();
if (state) {
TrackEntry *entry = state->addEmptyAnimation(trackIndex, mixDuration, delay);
TrackEntry &entry = state->addEmptyAnimation(trackIndex, mixDuration, delay);
UTrackEntry *uEntry = NewObject<UTrackEntry>();
uEntry->SetTrackEntry(entry);
trackEntries.Add(uEntry);

View File

@ -48,12 +48,12 @@ bool USpineSkeletonComponent::SetSkins(UPARAM(ref) TArray<FString> &SkinNames) {
if (skeleton) {
spine::Skin *newSkin = new spine::Skin("__spine-ue3_custom_skin");
for (auto &skinName : SkinNames) {
spine::Skin *skin = skeleton->getData()->findSkin(TCHAR_TO_UTF8(*skinName));
spine::Skin *skin = skeleton->getData().findSkin(TCHAR_TO_UTF8(*skinName));
if (!skin) {
delete newSkin;
return false;
}
newSkin->addSkin(skin);
newSkin->addSkin(*skin);
}
skeleton->setSkin(newSkin);
if (customSkin != nullptr) {
@ -68,7 +68,7 @@ bool USpineSkeletonComponent::SetSkins(UPARAM(ref) TArray<FString> &SkinNames) {
bool USpineSkeletonComponent::SetSkin(const FString skinName) {
CheckState();
if (skeleton) {
Skin *skin = skeleton->getData()->findSkin(TCHAR_TO_UTF8(*skinName));
Skin *skin = skeleton->getData().findSkin(TCHAR_TO_UTF8(*skinName));
if (!skin) return false;
skeleton->setSkin(skin);
return true;
@ -79,8 +79,8 @@ bool USpineSkeletonComponent::SetSkin(const FString skinName) {
void USpineSkeletonComponent::GetSkins(TArray<FString> &Skins) {
CheckState();
if (skeleton) {
for (size_t i = 0, n = skeleton->getData()->getSkins().size(); i < n; i++) {
Skins.Add(skeleton->getData()->getSkins()[i]->getName().buffer());
for (size_t i = 0, n = skeleton->getData().getSkins().size(); i < n; i++) {
Skins.Add(skeleton->getData().getSkins()[i]->getName().buffer());
}
}
}
@ -88,7 +88,7 @@ void USpineSkeletonComponent::GetSkins(TArray<FString> &Skins) {
bool USpineSkeletonComponent::HasSkin(const FString skinName) {
CheckState();
if (skeleton) {
return skeleton->getData()->findSkin(TCHAR_TO_UTF8(*skinName)) != nullptr;
return skeleton->getData().findSkin(TCHAR_TO_UTF8(*skinName)) != nullptr;
}
return false;
}
@ -127,12 +127,12 @@ FTransform USpineSkeletonComponent::GetBoneWorldTransform(const FString &BoneNam
baseTransform = owner->GetActorTransform();
}
FVector position(bone->getWorldX(), 0, bone->getWorldY());
FVector position(bone->getAppliedPose().getWorldX(), 0, bone->getAppliedPose().getWorldY());
FMatrix localTransform;
localTransform.SetIdentity();
localTransform.SetAxis(2, FVector(bone->getA(), 0, bone->getC()));
localTransform.SetAxis(0, FVector(bone->getB(), 0, bone->getD()));
localTransform.SetOrigin(FVector(bone->getWorldX(), 0, bone->getWorldY()));
localTransform.SetAxis(2, FVector(bone->getAppliedPose().getA(), 0, bone->getAppliedPose().getC()));
localTransform.SetAxis(0, FVector(bone->getAppliedPose().getB(), 0, bone->getAppliedPose().getD()));
localTransform.SetOrigin(FVector(bone->getAppliedPose().getWorldX(), 0, bone->getAppliedPose().getWorldY()));
localTransform = localTransform * baseTransform.ToMatrixWithScale();
FTransform result;
@ -166,12 +166,12 @@ void USpineSkeletonComponent::SetBoneWorldPosition(const FString &BoneName, cons
FVector localPosition = baseTransform.TransformPosition(position);
float localX = 0, localY = 0;
if (bone->getParent()) {
bone->getParent()->worldToLocal(localPosition.X, localPosition.Z, localX, localY);
bone->getParent()->getAppliedPose().worldToLocal(localPosition.X, localPosition.Z, localX, localY);
} else {
bone->worldToLocal(localPosition.X, localPosition.Z, localX, localY);
bone->getAppliedPose().worldToLocal(localPosition.X, localPosition.Z, localX, localY);
}
bone->setX(localX);
bone->setY(localY);
bone->getAppliedPose().setX(localX);
bone->getAppliedPose().setY(localY);
}
}
@ -182,19 +182,19 @@ void USpineSkeletonComponent::UpdateWorldTransform() {
}
}
void USpineSkeletonComponent::SetToSetupPose() {
void USpineSkeletonComponent::SetupPose() {
CheckState();
if (skeleton) skeleton->setToSetupPose();
if (skeleton) skeleton->setupPose();
}
void USpineSkeletonComponent::SetBonesToSetupPose() {
void USpineSkeletonComponent::SetupPoseBones() {
CheckState();
if (skeleton) skeleton->setBonesToSetupPose();
if (skeleton) skeleton->setupPoseBones();
}
void USpineSkeletonComponent::SetSlotsToSetupPose() {
void USpineSkeletonComponent::SetupPoseSlots() {
CheckState();
if (skeleton) skeleton->setSlotsToSetupPose();
if (skeleton) skeleton->SetupPoseSlots();
}
void USpineSkeletonComponent::SetScaleX(float scaleX) {
@ -266,8 +266,8 @@ void USpineSkeletonComponent::SetSlotColor(const FString SlotName, const FColor
void USpineSkeletonComponent::GetAnimations(TArray<FString> &Animations) {
CheckState();
if (skeleton) {
for (size_t i = 0, n = skeleton->getData()->getAnimations().size(); i < n; i++) {
Animations.Add(skeleton->getData()->getAnimations()[i]->getName().buffer());
for (size_t i = 0, n = skeleton->getData().getAnimations().size(); i < n; i++) {
Animations.Add(skeleton->getData().getAnimations()[i]->getName().buffer());
}
}
}
@ -283,7 +283,7 @@ bool USpineSkeletonComponent::HasAnimation(FString AnimationName) {
float USpineSkeletonComponent::GetAnimationDuration(FString AnimationName) {
CheckState();
if (skeleton) {
Animation *animation = skeleton->getData()->findAnimation(TCHAR_TO_UTF8(*AnimationName));
Animation *animation = skeleton->getData().findAnimation(TCHAR_TO_UTF8(*AnimationName));
if (animation == nullptr)
return 0;
else

View File

@ -187,7 +187,7 @@ void USpineSkeletonRendererComponent::UpdateMesh(USpineSkeletonComponent *compon
unsigned short quadIndices[] = {0, 1, 2, 0, 2, 3};
for (size_t i = 0; i < Skeleton->getSlots().size(); ++i) {
Vector<float> *attachmentVertices = &worldVertices;
Array<float> *attachmentVertices = &worldVertices;
unsigned short *attachmentIndices = nullptr;
int numVertices;
int numIndices;
@ -197,9 +197,9 @@ void USpineSkeletonRendererComponent::UpdateMesh(USpineSkeletonComponent *compon
float *attachmentUvs = nullptr;
Slot *slot = Skeleton->getDrawOrder()[i];
Attachment *attachment = slot->getAttachment();
Attachment *attachment = slot->getPose().getAttachment();
if (slot->getColor().a == 0 || !slot->getBone().isActive()) {
if (slot->getPose().getColor().a == 0 || !slot->getBone().isActive()) {
clipper.clipEnd(*slot);
continue;
}
@ -242,7 +242,7 @@ void USpineSkeletonRendererComponent::UpdateMesh(USpineSkeletonComponent *compon
attachmentColor.set(mesh->getColor());
attachmentVertices->setSize(mesh->getWorldVerticesLength(), 0);
mesh->computeWorldVertices(*slot, 0, mesh->getWorldVerticesLength(), attachmentVertices->buffer(), 0, 2);
mesh->computeWorldVertices(*Skeleton, *slot, 0, mesh->getWorldVerticesLength(), attachmentVertices->buffer(), 0, 2);
attachmentAtlasRegion = (AtlasRegion *) mesh->getRegion();
attachmentIndices = mesh->getTriangles().buffer();
attachmentUvs = mesh->getUVs().buffer();
@ -250,7 +250,7 @@ void USpineSkeletonRendererComponent::UpdateMesh(USpineSkeletonComponent *compon
numIndices = mesh->getTriangles().size();
} else /* clipping */ {
ClippingAttachment *clip = (ClippingAttachment *) attachment;
clipper.clipStart(*slot, clip);
clipper.clipStart(*Skeleton, *slot, clip);
continue;
}
@ -271,7 +271,7 @@ void USpineSkeletonRendererComponent::UpdateMesh(USpineSkeletonComponent *compon
// to the correct skeleton data yet, we won't find any regions.
// ignore regions for which we can't find a material
UMaterialInstanceDynamic *material = nullptr;
int foundPageIndex = (int) (intptr_t) attachmentAtlasRegion->rendererObject;
int foundPageIndex = (int) (intptr_t) attachmentAtlasRegion->getPageIndex();
if (foundPageIndex == -1) {
clipper.clipEnd(*slot);
continue;
@ -316,10 +316,10 @@ void USpineSkeletonRendererComponent::UpdateMesh(USpineSkeletonComponent *compon
SetMaterial(meshSection, material);
uint8 r = static_cast<uint8>(Skeleton->getColor().r * slot->getColor().r * attachmentColor.r * 255);
uint8 g = static_cast<uint8>(Skeleton->getColor().g * slot->getColor().g * attachmentColor.g * 255);
uint8 b = static_cast<uint8>(Skeleton->getColor().b * slot->getColor().b * attachmentColor.b * 255);
uint8 a = static_cast<uint8>(Skeleton->getColor().a * slot->getColor().a * attachmentColor.a * 255);
uint8 r = static_cast<uint8>(Skeleton->getColor().r * slot->getPose().getColor().r * attachmentColor.r * 255);
uint8 g = static_cast<uint8>(Skeleton->getColor().g * slot->getPose().getColor().g * attachmentColor.g * 255);
uint8 b = static_cast<uint8>(Skeleton->getColor().b * slot->getPose().getColor().b * attachmentColor.b * 255);
uint8 a = static_cast<uint8>(Skeleton->getColor().a * slot->getPose().getColor().a * attachmentColor.a * 255);
float *verticesPtr = attachmentVertices->buffer();
for (int j = 0; j < numVertices << 1; j += 2) {

View File

@ -46,11 +46,11 @@ public:
void SetEvent(spine::Event *event) {
Name = FString(UTF8_TO_TCHAR(event->getData().getName().buffer()));
if (!event->getStringValue().isEmpty()) {
StringValue = FString(UTF8_TO_TCHAR(event->getStringValue().buffer()));
if (!event->getString().isEmpty()) {
StringValue = FString(UTF8_TO_TCHAR(event->getString().buffer()));
}
this->IntValue = event->getIntValue();
this->FloatValue = event->getFloatValue();
this->IntValue = event->getInt();
this->FloatValue = event->getFloat();
this->Time = event->getTime();
}
@ -232,12 +232,12 @@ public:
UFUNCTION(BlueprintCallable, Category = "Components|Spine|TrackEntry")
FString getAnimationName() {
return entry ? entry->getAnimation()->getName().buffer() : "";
return entry ? entry->getAnimation().getName().buffer() : "";
}
UFUNCTION(BlueprintCallable, Category = "Components|Spine|TrackEntry")
float getAnimationDuration() {
return entry ? entry->getAnimation()->getDuration() : 0;
return entry ? entry->getAnimation().getDuration() : 0;
}
UFUNCTION(BlueprintCallable, Category = "Components|Spine|TrackEntry")

View File

@ -83,13 +83,13 @@ public:
void UpdateWorldTransform();
UFUNCTION(BlueprintCallable, Category = "Components|Spine|Skeleton")
void SetToSetupPose();
void SetupPose();
UFUNCTION(BlueprintCallable, Category = "Components|Spine|Skeleton")
void SetBonesToSetupPose();
void SetupPoseBones();
UFUNCTION(BlueprintCallable, Category = "Components|Spine|Skeleton")
void SetSlotsToSetupPose();
void SetupPoseSlots();
UFUNCTION(BlueprintCallable, Category = "Components|Spine|Skeleton")
void SetScaleX(float scaleX);

View File

@ -98,7 +98,7 @@ protected:
void Flush(int &Idx, TArray<FVector> &Vertices, TArray<int32> &Indices, TArray<FVector> &Normals, TArray<FVector2D> &Uvs, TArray<FColor> &Colors,
UMaterialInstanceDynamic *Material);
spine::Vector<float> worldVertices;
spine::Array<float> worldVertices;
spine::SkeletonClipping clipper;
UPROPERTY();

View File

@ -273,7 +273,7 @@ protected:
TArray<UMaterialInstanceDynamic *> atlasScreenBlendMaterials;
TMap<spine::AtlasPage *, UMaterialInstanceDynamic *> pageToScreenBlendMaterial;
spine::Vector<float> worldVertices;
spine::Array<float> worldVertices;
spine::SkeletonClipping clipper;
// keep track of track entries so they won't get GCed while

View File

@ -25,7 +25,7 @@ void ASpineboyCppPawn::Tick(float DeltaTime) {
spine::AnimationState *state = animationComponent->GetAnimationState();
spine::TrackEntry *entry = state->getCurrent(0);
if (entry) {
GEngine->AddOnScreenDebugMessage(-1, 0.5f, FColor::Yellow, FString(entry->getAnimation()->getName().buffer()));
GEngine->AddOnScreenDebugMessage(-1, 0.5f, FColor::Yellow, FString(entry->getAnimation().getName().buffer()));
}
}

View File

@ -1,6 +1,8 @@
@echo off
rmdir Plugins\SpinePlugin\Source\SpinePlugin\Public\spine-cpp /s /q
xcopy /E /I ..\spine-cpp\spine-cpp Plugins\SpinePlugin\Source\SpinePlugin\Public\spine-cpp || goto error
mkdir Plugins\SpinePlugin\Source\SpinePlugin\Public\spine-cpp
xcopy /E /I ..\spine-cpp\include Plugins\SpinePlugin\Source\SpinePlugin\Public\spine-cpp\include || goto error
xcopy /E /I ..\spine-cpp\src Plugins\SpinePlugin\Source\SpinePlugin\Public\spine-cpp\src || goto error
goto done
:error

View File

@ -14,12 +14,21 @@ else
log_warn
fi
log_action "Copying updated spine-cpp sources"
if CP_OUTPUT=$(cp -r ../spine-cpp/spine-cpp Plugins/SpinePlugin/Source/SpinePlugin/Public/spine-cpp 2>&1); then
log_action "Creating spine-cpp directory and copying include"
if CP_INCLUDE_OUTPUT=$(mkdir -p Plugins/SpinePlugin/Source/SpinePlugin/Public/spine-cpp && cp -r ../spine-cpp/include Plugins/SpinePlugin/Source/SpinePlugin/Public/spine-cpp/ 2>&1); then
log_ok
else
log_fail
log_error_output "$CP_INCLUDE_OUTPUT"
exit 1
fi
log_action "Copying spine-cpp src directory"
if CP_SRC_OUTPUT=$(cp -r ../spine-cpp/src Plugins/SpinePlugin/Source/SpinePlugin/Public/spine-cpp/ 2>&1); then
log_ok
log_summary "✓ Unreal Engine setup completed successfully"
else
log_fail
log_error_output "$CP_OUTPUT"
log_error_output "$CP_SRC_OUTPUT"
exit 1
fi