mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +08:00
Merge branch '3.8' into 3.9-beta
This commit is contained in:
commit
79d2dbfa5f
@ -356,6 +356,7 @@
|
|||||||
3) Copy the original material, add *_Outline* to its name and set the shader to `Universal Render Pipeline/Spine/Outline/Skeleton-OutlineOnly`.
|
3) Copy the original material, add *_Outline* to its name and set the shader to `Universal Render Pipeline/Spine/Outline/Skeleton-OutlineOnly`.
|
||||||
4) Assign this *_Outline* material at the `RenderExistingMesh` component under *Replacement Materials*.
|
4) Assign this *_Outline* material at the `RenderExistingMesh` component under *Replacement Materials*.
|
||||||
* Added `Outline Shaders URP` example scene to URP extension module to demonstrate the above additions.
|
* Added `Outline Shaders URP` example scene to URP extension module to demonstrate the above additions.
|
||||||
|
* Added support for Unity's [`SpriteAtlas`](https://docs.unity3d.com/Manual/class-SpriteAtlas.html) as atlas provider (as an alternative to `.atlas.txt` and `.png` files) alongside a skeleton data file. There is now an additional `Spine SpriteAtlas Import` tool window accessible via `Window - Spine - SpriteAtlas Import`. Additional information can be found in a new section on the [spine-unity documentation page](http://esotericsoftware.com/spine-unity#Advanced---Using-Unity-SpriteAtlas-as-Atlas-Provider).
|
||||||
|
|
||||||
* **Changes of default values**
|
* **Changes of default values**
|
||||||
* `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`.
|
* `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`.
|
||||||
|
|||||||
@ -725,6 +725,7 @@ namespace Spine {
|
|||||||
slot.g += (slotData.g - slot.g) * alpha;
|
slot.g += (slotData.g - slot.g) * alpha;
|
||||||
slot.b += (slotData.b - slot.b) * alpha;
|
slot.b += (slotData.b - slot.b) * alpha;
|
||||||
slot.a += (slotData.a - slot.a) * alpha;
|
slot.a += (slotData.a - slot.a) * alpha;
|
||||||
|
slot.ClampColor();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -758,6 +759,7 @@ namespace Spine {
|
|||||||
slot.g = g;
|
slot.g = g;
|
||||||
slot.b = b;
|
slot.b = b;
|
||||||
slot.a = a;
|
slot.a = a;
|
||||||
|
slot.ClampColor();
|
||||||
} else {
|
} else {
|
||||||
float br, bg, bb, ba;
|
float br, bg, bb, ba;
|
||||||
if (blend == MixBlend.Setup) {
|
if (blend == MixBlend.Setup) {
|
||||||
@ -775,6 +777,7 @@ namespace Spine {
|
|||||||
slot.g = bg + ((g - bg) * alpha);
|
slot.g = bg + ((g - bg) * alpha);
|
||||||
slot.b = bb + ((b - bb) * alpha);
|
slot.b = bb + ((b - bb) * alpha);
|
||||||
slot.a = ba + ((a - ba) * alpha);
|
slot.a = ba + ((a - ba) * alpha);
|
||||||
|
slot.ClampColor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -839,18 +842,22 @@ namespace Spine {
|
|||||||
slot.g = slotData.g;
|
slot.g = slotData.g;
|
||||||
slot.b = slotData.b;
|
slot.b = slotData.b;
|
||||||
slot.a = slotData.a;
|
slot.a = slotData.a;
|
||||||
|
slot.ClampColor();
|
||||||
slot.r2 = slotData.r2;
|
slot.r2 = slotData.r2;
|
||||||
slot.g2 = slotData.g2;
|
slot.g2 = slotData.g2;
|
||||||
slot.b2 = slotData.b2;
|
slot.b2 = slotData.b2;
|
||||||
|
slot.ClampSecondColor();
|
||||||
return;
|
return;
|
||||||
case MixBlend.First:
|
case MixBlend.First:
|
||||||
slot.r += (slot.r - slotData.r) * alpha;
|
slot.r += (slot.r - slotData.r) * alpha;
|
||||||
slot.g += (slot.g - slotData.g) * alpha;
|
slot.g += (slot.g - slotData.g) * alpha;
|
||||||
slot.b += (slot.b - slotData.b) * alpha;
|
slot.b += (slot.b - slotData.b) * alpha;
|
||||||
slot.a += (slot.a - slotData.a) * alpha;
|
slot.a += (slot.a - slotData.a) * alpha;
|
||||||
|
slot.ClampColor();
|
||||||
slot.r2 += (slot.r2 - slotData.r2) * alpha;
|
slot.r2 += (slot.r2 - slotData.r2) * alpha;
|
||||||
slot.g2 += (slot.g2 - slotData.g2) * alpha;
|
slot.g2 += (slot.g2 - slotData.g2) * alpha;
|
||||||
slot.b2 += (slot.b2 - slotData.b2) * alpha;
|
slot.b2 += (slot.b2 - slotData.b2) * alpha;
|
||||||
|
slot.ClampSecondColor();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -893,9 +900,11 @@ namespace Spine {
|
|||||||
slot.g = g;
|
slot.g = g;
|
||||||
slot.b = b;
|
slot.b = b;
|
||||||
slot.a = a;
|
slot.a = a;
|
||||||
|
slot.ClampColor();
|
||||||
slot.r2 = r2;
|
slot.r2 = r2;
|
||||||
slot.g2 = g2;
|
slot.g2 = g2;
|
||||||
slot.b2 = b2;
|
slot.b2 = b2;
|
||||||
|
slot.ClampSecondColor();
|
||||||
} else {
|
} else {
|
||||||
float br, bg, bb, ba, br2, bg2, bb2;
|
float br, bg, bb, ba, br2, bg2, bb2;
|
||||||
if (blend == MixBlend.Setup) {
|
if (blend == MixBlend.Setup) {
|
||||||
@ -919,9 +928,11 @@ namespace Spine {
|
|||||||
slot.g = bg + ((g - bg) * alpha);
|
slot.g = bg + ((g - bg) * alpha);
|
||||||
slot.b = bb + ((b - bb) * alpha);
|
slot.b = bb + ((b - bb) * alpha);
|
||||||
slot.a = ba + ((a - ba) * alpha);
|
slot.a = ba + ((a - ba) * alpha);
|
||||||
|
slot.ClampColor();
|
||||||
slot.r2 = br2 + ((r2 - br2) * alpha);
|
slot.r2 = br2 + ((r2 - br2) * alpha);
|
||||||
slot.g2 = bg2 + ((g2 - bg2) * alpha);
|
slot.g2 = bg2 + ((g2 - bg2) * alpha);
|
||||||
slot.b2 = bb2 + ((b2 - bb2) * alpha);
|
slot.b2 = bb2 + ((b2 - bb2) * alpha);
|
||||||
|
slot.ClampSecondColor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -970,7 +981,6 @@ namespace Spine {
|
|||||||
|
|
||||||
public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend,
|
public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend,
|
||||||
MixDirection direction) {
|
MixDirection direction) {
|
||||||
string attachmentName;
|
|
||||||
Slot slot = skeleton.slots.Items[slotIndex];
|
Slot slot = skeleton.slots.Items[slotIndex];
|
||||||
if (!slot.bone.active) return;
|
if (!slot.bone.active) return;
|
||||||
if (direction == MixDirection.Out) {
|
if (direction == MixDirection.Out) {
|
||||||
|
|||||||
@ -106,6 +106,13 @@ namespace Spine {
|
|||||||
/// color tinting.</summary>
|
/// color tinting.</summary>
|
||||||
public float A { get { return a; } set { a = value; } }
|
public float A { get { return a; } set { a = value; } }
|
||||||
|
|
||||||
|
public void ClampColor() {
|
||||||
|
r = MathUtils.Clamp(r, 0, 1);
|
||||||
|
g = MathUtils.Clamp(g, 0, 1);
|
||||||
|
b = MathUtils.Clamp(b, 0, 1);
|
||||||
|
a = MathUtils.Clamp(a, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>The dark color used to tint the slot's attachment for two color tinting, ignored if two color tinting is not used.</summary>
|
/// <summary>The dark color used to tint the slot's attachment for two color tinting, ignored if two color tinting is not used.</summary>
|
||||||
/// <seealso cref="HasSecondColor"/>
|
/// <seealso cref="HasSecondColor"/>
|
||||||
public float R2 { get { return r2; } set { r2 = value; } }
|
public float R2 { get { return r2; } set { r2 = value; } }
|
||||||
@ -118,6 +125,12 @@ namespace Spine {
|
|||||||
/// <summary>Whether R2 G2 B2 are used to tint the slot's attachment for two color tinting. False if two color tinting is not used.</summary>
|
/// <summary>Whether R2 G2 B2 are used to tint the slot's attachment for two color tinting. False if two color tinting is not used.</summary>
|
||||||
public bool HasSecondColor { get { return data.hasSecondColor; } set { data.hasSecondColor = value; } }
|
public bool HasSecondColor { get { return data.hasSecondColor; } set { data.hasSecondColor = value; } }
|
||||||
|
|
||||||
|
public void ClampSecondColor () {
|
||||||
|
r2 = MathUtils.Clamp(r2, 0, 1);
|
||||||
|
g2 = MathUtils.Clamp(g2, 0, 1);
|
||||||
|
b2 = MathUtils.Clamp(b2, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
public Attachment Attachment {
|
public Attachment Attachment {
|
||||||
/// <summary>The current attachment for the slot, or null if the slot has no attachment.</summary>
|
/// <summary>The current attachment for the slot, or null if the slot has no attachment.</summary>
|
||||||
get { return attachment; }
|
get { return attachment; }
|
||||||
|
|||||||
@ -797,6 +797,48 @@ public class AnimationStateTests {
|
|||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup("looping", // 28
|
||||||
|
expect(0, "start", 0, 0), //
|
||||||
|
expect(0, "event 0", 0, 0), //
|
||||||
|
expect(0, "event 14", 0.5f, 0.5f), //
|
||||||
|
expect(0, "event 30", 1, 1), //
|
||||||
|
expect(0, "complete", 1, 1), //
|
||||||
|
expect(0, "event 0", 1, 1), //
|
||||||
|
expect(0, "event 14", 1.5f, 1.5f), //
|
||||||
|
expect(0, "event 30", 2, 2), //
|
||||||
|
expect(0, "complete", 2, 2), //
|
||||||
|
expect(0, "event 0", 2, 2), //
|
||||||
|
expect(0, "event 14", 2.5f, 2.5f), //
|
||||||
|
expect(0, "end", 2.6f, 2.7f), //
|
||||||
|
expect(0, "dispose", 2.6f, 2.7f) //
|
||||||
|
);
|
||||||
|
state.setAnimation(0, "events0", true).setTrackEnd(2.6f);
|
||||||
|
run(0.1f, 1000, null);
|
||||||
|
|
||||||
|
setup("set next", // 29
|
||||||
|
expect(0, "start", 0, 0), //
|
||||||
|
expect(0, "event 0", 0, 0), //
|
||||||
|
expect(0, "event 14", 0.5f, 0.5f), //
|
||||||
|
expect(0, "event 30", 1, 1), //
|
||||||
|
expect(0, "complete", 1, 1), //
|
||||||
|
expect(0, "interrupt", 1.1f, 1.1f), //
|
||||||
|
|
||||||
|
expect(1, "start", 0.1f, 1.1f), //
|
||||||
|
expect(1, "event 0", 0.1f, 1.1f), //
|
||||||
|
|
||||||
|
expect(0, "end", 1.1f, 1.2f), //
|
||||||
|
expect(0, "dispose", 1.1f, 1.2f), //
|
||||||
|
|
||||||
|
expect(1, "event 14", 0.5f, 1.5f), //
|
||||||
|
expect(1, "event 30", 1, 2), //
|
||||||
|
expect(1, "complete", 1, 2), //
|
||||||
|
expect(1, "end", 1, 2.1f), //
|
||||||
|
expect(1, "dispose", 1, 2.1f) //
|
||||||
|
);
|
||||||
|
state.setAnimation(0, "events0", false);
|
||||||
|
state.addAnimation(0, "events1", false, 0).setTrackEnd(1);
|
||||||
|
run(0.1f, 1000, null);
|
||||||
|
|
||||||
System.out.println("AnimationState tests passed.");
|
System.out.println("AnimationState tests passed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -168,7 +168,7 @@ public class Bone implements Updatable {
|
|||||||
b = pa * lb - pb * ld;
|
b = pa * lb - pb * ld;
|
||||||
c = pc * la + pd * lc;
|
c = pc * la + pd * lc;
|
||||||
d = pc * lb + pd * ld;
|
d = pc * lb + pd * ld;
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
case noScale:
|
case noScale:
|
||||||
case noScaleOrReflection: {
|
case noScaleOrReflection: {
|
||||||
|
|||||||
@ -60,6 +60,8 @@ namespace Spine.Unity.Examples {
|
|||||||
|
|
||||||
if (applyPMA) {
|
if (applyPMA) {
|
||||||
try {
|
try {
|
||||||
|
if (sprite == null)
|
||||||
|
return;
|
||||||
sprite.texture.GetPixel(0, 0);
|
sprite.texture.GetPixel(0, 0);
|
||||||
} catch (UnityException e) {
|
} catch (UnityException e) {
|
||||||
Debug.LogFormat("Texture of {0} ({1}) is not read/write enabled. SpriteAttacher requires this in order to work with a SkeletonRenderer that renders premultiplied alpha. Please check the texture settings.", sprite.name, sprite.texture.name);
|
Debug.LogFormat("Texture of {0} ({1}) is not read/write enabled. SpriteAttacher requires this in order to work with a SkeletonRenderer that renders premultiplied alpha. Please check the texture settings.", sprite.name, sprite.texture.name);
|
||||||
@ -124,7 +126,10 @@ namespace Spine.Unity.Examples {
|
|||||||
|
|
||||||
spineSlot = spineSlot ?? skeletonComponent.Skeleton.FindSlot(slot);
|
spineSlot = spineSlot ?? skeletonComponent.Skeleton.FindSlot(slot);
|
||||||
Shader attachmentShader = applyPMA ? Shader.Find(DefaultPMAShader) : Shader.Find(DefaultStraightAlphaShader);
|
Shader attachmentShader = applyPMA ? Shader.Find(DefaultPMAShader) : Shader.Find(DefaultStraightAlphaShader);
|
||||||
attachment = applyPMA ? sprite.ToRegionAttachmentPMAClone(attachmentShader) : sprite.ToRegionAttachment(SpriteAttacher.GetPageFor(sprite.texture, attachmentShader));
|
if (sprite == null)
|
||||||
|
attachment = null;
|
||||||
|
else
|
||||||
|
attachment = applyPMA ? sprite.ToRegionAttachmentPMAClone(attachmentShader) : sprite.ToRegionAttachment(SpriteAttacher.GetPageFor(sprite.texture, attachmentShader));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "spine-unity-examples-editor",
|
||||||
|
"references": [
|
||||||
|
"spine-unity",
|
||||||
|
"spine-unity-examples"
|
||||||
|
],
|
||||||
|
"includePlatforms": [
|
||||||
|
"Editor"
|
||||||
|
],
|
||||||
|
"excludePlatforms": [],
|
||||||
|
"allowUnsafeCode": false,
|
||||||
|
"overrideReferences": false,
|
||||||
|
"precompiledReferences": [],
|
||||||
|
"autoReferenced": true,
|
||||||
|
"defineConstraints": [],
|
||||||
|
"versionDefines": [],
|
||||||
|
"noEngineReferences": false
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 39599136c72c0b64b925d3ff2885aecb
|
||||||
|
AssemblyDefinitionImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,153 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes License Agreement
|
||||||
|
* Last updated January 1, 2020. Replaces all prior versions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2020, Esoteric Software LLC
|
||||||
|
*
|
||||||
|
* Integration of the Spine Runtimes into software or otherwise creating
|
||||||
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
|
* http://esotericsoftware.com/spine-editor-license
|
||||||
|
*
|
||||||
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
|
* "Products"), provided that each user of the Products must obtain their own
|
||||||
|
* Spine Editor license and redistribution of the Products in any form must
|
||||||
|
* include this license and copyright notice.
|
||||||
|
*
|
||||||
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||||
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using Spine;
|
||||||
|
|
||||||
|
namespace Spine.Unity.Editor {
|
||||||
|
using Event = UnityEngine.Event;
|
||||||
|
|
||||||
|
[CustomEditor(typeof(SpineSpriteAtlasAsset)), CanEditMultipleObjects]
|
||||||
|
public class SpineSpriteAtlasAssetInspector : UnityEditor.Editor {
|
||||||
|
SerializedProperty atlasFile, materials;
|
||||||
|
SpineSpriteAtlasAsset atlasAsset;
|
||||||
|
|
||||||
|
static List<AtlasRegion> GetRegions (Atlas atlas) {
|
||||||
|
FieldInfo regionsField = SpineInspectorUtility.GetNonPublicField(typeof(Atlas), "regions");
|
||||||
|
return (List<AtlasRegion>)regionsField.GetValue(atlas);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnEnable () {
|
||||||
|
SpineEditorUtilities.ConfirmInitialization();
|
||||||
|
atlasFile = serializedObject.FindProperty("spriteAtlasFile");
|
||||||
|
materials = serializedObject.FindProperty("materials");
|
||||||
|
materials.isExpanded = true;
|
||||||
|
atlasAsset = (SpineSpriteAtlasAsset)target;
|
||||||
|
|
||||||
|
if (!SpineSpriteAtlasAsset.AnySpriteAtlasNeedsRegionsLoaded())
|
||||||
|
return;
|
||||||
|
EditorApplication.update -= SpineSpriteAtlasAsset.UpdateWhenEditorPlayModeStarted;
|
||||||
|
EditorApplication.update += SpineSpriteAtlasAsset.UpdateWhenEditorPlayModeStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDisable () {
|
||||||
|
EditorApplication.update -= SpineSpriteAtlasAsset.UpdateWhenEditorPlayModeStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
override public void OnInspectorGUI () {
|
||||||
|
if (serializedObject.isEditingMultipleObjects) {
|
||||||
|
DrawDefaultInspector();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedObject.Update();
|
||||||
|
atlasAsset = atlasAsset ?? (SpineSpriteAtlasAsset)target;
|
||||||
|
|
||||||
|
if (atlasAsset.RegionsNeedLoading) {
|
||||||
|
if (GUILayout.Button(SpineInspectorUtility.TempContent("Load regions by entering Play mode"), GUILayout.Height(20))) {
|
||||||
|
EditorApplication.isPlaying = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
EditorGUILayout.PropertyField(atlasFile);
|
||||||
|
EditorGUILayout.PropertyField(materials, true);
|
||||||
|
if (EditorGUI.EndChangeCheck()) {
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
atlasAsset.Clear();
|
||||||
|
atlasAsset.GetAtlas();
|
||||||
|
atlasAsset.updateRegionsInPlayMode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (materials.arraySize == 0) {
|
||||||
|
EditorGUILayout.HelpBox("No materials", MessageType.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < materials.arraySize; i++) {
|
||||||
|
SerializedProperty prop = materials.GetArrayElementAtIndex(i);
|
||||||
|
var material = (Material)prop.objectReferenceValue;
|
||||||
|
if (material == null) {
|
||||||
|
EditorGUILayout.HelpBox("Materials cannot be null.", MessageType.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (atlasFile.objectReferenceValue != null) {
|
||||||
|
int baseIndent = EditorGUI.indentLevel;
|
||||||
|
|
||||||
|
var regions = SpineSpriteAtlasAssetInspector.GetRegions(atlasAsset.GetAtlas());
|
||||||
|
int regionsCount = regions.Count;
|
||||||
|
using (new EditorGUILayout.HorizontalScope()) {
|
||||||
|
EditorGUILayout.LabelField("Atlas Regions", EditorStyles.boldLabel);
|
||||||
|
EditorGUILayout.LabelField(string.Format("{0} regions total", regionsCount));
|
||||||
|
}
|
||||||
|
AtlasPage lastPage = null;
|
||||||
|
for (int i = 0; i < regionsCount; i++) {
|
||||||
|
if (lastPage != regions[i].page) {
|
||||||
|
if (lastPage != null) {
|
||||||
|
EditorGUILayout.Separator();
|
||||||
|
EditorGUILayout.Separator();
|
||||||
|
}
|
||||||
|
lastPage = regions[i].page;
|
||||||
|
Material mat = ((Material)lastPage.rendererObject);
|
||||||
|
if (mat != null) {
|
||||||
|
EditorGUI.indentLevel = baseIndent;
|
||||||
|
using (new GUILayout.HorizontalScope())
|
||||||
|
using (new EditorGUI.DisabledGroupScope(true))
|
||||||
|
EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250));
|
||||||
|
EditorGUI.indentLevel = baseIndent + 1;
|
||||||
|
} else {
|
||||||
|
EditorGUILayout.HelpBox("Page missing material!", MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string regionName = regions[i].name;
|
||||||
|
Texture2D icon = SpineEditorUtilities.Icons.image;
|
||||||
|
if (regionName.EndsWith(" ")) {
|
||||||
|
regionName = string.Format("'{0}'", regions[i].name);
|
||||||
|
icon = SpineEditorUtilities.Icons.warning;
|
||||||
|
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(regionName, icon, "Region name ends with whitespace. This may cause errors. Please check your source image filenames."));
|
||||||
|
} else {
|
||||||
|
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(regionName, icon));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EditorGUI.indentLevel = baseIndent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current))
|
||||||
|
atlasAsset.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f063dc5ff6881db4a9ee2e059812cba2
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -43,6 +43,10 @@
|
|||||||
#define NEW_PREFERENCES_SETTINGS_PROVIDER
|
#define NEW_PREFERENCES_SETTINGS_PROVIDER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if UNITY_2018_2_OR_NEWER
|
||||||
|
#define EXPOSES_SPRITE_ATLAS_UTILITIES
|
||||||
|
#endif
|
||||||
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -60,6 +64,7 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
public const string SkeletonDataSuffix = "_SkeletonData";
|
public const string SkeletonDataSuffix = "_SkeletonData";
|
||||||
public const string AtlasSuffix = "_Atlas";
|
public const string AtlasSuffix = "_Atlas";
|
||||||
|
public const string SpriteAtlasSuffix = "_SpriteAtlas";
|
||||||
|
|
||||||
/// HACK: This list keeps the asset reference temporarily during importing.
|
/// HACK: This list keeps the asset reference temporarily during importing.
|
||||||
///
|
///
|
||||||
@ -251,6 +256,7 @@ namespace Spine.Unity.Editor {
|
|||||||
bool reimport = false) {
|
bool reimport = false) {
|
||||||
|
|
||||||
var atlasPaths = new List<string>();
|
var atlasPaths = new List<string>();
|
||||||
|
var spriteAtlasPaths = new List<string>();
|
||||||
var imagePaths = new List<string>();
|
var imagePaths = new List<string>();
|
||||||
var skeletonPaths = new List<PathAndProblemInfo>();
|
var skeletonPaths = new List<PathAndProblemInfo>();
|
||||||
CompatibilityProblemInfo compatibilityProblemInfo = null;
|
CompatibilityProblemInfo compatibilityProblemInfo = null;
|
||||||
@ -267,6 +273,9 @@ namespace Spine.Unity.Editor {
|
|||||||
if (str.EndsWith(".atlas.txt", System.StringComparison.Ordinal))
|
if (str.EndsWith(".atlas.txt", System.StringComparison.Ordinal))
|
||||||
atlasPaths.Add(str);
|
atlasPaths.Add(str);
|
||||||
break;
|
break;
|
||||||
|
case ".spriteatlas":
|
||||||
|
spriteAtlasPaths.Add(str);
|
||||||
|
break;
|
||||||
case ".png":
|
case ".png":
|
||||||
case ".jpg":
|
case ".jpg":
|
||||||
imagePaths.Add(str);
|
imagePaths.Add(str);
|
||||||
@ -294,7 +303,6 @@ namespace Spine.Unity.Editor {
|
|||||||
AtlasAssetBase atlas = IngestSpineAtlas(atlasText, texturesWithoutMetaFile);
|
AtlasAssetBase atlas = IngestSpineAtlas(atlasText, texturesWithoutMetaFile);
|
||||||
atlases.Add(atlas);
|
atlases.Add(atlas);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddDependentSkeletonIfAtlasChanged(skeletonPaths, atlasPaths);
|
AddDependentSkeletonIfAtlasChanged(skeletonPaths, atlasPaths);
|
||||||
|
|
||||||
// Import skeletons and match them with atlases.
|
// Import skeletons and match them with atlases.
|
||||||
@ -575,6 +583,164 @@ namespace Spine.Unity.Editor {
|
|||||||
return (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(AtlasAssetBase));
|
return (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(AtlasAssetBase));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool SpriteAtlasSettingsNeedAdjustment (UnityEngine.U2D.SpriteAtlas spriteAtlas) {
|
||||||
|
#if EXPOSES_SPRITE_ATLAS_UTILITIES
|
||||||
|
UnityEditor.U2D.SpriteAtlasPackingSettings packingSettings = UnityEditor.U2D.SpriteAtlasExtensions.GetPackingSettings(spriteAtlas);
|
||||||
|
UnityEditor.U2D.SpriteAtlasTextureSettings textureSettings = UnityEditor.U2D.SpriteAtlasExtensions.GetTextureSettings(spriteAtlas);
|
||||||
|
|
||||||
|
bool areSettingsAsDesired =
|
||||||
|
packingSettings.enableRotation == true &&
|
||||||
|
packingSettings.enableTightPacking == false &&
|
||||||
|
textureSettings.readable == true &&
|
||||||
|
textureSettings.generateMipMaps == false;
|
||||||
|
// note: platformSettings.textureCompression is always providing "Compressed", so we have to skip it.
|
||||||
|
return !areSettingsAsDesired;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool AdjustSpriteAtlasSettings (UnityEngine.U2D.SpriteAtlas spriteAtlas) {
|
||||||
|
#if EXPOSES_SPRITE_ATLAS_UTILITIES
|
||||||
|
UnityEditor.U2D.SpriteAtlasPackingSettings packingSettings = UnityEditor.U2D.SpriteAtlasExtensions.GetPackingSettings(spriteAtlas);
|
||||||
|
UnityEditor.U2D.SpriteAtlasTextureSettings textureSettings = UnityEditor.U2D.SpriteAtlasExtensions.GetTextureSettings(spriteAtlas);
|
||||||
|
|
||||||
|
packingSettings.enableRotation = true;
|
||||||
|
packingSettings.enableTightPacking = false;
|
||||||
|
UnityEditor.U2D.SpriteAtlasExtensions.SetPackingSettings(spriteAtlas, packingSettings);
|
||||||
|
|
||||||
|
textureSettings.readable = true;
|
||||||
|
textureSettings.generateMipMaps = false;
|
||||||
|
UnityEditor.U2D.SpriteAtlasExtensions.SetTextureSettings(spriteAtlas, textureSettings);
|
||||||
|
|
||||||
|
TextureImporterPlatformSettings platformSettings = new TextureImporterPlatformSettings();
|
||||||
|
platformSettings.textureCompression = TextureImporterCompression.Uncompressed;
|
||||||
|
platformSettings.crunchedCompression = false;
|
||||||
|
UnityEditor.U2D.SpriteAtlasExtensions.SetPlatformSettings(spriteAtlas, platformSettings);
|
||||||
|
|
||||||
|
string atlasPath = AssetDatabase.GetAssetPath(spriteAtlas);
|
||||||
|
Debug.Log(string.Format("Adjusted unsuitable SpriteAtlas settings '{0}'", atlasPath), spriteAtlas);
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool GeneratePngFromSpriteAtlas (UnityEngine.U2D.SpriteAtlas spriteAtlas, out string texturePath) {
|
||||||
|
texturePath = System.IO.Path.ChangeExtension(AssetDatabase.GetAssetPath(spriteAtlas), ".png");
|
||||||
|
if (spriteAtlas == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Texture2D tempTexture = SpineSpriteAtlasAsset.AccessPackedTextureEditor(spriteAtlas);
|
||||||
|
if (tempTexture == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
byte[] bytes = null;
|
||||||
|
try {
|
||||||
|
bytes = tempTexture.EncodeToPNG();
|
||||||
|
}
|
||||||
|
catch (System.Exception) {
|
||||||
|
// handled below
|
||||||
|
}
|
||||||
|
if (bytes == null || bytes.Length == 0) {
|
||||||
|
Debug.LogError("Could not read Compressed SpriteAtlas. Please enable 'Read/Write Enabled' and ensure 'Compression' is set to 'None' in Inspector.", spriteAtlas);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
System.IO.File.WriteAllBytes(texturePath, bytes);
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
AssetDatabase.Refresh();
|
||||||
|
return System.IO.File.Exists(texturePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AtlasAssetBase IngestSpriteAtlas (UnityEngine.U2D.SpriteAtlas spriteAtlas, List<string> texturesWithoutMetaFile) {
|
||||||
|
if (spriteAtlas == null) {
|
||||||
|
Debug.LogWarning("SpriteAtlas source cannot be null!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SpriteAtlasSettingsNeedAdjustment(spriteAtlas)) {
|
||||||
|
// settings need to be adjusted via the 'Spine SpriteAtlas Import' window if you want to use it as a Spine atlas.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture2D texture = null;
|
||||||
|
{ // only one page file
|
||||||
|
string texturePath;
|
||||||
|
GeneratePngFromSpriteAtlas(spriteAtlas, out texturePath);
|
||||||
|
texture = AssetDatabase.LoadAssetAtPath<Texture2D>(texturePath);
|
||||||
|
if (texture == null && System.IO.File.Exists(texturePath)) {
|
||||||
|
EditorUtility.SetDirty(spriteAtlas);
|
||||||
|
return null; // next iteration will load the texture as well.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string primaryName = spriteAtlas.name;
|
||||||
|
string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spriteAtlas)).Replace('\\', '/');
|
||||||
|
|
||||||
|
string atlasPath = assetPath + "/" + primaryName + SpriteAtlasSuffix + ".asset";
|
||||||
|
|
||||||
|
SpineSpriteAtlasAsset atlasAsset = AssetDatabase.LoadAssetAtPath<SpineSpriteAtlasAsset>(atlasPath);
|
||||||
|
|
||||||
|
List<Material> vestigialMaterials = new List<Material>();
|
||||||
|
|
||||||
|
if (atlasAsset == null)
|
||||||
|
atlasAsset = SpineSpriteAtlasAsset.CreateInstance<SpineSpriteAtlasAsset>();
|
||||||
|
else {
|
||||||
|
foreach (Material m in atlasAsset.materials)
|
||||||
|
vestigialMaterials.Add(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
protectFromStackGarbageCollection.Add(atlasAsset);
|
||||||
|
atlasAsset.spriteAtlasFile = spriteAtlas;
|
||||||
|
|
||||||
|
int pagesCount = 1;
|
||||||
|
var populatingMaterials = new List<Material>(pagesCount);
|
||||||
|
|
||||||
|
{
|
||||||
|
string pageName = "SpriteAtlas";
|
||||||
|
|
||||||
|
string materialPath = assetPath + "/" + primaryName + "_" + pageName + ".mat";
|
||||||
|
Material mat = AssetDatabase.LoadAssetAtPath<Material>(materialPath);
|
||||||
|
|
||||||
|
if (mat == null) {
|
||||||
|
mat = new Material(Shader.Find(SpineEditorUtilities.Preferences.defaultShader));
|
||||||
|
ApplyPMAOrStraightAlphaSettings(mat, SpineEditorUtilities.Preferences.textureSettingsReference);
|
||||||
|
AssetDatabase.CreateAsset(mat, materialPath);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vestigialMaterials.Remove(mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texture != null)
|
||||||
|
mat.mainTexture = texture;
|
||||||
|
|
||||||
|
EditorUtility.SetDirty(mat);
|
||||||
|
// note: don't call AssetDatabase.SaveAssets() since this would trigger OnPostprocessAllAssets() every time unnecessarily.
|
||||||
|
populatingMaterials.Add(mat); //atlasAsset.materials[i] = mat;
|
||||||
|
}
|
||||||
|
|
||||||
|
atlasAsset.materials = populatingMaterials.ToArray();
|
||||||
|
|
||||||
|
for (int i = 0; i < vestigialMaterials.Count; i++)
|
||||||
|
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(vestigialMaterials[i]));
|
||||||
|
|
||||||
|
if (AssetDatabase.GetAssetPath(atlasAsset) == "")
|
||||||
|
AssetDatabase.CreateAsset(atlasAsset, atlasPath);
|
||||||
|
else
|
||||||
|
atlasAsset.Clear();
|
||||||
|
|
||||||
|
atlasAsset.GetAtlas();
|
||||||
|
atlasAsset.updateRegionsInPlayMode = true;
|
||||||
|
|
||||||
|
EditorUtility.SetDirty(atlasAsset);
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
|
||||||
|
Debug.Log(string.Format("{0} :: Imported with {1} material", atlasAsset.name, atlasAsset.materials.Length), atlasAsset);
|
||||||
|
|
||||||
|
protectFromStackGarbageCollection.Remove(atlasAsset);
|
||||||
|
return (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(AtlasAssetBase));
|
||||||
|
}
|
||||||
|
|
||||||
static bool SetDefaultTextureSettings (string texturePath, SpineAtlasAsset atlasAsset) {
|
static bool SetDefaultTextureSettings (string texturePath, SpineAtlasAsset atlasAsset) {
|
||||||
TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath);
|
TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath);
|
||||||
if (texImporter == null) {
|
if (texImporter == null) {
|
||||||
@ -595,7 +761,7 @@ namespace Spine.Unity.Editor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NEW_PREFERENCES_SETTINGS_PROVIDER
|
#if NEW_PREFERENCES_SETTINGS_PROVIDER
|
||||||
static bool SetReferenceTextureSettings (string texturePath, SpineAtlasAsset atlasAsset, string referenceAssetPath) {
|
static bool SetReferenceTextureSettings (string texturePath, SpineAtlasAsset atlasAsset, string referenceAssetPath) {
|
||||||
var texturePreset = AssetDatabase.LoadAssetAtPath<UnityEditor.Presets.Preset>(referenceAssetPath);
|
var texturePreset = AssetDatabase.LoadAssetAtPath<UnityEditor.Presets.Preset>(referenceAssetPath);
|
||||||
bool isTexturePreset = texturePreset != null && texturePreset.GetTargetTypeName() == "TextureImporter";
|
bool isTexturePreset = texturePreset != null && texturePreset.GetTargetTypeName() == "TextureImporter";
|
||||||
@ -613,7 +779,7 @@ namespace Spine.Unity.Editor {
|
|||||||
AssetDatabase.SaveAssets();
|
AssetDatabase.SaveAssets();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static bool SetReferenceTextureSettings (string texturePath, SpineAtlasAsset atlasAsset, string referenceAssetPath) {
|
static bool SetReferenceTextureSettings (string texturePath, SpineAtlasAsset atlasAsset, string referenceAssetPath) {
|
||||||
TextureImporter reference = TextureImporter.GetAtPath(referenceAssetPath) as TextureImporter;
|
TextureImporter reference = TextureImporter.GetAtPath(referenceAssetPath) as TextureImporter;
|
||||||
if (reference == null)
|
if (reference == null)
|
||||||
@ -642,7 +808,7 @@ namespace Spine.Unity.Editor {
|
|||||||
AssetDatabase.SaveAssets();
|
AssetDatabase.SaveAssets();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void ApplyPMAOrStraightAlphaSettings (Material material, string referenceTextureSettings) {
|
static void ApplyPMAOrStraightAlphaSettings (Material material, string referenceTextureSettings) {
|
||||||
bool isUsingPMAWorkflow = string.IsNullOrEmpty(referenceTextureSettings) ||
|
bool isUsingPMAWorkflow = string.IsNullOrEmpty(referenceTextureSettings) ||
|
||||||
@ -650,9 +816,9 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
MaterialChecks.EnablePMAAtMaterial(material, isUsingPMAWorkflow);
|
MaterialChecks.EnablePMAAtMaterial(material, isUsingPMAWorkflow);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Import SkeletonData (json or binary)
|
#region Import SkeletonData (json or binary)
|
||||||
internal static string GetSkeletonDataAssetFilePath(TextAsset spineJson) {
|
internal static string GetSkeletonDataAssetFilePath(TextAsset spineJson) {
|
||||||
string primaryName = Path.GetFileNameWithoutExtension(spineJson.name);
|
string primaryName = Path.GetFileNameWithoutExtension(spineJson.name);
|
||||||
string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson)).Replace('\\', '/');
|
string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson)).Replace('\\', '/');
|
||||||
@ -996,7 +1162,7 @@ namespace Spine.Unity.Editor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
string spineGameObjectName = string.Format("Spine GameObject ({0})", skeletonDataAsset.name.Replace("_SkeletonData", ""));
|
string spineGameObjectName = string.Format("Spine GameObject ({0})", skeletonDataAsset.name.Replace(AssetUtility.SkeletonDataSuffix, ""));
|
||||||
GameObject go = EditorInstantiation.NewGameObject(spineGameObjectName, useObjectFactory,
|
GameObject go = EditorInstantiation.NewGameObject(spineGameObjectName, useObjectFactory,
|
||||||
typeof(MeshFilter), typeof(MeshRenderer), typeof(SkeletonAnimation));
|
typeof(MeshFilter), typeof(MeshRenderer), typeof(SkeletonAnimation));
|
||||||
SkeletonAnimation newSkeletonAnimation = go.GetComponent<SkeletonAnimation>();
|
SkeletonAnimation newSkeletonAnimation = go.GetComponent<SkeletonAnimation>();
|
||||||
@ -1025,19 +1191,19 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
/// <summary>Handles creating a new GameObject in the Unity Editor. This uses the new ObjectFactory API where applicable.</summary>
|
/// <summary>Handles creating a new GameObject in the Unity Editor. This uses the new ObjectFactory API where applicable.</summary>
|
||||||
public static GameObject NewGameObject (string name, bool useObjectFactory) {
|
public static GameObject NewGameObject (string name, bool useObjectFactory) {
|
||||||
#if NEW_PREFAB_SYSTEM
|
#if NEW_PREFAB_SYSTEM
|
||||||
if (useObjectFactory)
|
if (useObjectFactory)
|
||||||
return ObjectFactory.CreateGameObject(name);
|
return ObjectFactory.CreateGameObject(name);
|
||||||
#endif
|
#endif
|
||||||
return new GameObject(name);
|
return new GameObject(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Handles creating a new GameObject in the Unity Editor. This uses the new ObjectFactory API where applicable.</summary>
|
/// <summary>Handles creating a new GameObject in the Unity Editor. This uses the new ObjectFactory API where applicable.</summary>
|
||||||
public static GameObject NewGameObject (string name, bool useObjectFactory, params System.Type[] components) {
|
public static GameObject NewGameObject (string name, bool useObjectFactory, params System.Type[] components) {
|
||||||
#if NEW_PREFAB_SYSTEM
|
#if NEW_PREFAB_SYSTEM
|
||||||
if (useObjectFactory)
|
if (useObjectFactory)
|
||||||
return ObjectFactory.CreateGameObject(name, components);
|
return ObjectFactory.CreateGameObject(name, components);
|
||||||
#endif
|
#endif
|
||||||
return new GameObject(name, components);
|
return new GameObject(name, components);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1075,7 +1241,7 @@ namespace Spine.Unity.Editor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
string spineGameObjectName = string.Format("Spine Mecanim GameObject ({0})", skeletonDataAsset.name.Replace("_SkeletonData", ""));
|
string spineGameObjectName = string.Format("Spine Mecanim GameObject ({0})", skeletonDataAsset.name.Replace(AssetUtility.SkeletonDataSuffix, ""));
|
||||||
GameObject go = EditorInstantiation.NewGameObject(spineGameObjectName, useObjectFactory,
|
GameObject go = EditorInstantiation.NewGameObject(spineGameObjectName, useObjectFactory,
|
||||||
typeof(MeshFilter), typeof(MeshRenderer), typeof(Animator), typeof(SkeletonMecanim));
|
typeof(MeshFilter), typeof(MeshRenderer), typeof(Animator), typeof(SkeletonMecanim));
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,170 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes License Agreement
|
||||||
|
* Last updated January 1, 2020. Replaces all prior versions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2020, Esoteric Software LLC
|
||||||
|
*
|
||||||
|
* Integration of the Spine Runtimes into software or otherwise creating
|
||||||
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
|
* http://esotericsoftware.com/spine-editor-license
|
||||||
|
*
|
||||||
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
|
* "Products"), provided that each user of the Products must obtain their own
|
||||||
|
* Spine Editor license and redistribution of the Products in any form must
|
||||||
|
* include this license and copyright notice.
|
||||||
|
*
|
||||||
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||||
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace Spine.Unity.Editor {
|
||||||
|
|
||||||
|
using Editor = UnityEditor.Editor;
|
||||||
|
using Icons = SpineEditorUtilities.Icons;
|
||||||
|
|
||||||
|
public class SpriteAtlasImportWindow : EditorWindow {
|
||||||
|
const bool IsUtilityWindow = false;
|
||||||
|
|
||||||
|
[MenuItem("Window/Spine/SpriteAtlas Import", false, 5000)]
|
||||||
|
public static void Init (MenuCommand command) {
|
||||||
|
var window = EditorWindow.GetWindow<SpriteAtlasImportWindow>(IsUtilityWindow);
|
||||||
|
window.minSize = new Vector2(284f, 256f);
|
||||||
|
window.maxSize = new Vector2(500f, 256f);
|
||||||
|
window.titleContent = new GUIContent("Spine SpriteAtlas Import", Icons.spine);
|
||||||
|
window.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnityEngine.U2D.SpriteAtlas spriteAtlasAsset;
|
||||||
|
public TextAsset skeletonDataFile;
|
||||||
|
public SpineSpriteAtlasAsset spineSpriteAtlasAsset;
|
||||||
|
|
||||||
|
SerializedObject so;
|
||||||
|
|
||||||
|
void OnEnable () {
|
||||||
|
if (!SpineSpriteAtlasAsset.AnySpriteAtlasNeedsRegionsLoaded())
|
||||||
|
return;
|
||||||
|
EditorApplication.update -= SpineSpriteAtlasAsset.UpdateWhenEditorPlayModeStarted;
|
||||||
|
EditorApplication.update += SpineSpriteAtlasAsset.UpdateWhenEditorPlayModeStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDisable () {
|
||||||
|
EditorApplication.update -= SpineSpriteAtlasAsset.UpdateWhenEditorPlayModeStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnGUI () {
|
||||||
|
so = so ?? new SerializedObject(this);
|
||||||
|
|
||||||
|
EditorGUIUtility.wideMode = true;
|
||||||
|
EditorGUILayout.LabelField("Spine SpriteAtlas Import", EditorStyles.boldLabel);
|
||||||
|
|
||||||
|
using (new SpineInspectorUtility.BoxScope()) {
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
var spriteAtlasAssetProperty = so.FindProperty("spriteAtlasAsset");
|
||||||
|
EditorGUILayout.PropertyField(spriteAtlasAssetProperty, new GUIContent("SpriteAtlas", EditorGUIUtility.IconContent("SpriteAtlas Icon").image));
|
||||||
|
if (EditorGUI.EndChangeCheck()) {
|
||||||
|
so.ApplyModifiedProperties();
|
||||||
|
if (spriteAtlasAsset != null) {
|
||||||
|
if (AssetUtility.SpriteAtlasSettingsNeedAdjustment(spriteAtlasAsset)) {
|
||||||
|
AssetUtility.AdjustSpriteAtlasSettings(spriteAtlasAsset);
|
||||||
|
}
|
||||||
|
GenerateAssetsFromSpriteAtlas(spriteAtlasAsset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var spineSpriteAtlasAssetProperty = so.FindProperty("spineSpriteAtlasAsset");
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
EditorGUILayout.PropertyField(spineSpriteAtlasAssetProperty, new GUIContent("SpineSpriteAtlasAsset", EditorGUIUtility.IconContent("ScriptableObject Icon").image));
|
||||||
|
if (spineSpriteAtlasAssetProperty.objectReferenceValue == null) {
|
||||||
|
spineSpriteAtlasAssetProperty.objectReferenceValue = spineSpriteAtlasAsset = FindSpineSpriteAtlasAsset(spriteAtlasAsset);
|
||||||
|
}
|
||||||
|
if (EditorGUI.EndChangeCheck()) {
|
||||||
|
so.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
|
||||||
|
using (new EditorGUI.DisabledScope(spineSpriteAtlasAsset == null)) {
|
||||||
|
if (SpineInspectorUtility.LargeCenteredButton(new GUIContent("Load regions by entering Play mode"))) {
|
||||||
|
GenerateAssetsFromSpriteAtlas(spriteAtlasAsset);
|
||||||
|
SpineSpriteAtlasAsset.UpdateByStartingEditorPlayMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using (new SpineInspectorUtility.BoxScope()) {
|
||||||
|
if (spriteAtlasAsset == null) {
|
||||||
|
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Please assign SpriteAtlas file.", Icons.warning), GUILayout.Height(46));
|
||||||
|
}
|
||||||
|
else if (spineSpriteAtlasAsset == null || spineSpriteAtlasAsset.RegionsNeedLoading) {
|
||||||
|
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Please hit 'Load regions ..' to load\nregion info. Play mode is started\nand stopped automatically.", Icons.warning), GUILayout.Height(54));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("SpriteAtlas imported\nsuccessfully.", Icons.spine), GUILayout.Height(46));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isAtlasComplete = (spineSpriteAtlasAsset != null && !spineSpriteAtlasAsset.RegionsNeedLoading);
|
||||||
|
bool canImportSkeleton = (spriteAtlasAsset != null && skeletonDataFile != null);
|
||||||
|
using (new SpineInspectorUtility.BoxScope()) {
|
||||||
|
|
||||||
|
using (new EditorGUI.DisabledScope(!isAtlasComplete)) {
|
||||||
|
var skeletonDataAssetProperty = so.FindProperty("skeletonDataFile");
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
EditorGUILayout.PropertyField(skeletonDataAssetProperty, SpineInspectorUtility.TempContent("Skeleton json/skel file", Icons.spine));
|
||||||
|
if (EditorGUI.EndChangeCheck()) {
|
||||||
|
so.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
}
|
||||||
|
using (new EditorGUI.DisabledScope(!canImportSkeleton)) {
|
||||||
|
if (SpineInspectorUtility.LargeCenteredButton(new GUIContent("Import Skeleton"))) {
|
||||||
|
//AssetUtility.IngestSpriteAtlas(spriteAtlasAsset, null);
|
||||||
|
string skeletonPath = AssetDatabase.GetAssetPath(skeletonDataFile);
|
||||||
|
string[] skeletons = new string[] { skeletonPath };
|
||||||
|
AssetUtility.ImportSpineContent(skeletons, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GenerateAssetsFromSpriteAtlas (UnityEngine.U2D.SpriteAtlas spriteAtlasAsset) {
|
||||||
|
AssetUtility.IngestSpriteAtlas(spriteAtlasAsset, null);
|
||||||
|
string texturePath;
|
||||||
|
if (AssetUtility.GeneratePngFromSpriteAtlas(spriteAtlasAsset, out texturePath)) {
|
||||||
|
Debug.Log(string.Format("Generated SpriteAtlas texture '{0}'", texturePath), spriteAtlasAsset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpineSpriteAtlasAsset FindSpineSpriteAtlasAsset (UnityEngine.U2D.SpriteAtlas spriteAtlasAsset) {
|
||||||
|
string path = AssetDatabase.GetAssetPath(spriteAtlasAsset).Replace(".spriteatlas", AssetUtility.SpriteAtlasSuffix + ".asset");
|
||||||
|
if (System.IO.File.Exists(path)) {
|
||||||
|
return AssetDatabase.LoadAssetAtPath<SpineSpriteAtlasAsset>(path);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkeletonDataAsset FindSkeletonDataAsset (TextAsset skeletonDataFile) {
|
||||||
|
string path = AssetDatabase.GetAssetPath(skeletonDataFile);
|
||||||
|
path = path.Replace(".json", AssetUtility.SkeletonDataSuffix + ".asset");
|
||||||
|
path = path.Replace(".skel.bytes", AssetUtility.SkeletonDataSuffix + ".asset");
|
||||||
|
if (System.IO.File.Exists(path)) {
|
||||||
|
return AssetDatabase.LoadAssetAtPath<SkeletonDataAsset>(path);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a5b99b091defeef439a0cb8c99fd8a51
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,397 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes License Agreement
|
||||||
|
* Last updated January 1, 2020. Replaces all prior versions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2020, Esoteric Software LLC
|
||||||
|
*
|
||||||
|
* Integration of the Spine Runtimes into software or otherwise creating
|
||||||
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
|
* http://esotericsoftware.com/spine-editor-license
|
||||||
|
*
|
||||||
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
|
* "Products"), provided that each user of the Products must obtain their own
|
||||||
|
* Spine Editor license and redistribution of the Products in any form must
|
||||||
|
* include this license and copyright notice.
|
||||||
|
*
|
||||||
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||||
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#if UNITY_2018_2_OR_NEWER
|
||||||
|
#define EXPOSES_SPRITE_ATLAS_UTILITIES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using UnityEngine;
|
||||||
|
using Spine;
|
||||||
|
using UnityEngine.U2D;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
using UnityEditor;
|
||||||
|
using System.Reflection;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Spine.Unity {
|
||||||
|
/// <summary>Loads and stores a Spine atlas and list of materials.</summary>
|
||||||
|
[CreateAssetMenu(fileName = "New Spine SpriteAtlas Asset", menuName = "Spine/Spine SpriteAtlas Asset")]
|
||||||
|
public class SpineSpriteAtlasAsset : AtlasAssetBase {
|
||||||
|
public SpriteAtlas spriteAtlasFile;
|
||||||
|
public Material[] materials;
|
||||||
|
protected Atlas atlas;
|
||||||
|
public bool updateRegionsInPlayMode;
|
||||||
|
|
||||||
|
[System.Serializable]
|
||||||
|
protected class SavedRegionInfo {
|
||||||
|
public float x, y, width, height;
|
||||||
|
public SpritePackingRotation packingRotation;
|
||||||
|
}
|
||||||
|
[SerializeField] protected SavedRegionInfo[] savedRegions;
|
||||||
|
|
||||||
|
public override bool IsLoaded { get { return this.atlas != null; } }
|
||||||
|
|
||||||
|
public override IEnumerable<Material> Materials { get { return materials; } }
|
||||||
|
public override int MaterialCount { get { return materials == null ? 0 : materials.Length; } }
|
||||||
|
public override Material PrimaryMaterial { get { return materials[0]; } }
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
static MethodInfo GetPackedSpritesMethod, GetPreviewTexturesMethod;
|
||||||
|
#if !EXPOSES_SPRITE_ATLAS_UTILITIES
|
||||||
|
static MethodInfo PackAtlasesMethod;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#region Runtime Instantiation
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a runtime AtlasAsset</summary>
|
||||||
|
public static SpineSpriteAtlasAsset CreateRuntimeInstance (SpriteAtlas spriteAtlasFile, Material[] materials, bool initialize) {
|
||||||
|
SpineSpriteAtlasAsset atlasAsset = ScriptableObject.CreateInstance<SpineSpriteAtlasAsset>();
|
||||||
|
atlasAsset.Reset();
|
||||||
|
atlasAsset.spriteAtlasFile = spriteAtlasFile;
|
||||||
|
atlasAsset.materials = materials;
|
||||||
|
|
||||||
|
if (initialize)
|
||||||
|
atlasAsset.GetAtlas();
|
||||||
|
|
||||||
|
return atlasAsset;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
void Reset () {
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Clear () {
|
||||||
|
atlas = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <returns>The atlas or null if it could not be loaded.</returns>
|
||||||
|
public override Atlas GetAtlas () {
|
||||||
|
if (spriteAtlasFile == null) {
|
||||||
|
Debug.LogError("SpriteAtlas file not set for SpineSpriteAtlasAsset: " + name, this);
|
||||||
|
Clear();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (materials == null || materials.Length == 0) {
|
||||||
|
Debug.LogError("Materials not set for SpineSpriteAtlasAsset: " + name, this);
|
||||||
|
Clear();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (atlas != null) return atlas;
|
||||||
|
|
||||||
|
try {
|
||||||
|
atlas = LoadAtlas(spriteAtlasFile);
|
||||||
|
return atlas;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Debug.LogError("Error analyzing SpriteAtlas for SpineSpriteAtlasAsset: " + name + "\n" + ex.Message + "\n" + ex.StackTrace, this);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void AssignRegionsFromSavedRegions (Sprite[] sprites, Atlas usedAtlas) {
|
||||||
|
|
||||||
|
if (savedRegions == null || savedRegions.Length != sprites.Length)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (var region in usedAtlas) {
|
||||||
|
var savedRegion = savedRegions[i];
|
||||||
|
var page = region.page;
|
||||||
|
|
||||||
|
region.degrees = savedRegion.packingRotation == SpritePackingRotation.None ? 0 : 90;
|
||||||
|
region.rotate = region.degrees != 0;
|
||||||
|
|
||||||
|
float x = savedRegion.x;
|
||||||
|
float y = savedRegion.y;
|
||||||
|
float width = savedRegion.width;
|
||||||
|
float height = savedRegion.height;
|
||||||
|
|
||||||
|
region.u = x / (float)page.width;
|
||||||
|
region.v = y / (float)page.height;
|
||||||
|
if (region.rotate) {
|
||||||
|
region.u2 = (x + height) / (float)page.width;
|
||||||
|
region.v2 = (y + width) / (float)page.height;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
region.u2 = (x + width) / (float)page.width;
|
||||||
|
region.v2 = (y + height) / (float)page.height;
|
||||||
|
}
|
||||||
|
region.x = (int)x;
|
||||||
|
region.y = (int)y;
|
||||||
|
region.width = Math.Abs((int)width);
|
||||||
|
region.height = Math.Abs((int)height);
|
||||||
|
|
||||||
|
// flip upside down
|
||||||
|
var temp = region.v;
|
||||||
|
region.v = region.v2;
|
||||||
|
region.v2 = temp;
|
||||||
|
|
||||||
|
region.originalWidth = (int)width;
|
||||||
|
region.originalHeight = (int)height;
|
||||||
|
|
||||||
|
// note: currently sprite pivot offsets are ignored.
|
||||||
|
// var sprite = sprites[i];
|
||||||
|
region.offsetX = 0;//sprite.pivot.x;
|
||||||
|
region.offsetY = 0;//sprite.pivot.y;
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Atlas LoadAtlas (UnityEngine.U2D.SpriteAtlas spriteAtlas) {
|
||||||
|
|
||||||
|
List<AtlasPage> pages = new List<AtlasPage>();
|
||||||
|
List<AtlasRegion> regions = new List<AtlasRegion>();
|
||||||
|
|
||||||
|
Sprite[] sprites = new UnityEngine.Sprite[spriteAtlas.spriteCount];
|
||||||
|
spriteAtlas.GetSprites(sprites);
|
||||||
|
if (sprites.Length == 0)
|
||||||
|
return new Atlas(pages, regions);
|
||||||
|
|
||||||
|
Texture2D texture = null;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (!Application.isPlaying)
|
||||||
|
texture = AccessPackedTextureEditor(spriteAtlas);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
texture = AccessPackedTexture(sprites);
|
||||||
|
|
||||||
|
Material material = materials[0];
|
||||||
|
#if !UNITY_EDITOR
|
||||||
|
material.mainTexture = texture;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Spine.AtlasPage page = new AtlasPage();
|
||||||
|
page.name = spriteAtlas.name;
|
||||||
|
page.width = texture.width;
|
||||||
|
page.height = texture.height;
|
||||||
|
page.format = Spine.Format.RGBA8888;
|
||||||
|
|
||||||
|
page.minFilter = TextureFilter.Linear;
|
||||||
|
page.magFilter = TextureFilter.Linear;
|
||||||
|
page.uWrap = TextureWrap.ClampToEdge;
|
||||||
|
page.vWrap = TextureWrap.ClampToEdge;
|
||||||
|
page.rendererObject = material;
|
||||||
|
pages.Add(page);
|
||||||
|
|
||||||
|
sprites = AccessPackedSprites(spriteAtlas);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for ( ; i < sprites.Length; ++i) {
|
||||||
|
var sprite = sprites[i];
|
||||||
|
AtlasRegion region = new AtlasRegion();
|
||||||
|
region.name = sprite.name.Replace("(Clone)", "");
|
||||||
|
region.page = page;
|
||||||
|
region.degrees = sprite.packingRotation == SpritePackingRotation.None ? 0 : 90;
|
||||||
|
region.rotate = region.degrees != 0;
|
||||||
|
|
||||||
|
region.u2 = 1;
|
||||||
|
region.v2 = 1;
|
||||||
|
region.width = page.width;
|
||||||
|
region.height = page.height;
|
||||||
|
region.originalWidth = page.width;
|
||||||
|
region.originalHeight = page.height;
|
||||||
|
|
||||||
|
region.index = i;
|
||||||
|
regions.Add(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
var atlas = new Atlas(pages, regions);
|
||||||
|
AssignRegionsFromSavedRegions(sprites, atlas);
|
||||||
|
|
||||||
|
return atlas;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
public static void UpdateByStartingEditorPlayMode () {
|
||||||
|
EditorApplication.isPlaying = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool AnySpriteAtlasNeedsRegionsLoaded () {
|
||||||
|
string[] guids = UnityEditor.AssetDatabase.FindAssets("t:SpineSpriteAtlasAsset");
|
||||||
|
foreach (var guid in guids) {
|
||||||
|
string path = UnityEditor.AssetDatabase.GUIDToAssetPath(guid);
|
||||||
|
if (!string.IsNullOrEmpty(path)) {
|
||||||
|
var atlasAsset = UnityEditor.AssetDatabase.LoadAssetAtPath<SpineSpriteAtlasAsset>(path);
|
||||||
|
if (atlasAsset) {
|
||||||
|
if (atlasAsset.RegionsNeedLoading)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateWhenEditorPlayModeStarted () {
|
||||||
|
if (!EditorApplication.isPlaying)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EditorApplication.update -= UpdateWhenEditorPlayModeStarted;
|
||||||
|
string[] guids = UnityEditor.AssetDatabase.FindAssets("t:SpineSpriteAtlasAsset");
|
||||||
|
if (guids.Length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Debug.Log("Updating SpineSpriteAtlasAssets");
|
||||||
|
foreach (var guid in guids) {
|
||||||
|
string path = UnityEditor.AssetDatabase.GUIDToAssetPath(guid);
|
||||||
|
if (!string.IsNullOrEmpty(path)) {
|
||||||
|
var atlasAsset = UnityEditor.AssetDatabase.LoadAssetAtPath<SpineSpriteAtlasAsset>(path);
|
||||||
|
if (atlasAsset) {
|
||||||
|
atlasAsset.atlas = atlasAsset.LoadAtlas(atlasAsset.spriteAtlasFile);
|
||||||
|
atlasAsset.LoadRegionsInEditorPlayMode();
|
||||||
|
Debug.Log(string.Format("Updated regions of '{0}'", atlasAsset.name), atlasAsset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorApplication.isPlaying = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RegionsNeedLoading {
|
||||||
|
get { return savedRegions == null || savedRegions.Length == 0 || updateRegionsInPlayMode; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadRegionsInEditorPlayMode () {
|
||||||
|
|
||||||
|
Sprite[] sprites = null;
|
||||||
|
System.Type T = Type.GetType("UnityEditor.U2D.SpriteAtlasExtensions,UnityEditor");
|
||||||
|
var method = T.GetMethod("GetPackedSprites", BindingFlags.NonPublic | BindingFlags.Static);
|
||||||
|
if (method != null) {
|
||||||
|
object retval = method.Invoke(null, new object[] { spriteAtlasFile });
|
||||||
|
var spritesArray = retval as Sprite[];
|
||||||
|
if (spritesArray != null && spritesArray.Length > 0) {
|
||||||
|
sprites = spritesArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sprites == null) {
|
||||||
|
sprites = new UnityEngine.Sprite[spriteAtlasFile.spriteCount];
|
||||||
|
spriteAtlasFile.GetSprites(sprites);
|
||||||
|
}
|
||||||
|
if (sprites.Length == 0) {
|
||||||
|
Debug.LogWarning(string.Format("SpriteAtlas '{0}' contains no sprites. Please make sure all assigned images are set to import type 'Sprite'.", spriteAtlasFile.name), spriteAtlasFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (sprites[0].packingMode == SpritePackingMode.Tight) {
|
||||||
|
Debug.LogError(string.Format("SpriteAtlas '{0}': Tight packing is not supported. Please disable 'Tight Packing' in the SpriteAtlas Inspector.", spriteAtlasFile.name), spriteAtlasFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (savedRegions == null || savedRegions.Length != sprites.Length)
|
||||||
|
savedRegions = new SavedRegionInfo[sprites.Length];
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (var region in atlas) {
|
||||||
|
var sprite = sprites[i];
|
||||||
|
var rect = sprite.textureRect;
|
||||||
|
float x = rect.min.x;
|
||||||
|
float y = rect.min.y;
|
||||||
|
float width = rect.width;
|
||||||
|
float height = rect.height;
|
||||||
|
|
||||||
|
var savedRegion = new SavedRegionInfo();
|
||||||
|
savedRegion.x = x;
|
||||||
|
savedRegion.y = y;
|
||||||
|
savedRegion.width = width;
|
||||||
|
savedRegion.height = height;
|
||||||
|
savedRegion.packingRotation = sprite.packingRotation;
|
||||||
|
savedRegions[i] = savedRegion;
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
updateRegionsInPlayMode = false;
|
||||||
|
AssignRegionsFromSavedRegions(sprites, atlas);
|
||||||
|
EditorUtility.SetDirty(this);
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Texture2D AccessPackedTextureEditor (SpriteAtlas spriteAtlas) {
|
||||||
|
#if EXPOSES_SPRITE_ATLAS_UTILITIES
|
||||||
|
UnityEditor.U2D.SpriteAtlasUtility.PackAtlases(new SpriteAtlas[] { spriteAtlas }, EditorUserBuildSettings.activeBuildTarget);
|
||||||
|
#else
|
||||||
|
/*if (PackAtlasesMethod == null) {
|
||||||
|
System.Type T = Type.GetType("UnityEditor.U2D.SpriteAtlasUtility,UnityEditor");
|
||||||
|
PackAtlasesMethod = T.GetMethod("PackAtlases", BindingFlags.NonPublic | BindingFlags.Static);
|
||||||
|
}
|
||||||
|
if (PackAtlasesMethod != null) {
|
||||||
|
PackAtlasesMethod.Invoke(null, new object[] { new SpriteAtlas[] { spriteAtlas }, EditorUserBuildSettings.activeBuildTarget });
|
||||||
|
}*/
|
||||||
|
#endif
|
||||||
|
if (GetPreviewTexturesMethod == null) {
|
||||||
|
System.Type T = Type.GetType("UnityEditor.U2D.SpriteAtlasExtensions,UnityEditor");
|
||||||
|
GetPreviewTexturesMethod = T.GetMethod("GetPreviewTextures", BindingFlags.NonPublic | BindingFlags.Static);
|
||||||
|
}
|
||||||
|
if (GetPreviewTexturesMethod != null) {
|
||||||
|
object retval = GetPreviewTexturesMethod.Invoke(null, new object[] { spriteAtlas });
|
||||||
|
var textures = retval as Texture2D[];
|
||||||
|
if (textures.Length > 0)
|
||||||
|
return textures[0];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
public static Texture2D AccessPackedTexture (Sprite[] sprites) {
|
||||||
|
return sprites[0].texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Sprite[] AccessPackedSprites (UnityEngine.U2D.SpriteAtlas spriteAtlas) {
|
||||||
|
Sprite[] sprites = null;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (!Application.isPlaying) {
|
||||||
|
|
||||||
|
if (GetPackedSpritesMethod == null) {
|
||||||
|
System.Type T = Type.GetType("UnityEditor.U2D.SpriteAtlasExtensions,UnityEditor");
|
||||||
|
GetPackedSpritesMethod = T.GetMethod("GetPackedSprites", BindingFlags.NonPublic | BindingFlags.Static);
|
||||||
|
}
|
||||||
|
if (GetPackedSpritesMethod != null) {
|
||||||
|
object retval = GetPackedSpritesMethod.Invoke(null, new object[] { spriteAtlas });
|
||||||
|
var spritesArray = retval as Sprite[];
|
||||||
|
if (spritesArray != null && spritesArray.Length > 0) {
|
||||||
|
sprites = spritesArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (sprites == null) {
|
||||||
|
sprites = new UnityEngine.Sprite[spriteAtlas.spriteCount];
|
||||||
|
spriteAtlas.GetSprites(sprites);
|
||||||
|
if (sprites.Length == 0)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return sprites;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ce59897dd7e6cbc4690a05ebaf975dff
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -417,9 +417,8 @@ namespace Spine.Unity {
|
|||||||
var interruptingStateInfo = animator.GetNextAnimatorStateInfo(layer);
|
var interruptingStateInfo = animator.GetNextAnimatorStateInfo(layer);
|
||||||
layerInfos.isLastFrameOfInterruption = interruptingStateInfo.fullPathHash == 0;
|
layerInfos.isLastFrameOfInterruption = interruptingStateInfo.fullPathHash == 0;
|
||||||
if (!layerInfos.isLastFrameOfInterruption) {
|
if (!layerInfos.isLastFrameOfInterruption) {
|
||||||
layerInfos.interruptingClipInfoCount = interruptingClipInfos.Count;
|
|
||||||
|
|
||||||
animator.GetNextAnimatorClipInfo(layer, interruptingClipInfos);
|
animator.GetNextAnimatorClipInfo(layer, interruptingClipInfos);
|
||||||
|
layerInfos.interruptingClipInfoCount = interruptingClipInfos.Count;
|
||||||
float oldTime = layerInfos.interruptingStateInfo.normalizedTime;
|
float oldTime = layerInfos.interruptingStateInfo.normalizedTime;
|
||||||
float newTime = interruptingStateInfo.normalizedTime;
|
float newTime = interruptingStateInfo.normalizedTime;
|
||||||
layerInfos.interruptingClipTimeAddition = newTime - oldTime;
|
layerInfos.interruptingClipTimeAddition = newTime - oldTime;
|
||||||
|
|||||||
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections;
|
using System;
|
||||||
|
|
||||||
namespace Spine.Unity.AttachmentTools {
|
namespace Spine.Unity.AttachmentTools {
|
||||||
|
|
||||||
@ -537,7 +537,24 @@ namespace Spine.Unity.AttachmentTools {
|
|||||||
bool mipmaps = UseMipMaps, bool linear = false, bool applyPMA = false) {
|
bool mipmaps = UseMipMaps, bool linear = false, bool applyPMA = false) {
|
||||||
|
|
||||||
var spriteTexture = s.texture;
|
var spriteTexture = s.texture;
|
||||||
var r = s.textureRect;
|
Rect r;
|
||||||
|
if (!s.packed || s.packingMode == SpritePackingMode.Rectangle) {
|
||||||
|
r = s.textureRect;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
r = new Rect();
|
||||||
|
r.xMin = Math.Min(s.uv[0].x, s.uv[1].x) * spriteTexture.width;
|
||||||
|
r.xMax = Math.Max(s.uv[0].x, s.uv[1].x) * spriteTexture.width;
|
||||||
|
r.yMin = Math.Min(s.uv[0].y, s.uv[2].y) * spriteTexture.height;
|
||||||
|
r.yMax = Math.Max(s.uv[0].y, s.uv[2].y) * spriteTexture.height;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (s.uv.Length > 4) {
|
||||||
|
Debug.LogError("When using a tightly packed SpriteAtlas with Spine, you may only access Sprites that are packed as 'FullRect' from it! " +
|
||||||
|
"You can either disable 'Tight Packing' at the whole SpriteAtlas, or change the single Sprite's TextureImporter Setting 'MeshType' to 'Full Rect'." +
|
||||||
|
"Sprite Asset: " + s.name, s);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
var newTexture = new Texture2D((int)r.width, (int)r.height, textureFormat, mipmaps, linear);
|
var newTexture = new Texture2D((int)r.width, (int)r.height, textureFormat, mipmaps, linear);
|
||||||
newTexture.CopyTextureAttributesFrom(spriteTexture);
|
newTexture.CopyTextureAttributesFrom(spriteTexture);
|
||||||
if (applyPMA)
|
if (applyPMA)
|
||||||
|
|||||||
@ -38,6 +38,7 @@ namespace Spine.Unity {
|
|||||||
|
|
||||||
static readonly int STRAIGHT_ALPHA_PARAM_ID = Shader.PropertyToID("_StraightAlphaInput");
|
static readonly int STRAIGHT_ALPHA_PARAM_ID = Shader.PropertyToID("_StraightAlphaInput");
|
||||||
static readonly string ALPHAPREMULTIPLY_ON_KEYWORD = "_ALPHAPREMULTIPLY_ON";
|
static readonly string ALPHAPREMULTIPLY_ON_KEYWORD = "_ALPHAPREMULTIPLY_ON";
|
||||||
|
static readonly string STRAIGHT_ALPHA_KEYWORD = "_STRAIGHT_ALPHA_INPUT";
|
||||||
|
|
||||||
public static readonly string kPMANotSupportedLinearMessage =
|
public static readonly string kPMANotSupportedLinearMessage =
|
||||||
"Warning: Premultiply-alpha atlas textures not supported in Linear color space!\n\nPlease\n"
|
"Warning: Premultiply-alpha atlas textures not supported in Linear color space!\n\nPlease\n"
|
||||||
@ -134,6 +135,10 @@ namespace Spine.Unity {
|
|||||||
public static void EnablePMAAtMaterial (Material material, bool enablePMA) {
|
public static void EnablePMAAtMaterial (Material material, bool enablePMA) {
|
||||||
if (material.HasProperty(STRAIGHT_ALPHA_PARAM_ID)) {
|
if (material.HasProperty(STRAIGHT_ALPHA_PARAM_ID)) {
|
||||||
material.SetInt(STRAIGHT_ALPHA_PARAM_ID, enablePMA ? 0 : 1);
|
material.SetInt(STRAIGHT_ALPHA_PARAM_ID, enablePMA ? 0 : 1);
|
||||||
|
if (enablePMA)
|
||||||
|
material.DisableKeyword(STRAIGHT_ALPHA_KEYWORD);
|
||||||
|
else
|
||||||
|
material.EnableKeyword(STRAIGHT_ALPHA_KEYWORD);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (enablePMA)
|
if (enablePMA)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user