From be834c51458e862eedd9f97adc9ec5c737d3aa66 Mon Sep 17 00:00:00 2001 From: pharan Date: Mon, 2 Jul 2018 16:15:25 +0800 Subject: [PATCH 1/2] [unity] Better nonrenderables repack handling. Fixes : https://github.com/EsotericSoftware/spine-runtimes/issues/1132 --- .../AttachmentTools/AttachmentTools.cs | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/spine-unity/Assets/spine-unity/Modules/AttachmentTools/AttachmentTools.cs b/spine-unity/Assets/spine-unity/Modules/AttachmentTools/AttachmentTools.cs index 7d0b2d0e1..601f06685 100644 --- a/spine-unity/Assets/spine-unity/Modules/AttachmentTools/AttachmentTools.cs +++ b/spine-unity/Assets/spine-unity/Modules/AttachmentTools/AttachmentTools.cs @@ -211,6 +211,8 @@ namespace Spine.Unity.Modules.AttachmentTools { internal const bool UseMipMaps = false; internal const float DefaultScale = 0.01f; + const int NonrenderingRegion = -1; + public static AtlasRegion ToAtlasRegion (this Texture2D t, Material materialPropertySource, float scale = DefaultScale) { return t.ToAtlasRegion(materialPropertySource.shader, scale, materialPropertySource); } @@ -395,7 +397,7 @@ namespace Spine.Unity.Modules.AttachmentTools { /// The List(Attachment) to populate with the newly created Attachment objects. /// /// May be null. If no Material property source is provided, no special - public static void GetRepackedAttachments (List sourceAttachments, List outputAttachments, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, string newAssetName = "Repacked Attachments", bool clearCache = false) { + public static void GetRepackedAttachments (List sourceAttachments, List outputAttachments, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, string newAssetName = "Repacked Attachments", bool clearCache = false, bool useOriginalNonrenderables = true) { if (sourceAttachments == null) throw new System.ArgumentNullException("sourceAttachments"); if (outputAttachments == null) throw new System.ArgumentNullException("outputAttachments"); @@ -411,9 +413,9 @@ namespace Spine.Unity.Modules.AttachmentTools { int newRegionIndex = 0; for (int i = 0, n = sourceAttachments.Count; i < n; i++) { var originalAttachment = sourceAttachments[i]; - var newAttachment = originalAttachment.GetClone(true); - if (IsRenderable(newAttachment)) { - + + if (IsRenderable(originalAttachment)) { + var newAttachment = originalAttachment.GetClone(true); var region = newAttachment.GetRegion(); int existingIndex; if (existingRegions.TryGetValue(region, out existingIndex)) { @@ -427,6 +429,9 @@ namespace Spine.Unity.Modules.AttachmentTools { } outputAttachments[i] = newAttachment; + } else { + outputAttachments[i] = useOriginalNonrenderables ? originalAttachment : originalAttachment.GetClone(true); + regionIndexes.Add(NonrenderingRegion); // Output attachments pairs with regionIndexes list 1:1. Pad with a sentinel if the attachment doesn't have a region. } } @@ -460,7 +465,8 @@ namespace Spine.Unity.Modules.AttachmentTools { // Map the cloned attachments to the repacked atlas. for (int i = 0, n = outputAttachments.Count; i < n; i++) { var a = outputAttachments[i]; - a.SetRegion(repackedRegions[regionIndexes[i]]); + if (IsRenderable(a)) + a.SetRegion(repackedRegions[regionIndexes[i]]); } // Clean up. @@ -474,14 +480,14 @@ namespace Spine.Unity.Modules.AttachmentTools { /// /// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas comprised of all the regions from the original skin. /// No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them. - public static Skin GetRepackedSkin (this Skin o, string newName, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps) { - return GetRepackedSkin(o, newName, materialPropertySource.shader, out outputMaterial, out outputTexture, maxAtlasSize, padding, textureFormat, mipmaps, materialPropertySource); + public static Skin GetRepackedSkin (this Skin o, string newName, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, bool useOriginalNonrenderables = true) { + return GetRepackedSkin(o, newName, materialPropertySource.shader, out outputMaterial, out outputTexture, maxAtlasSize, padding, textureFormat, mipmaps, materialPropertySource, useOriginalNonrenderables); } /// /// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas comprised of all the regions from the original skin. /// No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them. - public static Skin GetRepackedSkin (this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, Material materialPropertySource = null, bool clearCache = false) { + public static Skin GetRepackedSkin (this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, Material materialPropertySource = null, bool clearCache = false, bool useOriginalNonrenderables = true) { if (o == null) throw new System.NullReferenceException("Skin was null"); var skinAttachments = o.Attachments; var newSkin = new Skin(newName); @@ -495,10 +501,13 @@ namespace Spine.Unity.Modules.AttachmentTools { var texturesToPack = new List(); var originalRegions = new List(); int newRegionIndex = 0; - foreach (var kvp in skinAttachments) { - var newAttachment = kvp.Value.GetClone(true); - if (IsRenderable(newAttachment)) { + foreach (var skinEntry in skinAttachments) { + var originalKey = skinEntry.Key; + var originalAttachment = skinEntry.Value; + Attachment newAttachment; + if (IsRenderable(originalAttachment)) { + newAttachment = originalAttachment.GetClone(true); var region = newAttachment.GetRegion(); int existingIndex; if (existingRegions.TryGetValue(region, out existingIndex)) { @@ -512,9 +521,10 @@ namespace Spine.Unity.Modules.AttachmentTools { } repackedAttachments.Add(newAttachment); - } - var key = kvp.Key; - newSkin.AddAttachment(key.slotIndex, key.name, newAttachment); + newSkin.AddAttachment(originalKey.slotIndex, originalKey.name, newAttachment); + } else { + newSkin.AddAttachment(originalKey.slotIndex, originalKey.name, useOriginalNonrenderables ? originalAttachment : originalAttachment.GetClone(true)); + } } // Fill a new texture with the collected attachment textures. @@ -546,7 +556,8 @@ namespace Spine.Unity.Modules.AttachmentTools { // Map the cloned attachments to the repacked atlas. for (int i = 0, n = repackedAttachments.Count; i < n; i++) { var a = repackedAttachments[i]; - a.SetRegion(repackedRegions[regionIndexes[i]]); + if (IsRenderable(a)) + a.SetRegion(repackedRegions[regionIndexes[i]]); } // Clean up. From 71c0887dab46dabdcb5bb2232407862f9863ee27 Mon Sep 17 00:00:00 2001 From: badlogic Date: Tue, 3 Jul 2018 12:14:59 +0200 Subject: [PATCH 2/2] [ue4] Added error dialogs when skeleton and atlas couldn't be loaded. --- .../Source/SpinePlugin/Private/SpinePlugin.cpp | 2 ++ .../Private/SpineSkeletonAnimationComponent.cpp | 14 ++++++++------ .../SpinePlugin/Private/SpineSkeletonDataAsset.cpp | 13 +++++++++++++ .../Source/SpinePlugin/Public/SpinePlugin.h | 2 ++ 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpinePlugin.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpinePlugin.cpp index 4e8351326..18ae0d50e 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpinePlugin.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpinePlugin.cpp @@ -30,6 +30,8 @@ #include "SpinePluginPrivatePCH.h" +DEFINE_LOG_CATEGORY(SpineLog); + class FSpinePlugin : public SpinePlugin { virtual void StartupModule() override; virtual void ShutdownModule() override; diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonAnimationComponent.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonAnimationComponent.cpp index a575af97d..c01629bb3 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonAnimationComponent.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonAnimationComponent.cpp @@ -107,12 +107,14 @@ void USpineSkeletonAnimationComponent::CheckState () { if (Atlas && SkeletonData) { spSkeletonData* data = SkeletonData->GetSkeletonData(Atlas->GetAtlas(false), false); - skeleton = spSkeleton_create(data); - spAnimationStateData* stateData = SkeletonData->GetAnimationStateData(Atlas->GetAtlas(false)); - state = spAnimationState_create(stateData); - state->rendererObject = (void*)this; - state->listener = callback; - trackEntries.Empty(); + if (data) { + skeleton = spSkeleton_create(data); + spAnimationStateData* stateData = SkeletonData->GetAnimationStateData(Atlas->GetAtlas(false)); + state = spAnimationState_create(stateData); + state->rendererObject = (void*)this; + state->listener = callback; + trackEntries.Empty(); + } } lastAtlas = Atlas; diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp index 2c6d9ccfc..8ff4bf4dd 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp @@ -33,6 +33,7 @@ #include #include #include +#include "Runtime/Core/Public/Misc/MessageDialog.h" #define LOCTEXT_NAMESPACE "Spine" @@ -103,10 +104,22 @@ spSkeletonData* USpineSkeletonDataAsset::GetSkeletonData (spAtlas* Atlas, bool F if (skeletonDataFileName.GetPlainNameString().Contains(TEXT(".json"))) { spSkeletonJson* json = spSkeletonJson_create(Atlas); this->skeletonData = spSkeletonJson_readSkeletonData(json, (const char*)rawData.GetData()); + if (!skeletonData) { +#if WITH_EDITORONLY_DATA + FMessageDialog::Debugf(FText::FromString(UTF8_TO_TCHAR(json->error))); +#endif + UE_LOG(SpineLog, Error, TEXT("Couldn't load skeleton data and atlas: %s"), UTF8_TO_TCHAR(json->error)); + } spSkeletonJson_dispose(json); } else { spSkeletonBinary* binary = spSkeletonBinary_create(Atlas); this->skeletonData = spSkeletonBinary_readSkeletonData(binary, (const unsigned char*)rawData.GetData(), (int)rawData.Num()); + if (!skeletonData) { +#if WITH_EDITORONLY_DATA + FMessageDialog::Debugf(FText::FromString(UTF8_TO_TCHAR(binary->error))); +#endif + UE_LOG(SpineLog, Error, TEXT("Couldn't load skeleton data and atlas: %s"), UTF8_TO_TCHAR(binary->error)); + } spSkeletonBinary_dispose(binary); } if (animationStateData) { diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpinePlugin.h b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpinePlugin.h index 6011f932d..0d16143f7 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpinePlugin.h +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpinePlugin.h @@ -32,6 +32,8 @@ #include "ModuleManager.h" +DECLARE_LOG_CATEGORY_EXTERN(SpineLog, Log, All); + class SPINEPLUGIN_API SpinePlugin : public IModuleInterface { public: