diff --git a/spine-csharp/src/SkeletonClipping.cs b/spine-csharp/src/SkeletonClipping.cs index 7efc7c143..bc2ea4d0b 100644 --- a/spine-csharp/src/SkeletonClipping.cs +++ b/spine-csharp/src/SkeletonClipping.cs @@ -270,7 +270,7 @@ namespace Spine { return clipped; } - static void MakeClockwise (ExposedList polygon) { + public static void MakeClockwise (ExposedList polygon) { float[] vertices = polygon.Items; int verticeslength = polygon.Count; diff --git a/spine-csharp/src/Triangulator.cs b/spine-csharp/src/Triangulator.cs index c4bdb0418..ad9f39ee2 100644 --- a/spine-csharp/src/Triangulator.cs +++ b/spine-csharp/src/Triangulator.cs @@ -31,7 +31,7 @@ using System; namespace Spine { - internal class Triangulator { + public class Triangulator { private readonly ExposedList> convexPolygons = new ExposedList>(); private readonly ExposedList> convexPolygonsIndices = new ExposedList>(); diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java index 3100fa51b..6f19ace48 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java @@ -175,6 +175,8 @@ public class SkeletonBinary { if (skeletonData.hash.isEmpty()) skeletonData.hash = null; skeletonData.version = input.readString(); if (skeletonData.version.isEmpty()) skeletonData.version = null; + skeletonData.x = input.readFloat(); + skeletonData.y = input.readFloat(); skeletonData.width = input.readFloat(); skeletonData.height = input.readFloat(); diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java index bfee2464c..2a800d747 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java @@ -47,7 +47,7 @@ public class SkeletonData { final Array ikConstraints = new Array(); final Array transformConstraints = new Array(); final Array pathConstraints = new Array(); - float width, height; + float x, y, width, height; String version, hash; // Nonessential. @@ -234,6 +234,24 @@ public class SkeletonData { this.name = name; } + /** The X coordinate of the skeleton's axis aligned bounding box in the setup pose. */ + public float getX () { + return x; + } + + public void setX (float x) { + this.x = x; + } + + /** The Y coordinate of the skeleton's axis aligned bounding box in the setup pose. */ + public float getY () { + return y; + } + + public void setY (float y) { + this.y = y; + } + /** The width of the skeleton's axis aligned bounding box in the setup pose. */ public float getWidth () { return width; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java index f707cfa19..10fa289b4 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java @@ -122,6 +122,8 @@ public class SkeletonJson { if (skeletonMap != null) { skeletonData.hash = skeletonMap.getString("hash", null); skeletonData.version = skeletonMap.getString("spine", null); + skeletonData.x = skeletonMap.getFloat("x", 0); + skeletonData.y = skeletonMap.getFloat("y", 0); skeletonData.width = skeletonMap.getFloat("width", 0); skeletonData.height = skeletonMap.getFloat("height", 0); skeletonData.fps = skeletonMap.getFloat("fps", 30); diff --git a/spine-monogame/example/ExampleGame.cs b/spine-monogame/example/ExampleGame.cs index ced2ede1e..f9251046d 100644 --- a/spine-monogame/example/ExampleGame.cs +++ b/spine-monogame/example/ExampleGame.cs @@ -65,9 +65,9 @@ namespace Spine { // String name = "spineboy-ess"; // String name = "goblins-pro"; - // String name = "raptor-pro"; + String name = "raptor-pro"; // String name = "tank-pro"; - String name = "coin-pro"; + // String name = "coin-pro"; String atlasName = name.Replace("-pro", "").Replace("-ess", ""); bool binaryData = false; @@ -109,17 +109,17 @@ namespace Spine { state.Complete += Complete; state.Event += Event; - state.SetAnimation(0, "test", false); + state.SetAnimation(0, "run", false); TrackEntry entry = state.AddAnimation(0, "jump", false, 0); entry.End += End; // Event handling for queued animations. state.AddAnimation(0, "run", true, 0); } else if (name == "raptor-pro") { state.SetAnimation(0, "walk", true); - state.AddAnimation(1, "gungrab", false, 2); + state.AddAnimation(1, "gun-grab", false, 2); } else if (name == "coin-pro") { - state.SetAnimation(0, "rotate", true); + state.SetAnimation(0, "animation", true); } else if (name == "tank-pro") { state.SetAnimation(0, "drive", true); @@ -127,9 +127,10 @@ namespace Spine { else { state.SetAnimation(0, "walk", true); } - + skeleton.X = 400 + (name == "tank-pro" ? 300 : 0); skeleton.Y = GraphicsDevice.Viewport.Height; + skeleton.ScaleY = -1; skeleton.UpdateWorldTransform(); headSlot = skeleton.FindSlot("head"); diff --git a/spine-monogame/example/spine-monogame-example.csproj b/spine-monogame/example/spine-monogame-example.csproj index 5638d957d..bb44f0321 100644 --- a/spine-monogame/example/spine-monogame-example.csproj +++ b/spine-monogame/example/spine-monogame-example.csproj @@ -42,6 +42,15 @@ app.manifest + + spine-xna\ShapeRenderer.cs + + + spine-xna\SkeletonDebugRenderer.cs + + + spine-xna\VertexEffect.cs + spine-xna\MeshBatcher.cs diff --git a/spine-ue4/Config/DefaultEngine.ini b/spine-ue4/Config/DefaultEngine.ini index 380efca92..6c63e6306 100644 --- a/spine-ue4/Config/DefaultEngine.ini +++ b/spine-ue4/Config/DefaultEngine.ini @@ -7,9 +7,15 @@ DefaultGraphicsPerformance=Maximum AppliedDefaultGraphicsPerformance=Maximum [/Script/EngineSettings.GameMapsSettings] -GameDefaultMap=/Game/Test/Test.Test +GameDefaultMap=/Game/Test/NewWorld.NewWorld GlobalDefaultGameMode=/Game/Test/Blueprints/TouchClick.TouchClick_C +[/Script/IOSRuntimeSettings.IOSRuntimeSettings] +bSupportsPortraitOrientation=False +bSupportsUpsideDownOrientation=False +bSupportsLandscapeLeftOrientation=True +PreferredLandscapeOrientation=LandscapeLeft + [/Script/Engine.PhysicsSettings] DefaultGravityZ=-980.000000 DefaultTerminalVelocity=4000.000000 @@ -17,12 +23,12 @@ DefaultFluidFriction=0.300000 SimulateScratchMemorySize=262144 RagdollAggregateThreshold=4 TriangleMeshTriangleMinAreaThreshold=5.000000 -bEnableAsyncScene=False bEnableShapeSharing=False bEnablePCM=True bEnableStabilization=False bWarnMissingLocks=True bEnable2DPhysics=False +PhysicErrorCorrection=(PingExtrapolation=0.100000,PingLimit=100.000000,ErrorPerLinearDifference=1.000000,ErrorPerAngularDifference=1.000000,MaxRestoredStateError=1.000000,MaxLinearHardSnapDistance=400.000000,PositionLerp=0.000000,AngleLerp=0.400000,LinearVelocityCoefficient=100.000000,AngularVelocityCoefficient=10.000000,ErrorAccumulationSeconds=0.500000,ErrorAccumulationDistanceSq=15.000000,ErrorAccumulationSimilarity=100.000000) LockedAxis=Invalid DefaultDegreesOfFreedom=Full3D BounceThresholdVelocity=200.000000 @@ -39,6 +45,8 @@ bDefaultHasComplexCollision=True bSuppressFaceRemapTable=False bSupportUVFromHitResults=False bDisableActiveActors=False +bDisableKinematicStaticPairs=False +bDisableKinematicKinematicPairs=False bDisableCCD=False bEnableEnhancedDeterminism=False MaxPhysicsDeltaTime=0.033333 @@ -47,16 +55,7 @@ bSubsteppingAsync=False MaxSubstepDeltaTime=0.016667 MaxSubsteps=6 SyncSceneSmoothingFactor=0.000000 -AsyncSceneSmoothingFactor=0.990000 InitialAverageFrameRate=0.016667 PhysXTreeRebuildRate=10 - - - - -[/Script/IOSRuntimeSettings.IOSRuntimeSettings] -bSupportsPortraitOrientation=False -bSupportsUpsideDownOrientation=False -bSupportsLandscapeLeftOrientation=True -PreferredLandscapeOrientation=LandscapeLeft +DefaultBroadphaseSettings=(bUseMBPOnClient=False,bUseMBPOnServer=False,MBPBounds=(Min=(X=0.000000,Y=0.000000,Z=0.000000),Max=(X=0.000000,Y=0.000000,Z=0.000000),IsValid=0),MBPNumSubdivs=2) diff --git a/spine-ue4/Content/Test/NewWorld.umap b/spine-ue4/Content/Test/NewWorld.umap index ba5b861ae..051798ef7 100644 Binary files a/spine-ue4/Content/Test/NewWorld.umap and b/spine-ue4/Content/Test/NewWorld.umap differ diff --git a/spine-ue4/Content/Test/raptor-widget.uasset b/spine-ue4/Content/Test/raptor-widget.uasset new file mode 100644 index 000000000..ff4214a3f Binary files /dev/null and b/spine-ue4/Content/Test/raptor-widget.uasset differ diff --git a/spine-ue4/Content/Test/widget.uasset b/spine-ue4/Content/Test/widget.uasset deleted file mode 100644 index 14d1131a8..000000000 Binary files a/spine-ue4/Content/Test/widget.uasset and /dev/null differ diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpineEditorPlugin/Private/SpineEditorPlugin.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpineEditorPlugin/Private/SpineEditorPlugin.cpp index 3b0fbcf5d..640ebb3c3 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpineEditorPlugin/Private/SpineEditorPlugin.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpineEditorPlugin/Private/SpineEditorPlugin.cpp @@ -37,7 +37,7 @@ class FSpineEditorPlugin: public ISpineEditorPlugin { virtual void ShutdownModule() override; }; -IMPLEMENT_MODULE(FSpineEditorPlugin, ISpineEditorPlugin) +IMPLEMENT_MODULE(FSpineEditorPlugin, SpineEditorPlugin) void FSpineEditorPlugin::StartupModule () { } diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SSpineWidget.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SSpineWidget.cpp index 3ddd69342..5ab6b4923 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SSpineWidget.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SSpineWidget.cpp @@ -51,6 +51,13 @@ void SSpineWidget::Construct(const FArguments& args) { void SSpineWidget::SetData(USpineWidget* Widget) { this->widget = Widget; + if (widget && widget->skeleton && widget->Atlas) { + Skeleton *skeleton = widget->skeleton; + skeleton->setToSetupPose(); + skeleton->updateWorldTransform(); + Vector scratchBuffer; + skeleton->getBounds(this->boundsMin.X, this->boundsMin.Y, this->boundsSize.X, this->boundsSize.Y, scratchBuffer); + } } static void setVertex(FSlateVertex* vertex, float x, float y, float u, float v, const FColor& color, const FVector2D& offset) { @@ -163,6 +170,12 @@ int32 SSpineWidget::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeo void SSpineWidget::Flush(int32 LayerId, FSlateWindowElementList& OutDrawElements, const FGeometry& AllottedGeometry, int &Idx, TArray &Vertices, TArray &Indices, TArray &Uvs, TArray &Colors, TArray& Colors2, UMaterialInstanceDynamic* Material) { if (Vertices.Num() == 0) return; SSpineWidget* self = (SSpineWidget*)this; + + const FVector2D widgetSize = AllottedGeometry.GetDrawSize(); + const float setupScale = (widgetSize / FVector2D(boundsSize.X, boundsSize.Y)).GetMin(); + for (int i = 0; i < Vertices.Num(); i++) { + Vertices[i] = (Vertices[i] - FVector(boundsMin.X, -(boundsMin.Y + boundsSize.Y), 0)) * setupScale * widget->Scale; + } self->renderData.IndexData.SetNumUninitialized(Indices.Num()); uint32* indexData = (uint32*)renderData.IndexData.GetData(); @@ -293,18 +306,6 @@ void SSpineWidget::UpdateMesh(int32 LayerId, FSlateWindowElementList& OutDrawEle } if (lastMaterial != material) { - FBox VerticeBounds = FBox(); - for (int i = 0; i < vertices.Num(); i++) { - VerticeBounds += vertices[i]; - } - const FVector2D DrawSize = AllottedGeometry.GetDrawSize(); - const FVector BoundMin = VerticeBounds.Min; - const FVector BoundSize = VerticeBounds.GetSize(); - const float Scale = (DrawSize / FVector2D(BoundSize.X, BoundSize.Y)).GetMin(); - - for (int i = 0; i < vertices.Num(); i++) { - vertices[i] = (vertices[i] - BoundMin) * Scale; - } Flush(LayerId, OutDrawElements, AllottedGeometry, meshSection, vertices, indices, uvs, colors, darkColors, lastMaterial); lastMaterial = material; idx = 0; @@ -335,22 +336,7 @@ void SSpineWidget::UpdateMesh(int32 LayerId, FSlateWindowElementList& OutDrawEle clipper.clipEnd(*slot); } - - FBox VerticeBounds = FBox(); - for (int i = 0; i < vertices.Num(); i++) - { - VerticeBounds += vertices[i]; - } - const FVector2D DrawSize = AllottedGeometry.GetDrawSize(); - const FVector BoundMin = VerticeBounds.Min; - const FVector BoundSize = VerticeBounds.GetSize(); - const float Scale = (DrawSize / FVector2D(BoundSize.X, BoundSize.Y)).GetMin(); - - for (int i = 0; i < vertices.Num(); i++) - { - vertices[i] = (vertices[i] - BoundMin)*Scale; - } - + Flush(LayerId, OutDrawElements, AllottedGeometry, meshSection, vertices, indices, uvs, colors, darkColors, lastMaterial); clipper.clipEnd(); } \ No newline at end of file diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineWidget.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineWidget.cpp index a7abb9865..94d1a824f 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineWidget.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineWidget.cpp @@ -38,7 +38,41 @@ using namespace spine; -void callback(AnimationState* state, spine::EventType type, TrackEntry* entry, Event* event); +void callbackWidget(AnimationState* state, spine::EventType type, TrackEntry* entry, Event* event) { + USpineWidget* component = (USpineWidget*)state->getRendererObject(); + + if (entry->getRendererObject()) { + UTrackEntry* uEntry = (UTrackEntry*)entry->getRendererObject(); + if (type == EventType_Start) { + component->AnimationStart.Broadcast(uEntry); + uEntry->AnimationStart.Broadcast(uEntry); + } + else if (type == EventType_Interrupt) { + component->AnimationInterrupt.Broadcast(uEntry); + uEntry->AnimationInterrupt.Broadcast(uEntry); + } + else if (type == EventType_Event) { + FSpineEvent evt; + evt.SetEvent(event); + component->AnimationEvent.Broadcast(uEntry, evt); + uEntry->AnimationEvent.Broadcast(uEntry, evt); + } + else if (type == EventType_Complete) { + component->AnimationComplete.Broadcast(uEntry); + uEntry->AnimationComplete.Broadcast(uEntry); + } + else if (type == EventType_End) { + component->AnimationEnd.Broadcast(uEntry); + uEntry->AnimationEnd.Broadcast(uEntry); + } + else if (type == EventType_Dispose) { + component->AnimationDispose.Broadcast(uEntry); + uEntry->AnimationDispose.Broadcast(uEntry); + uEntry->SetTrackEntry(nullptr); + component->GCTrackEntry(uEntry); + } + } +} USpineWidget::USpineWidget(const FObjectInitializer& ObjectInitializer): Super(ObjectInitializer) { static ConstructorHelpers::FObjectFinder NormalMaterialRef(TEXT("/SpinePlugin/UI_SpineUnlitNormalMaterial")); @@ -130,7 +164,7 @@ void USpineWidget::CheckState() { AnimationStateData* stateData = SkeletonData->GetAnimationStateData(Atlas->GetAtlas()); state = new (__FILE__, __LINE__) AnimationState(stateData); state->setRendererObject((void*)this); - state->setListener(callback); + state->setListener(callbackWidget); trackEntries.Empty(); } } @@ -355,7 +389,8 @@ UTrackEntry* USpineWidget::SetAnimation(int trackIndex, FString animationName, b trackEntries.Add(uEntry); return uEntry; } - else return NewObject(); + else + return NewObject(); } @@ -370,7 +405,8 @@ UTrackEntry* USpineWidget::AddAnimation(int trackIndex, FString animationName, b trackEntries.Add(uEntry); return uEntry; } - else return NewObject(); + else + return NewObject(); } UTrackEntry* USpineWidget::SetEmptyAnimation(int trackIndex, float mixDuration) { @@ -382,7 +418,8 @@ UTrackEntry* USpineWidget::SetEmptyAnimation(int trackIndex, float mixDuration) trackEntries.Add(uEntry); return uEntry; } - else return NewObject(); + else + return NewObject(); } UTrackEntry* USpineWidget::AddEmptyAnimation(int trackIndex, float mixDuration, float delay) { @@ -394,7 +431,8 @@ UTrackEntry* USpineWidget::AddEmptyAnimation(int trackIndex, float mixDuration, trackEntries.Add(uEntry); return uEntry; } - else return NewObject(); + else + return NewObject(); } UTrackEntry* USpineWidget::GetCurrent(int trackIndex) { @@ -411,7 +449,8 @@ UTrackEntry* USpineWidget::GetCurrent(int trackIndex) { return uEntry; } } - else return NewObject(); + else + return NewObject(); } void USpineWidget::ClearTracks() { diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SSpineWidget.h b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SSpineWidget.h index 5c04c9be1..13c09e7ab 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SSpineWidget.h +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SSpineWidget.h @@ -55,7 +55,8 @@ protected: void Flush(int32 LayerId, FSlateWindowElementList& OutDrawElements, const FGeometry& AllottedGeometry, int &Idx, TArray &Vertices, TArray &Indices, TArray &Uvs, TArray &Colors, TArray &Colors2, UMaterialInstanceDynamic* Material); - USpineWidget* widget; - + USpineWidget* widget; FRenderData renderData; + FVector boundsMin; + FVector boundsSize; }; diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineWidget.h b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineWidget.h index 96f39c8df..12b4c6c85 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineWidget.h +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineWidget.h @@ -52,6 +52,8 @@ public: #if WITH_EDITOR virtual const FText GetPaletteCategory() override; #endif + UPROPERTY(Category = Spine, EditAnywhere, BlueprintReadWrite) + float Scale = 1; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Spine) USpineAtlasAsset* Atlas; diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/SpinePlugin.Build.cs b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/SpinePlugin.Build.cs index cb9a760b6..d2037221d 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/SpinePlugin.Build.cs +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/SpinePlugin.Build.cs @@ -15,7 +15,7 @@ namespace UnrealBuildTool.Rules PrivateIncludePaths.Add(Path.Combine(ModuleDirectory, "Private")); PrivateIncludePaths.Add(Path.Combine(ModuleDirectory, "Public/spine-cpp/include")); - PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "RHI", "RenderCore", "ShaderCore", "ProceduralMeshComponent", "UMG", "Slate", "SlateCore" }); + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "ProceduralMeshComponent", "UMG", "Slate", "SlateCore" }); PublicDefinitions.Add("SPINE_UE4"); } } diff --git a/spine-ue4/SpineUE4.uproject b/spine-ue4/SpineUE4.uproject index 85dca7bbd..8830daf34 100644 --- a/spine-ue4/SpineUE4.uproject +++ b/spine-ue4/SpineUE4.uproject @@ -1,6 +1,6 @@ { "FileVersion": 3, - "EngineAssociation": "4.21", + "EngineAssociation": "4.22", "Category": "", "Description": "", "Modules": [ diff --git a/spine-xna/example/data/goblins-mesh.atlas b/spine-xna/example/data/goblins.atlas similarity index 100% rename from spine-xna/example/data/goblins-mesh.atlas rename to spine-xna/example/data/goblins.atlas