Merge branch '3.8' into 4.0-beta

This commit is contained in:
Harald Csaszar 2020-11-16 21:31:57 +01:00
commit bf4df3b5f3
8 changed files with 386 additions and 371 deletions

View File

@ -375,6 +375,7 @@
* Now providing `BeforeApply` update callbacks at all skeleton animation components (`SkeletonAnimation`, `SkeletonMecanim` and `SkeletonGraphic`). * Now providing `BeforeApply` update callbacks at all skeleton animation components (`SkeletonAnimation`, `SkeletonMecanim` and `SkeletonGraphic`).
* Added `BoundingBoxFollowerGraphic` component. This class is a counterpart of `BoundingBoxFollower` that can be used with `SkeletonGraphic`. * Added `BoundingBoxFollowerGraphic` component. This class is a counterpart of `BoundingBoxFollower` that can be used with `SkeletonGraphic`.
* Added Inspector context menu functions `SkeletonRenderer - Add all BoundingBoxFollower GameObjects` and `SkeletonGraphic - Add all BoundingBoxFollowerGraphic GameObjects` that automatically generate bounding box follower GameObjects for every `BoundingBoxAttachment` for all skins of a skeleton. * Added Inspector context menu functions `SkeletonRenderer - Add all BoundingBoxFollower GameObjects` and `SkeletonGraphic - Add all BoundingBoxFollowerGraphic GameObjects` that automatically generate bounding box follower GameObjects for every `BoundingBoxAttachment` for all skins of a skeleton.
* `GetRemappedClone()` now provides an additional parameter `pivotShiftsMeshUVCoords` for `MeshAttachment` to prevent uv shifts at a non-central Sprite pivot. This parameter defaults to `true` to maintain previous behaviour.
* **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`.

View File

@ -94,13 +94,13 @@ namespace Spine.Unity.Examples {
// Let's do this for the visor. // Let's do this for the visor.
int visorSlotIndex = skeleton.FindSlotIndex(visorSlot); // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster. int visorSlotIndex = skeleton.FindSlotIndex(visorSlot); // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster.
Attachment templateAttachment = templateSkin.GetAttachment(visorSlotIndex, visorKey); // STEP 1.1 Attachment templateAttachment = templateSkin.GetAttachment(visorSlotIndex, visorKey); // STEP 1.1
Attachment newAttachment = templateAttachment.GetRemappedClone(visorSprite, sourceMaterial); // STEP 1.2 - 1.3 Attachment newAttachment = templateAttachment.GetRemappedClone(visorSprite, sourceMaterial, pivotShiftsMeshUVCoords : false); // STEP 1.2 - 1.3
customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment); // STEP 1.4 customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment); // STEP 1.4
// And now for the gun. // And now for the gun.
int gunSlotIndex = skeleton.FindSlotIndex(gunSlot); int gunSlotIndex = skeleton.FindSlotIndex(gunSlot);
Attachment templateGun = templateSkin.GetAttachment(gunSlotIndex, gunKey); // STEP 1.1 Attachment templateGun = templateSkin.GetAttachment(gunSlotIndex, gunKey); // STEP 1.1
Attachment newGun = templateGun.GetRemappedClone(gunSprite, sourceMaterial); // STEP 1.2 - 1.3 Attachment newGun = templateGun.GetRemappedClone(gunSprite, sourceMaterial, pivotShiftsMeshUVCoords: false); // STEP 1.2 - 1.3
if (newGun != null) customSkin.SetAttachment(gunSlotIndex, gunKey, newGun); // STEP 1.4 if (newGun != null) customSkin.SetAttachment(gunSlotIndex, gunKey, newGun); // STEP 1.4
// customSkin.RemoveAttachment(gunSlotIndex, gunKey); // To remove an item. // customSkin.RemoveAttachment(gunSlotIndex, gunKey); // To remove an item.

View File

@ -115,6 +115,8 @@ namespace Spine.Unity {
nameTable.Clear(); nameTable.Clear();
var skeleton = skeletonRenderer.skeleton; var skeleton = skeletonRenderer.skeleton;
if (skeleton == null)
return;
slot = skeleton.FindSlot(slotName); slot = skeleton.FindSlot(slotName);
int slotIndex = skeleton.FindSlotIndex(slotName); int slotIndex = skeleton.FindSlotIndex(slotName);

View File

@ -115,6 +115,8 @@ namespace Spine.Unity {
nameTable.Clear(); nameTable.Clear();
var skeleton = skeletonGraphic.Skeleton; var skeleton = skeletonGraphic.Skeleton;
if (skeleton == null)
return;
slot = skeleton.FindSlot(slotName); slot = skeleton.FindSlot(slotName);
int slotIndex = skeleton.FindSlotIndex(slotName); int slotIndex = skeleton.FindSlotIndex(slotName);

View File

@ -45,8 +45,18 @@ namespace Spine.Unity.AttachmentTools {
/// <param name="premultiplyAlpha">If <c>true</c>, a premultiply alpha clone of the original texture will be created.</param> /// <param name="premultiplyAlpha">If <c>true</c>, a premultiply alpha clone of the original texture will be created.</param>
/// <param name="cloneMeshAsLinked">If <c>true</c> MeshAttachments will be cloned as linked meshes and will inherit animation from the original attachment.</param> /// <param name="cloneMeshAsLinked">If <c>true</c> MeshAttachments will be cloned as linked meshes and will inherit animation from the original attachment.</param>
/// <param name="useOriginalRegionSize">If <c>true</c> the size of the original attachment will be followed, instead of using the Sprite size.</param> /// <param name="useOriginalRegionSize">If <c>true</c> the size of the original attachment will be followed, instead of using the Sprite size.</param>
public static Attachment GetRemappedClone (this Attachment o, Sprite sprite, Material sourceMaterial, bool premultiplyAlpha = true, bool cloneMeshAsLinked = true, bool useOriginalRegionSize = false) { /// <param name="pivotShiftsMeshUVCoords">If <c>true</c> and the original Attachment is a MeshAttachment, then
/// a non-central sprite pivot will shift uv coords in the opposite direction. Vertices will not be offset in
/// any case when the original Attachment is a MeshAttachment.</param>
public static Attachment GetRemappedClone (this Attachment o, Sprite sprite, Material sourceMaterial,
bool premultiplyAlpha = true, bool cloneMeshAsLinked = true, bool useOriginalRegionSize = false,
bool pivotShiftsMeshUVCoords = true) {
var atlasRegion = premultiplyAlpha ? sprite.ToAtlasRegionPMAClone(sourceMaterial) : sprite.ToAtlasRegion(new Material(sourceMaterial) { mainTexture = sprite.texture } ); var atlasRegion = premultiplyAlpha ? sprite.ToAtlasRegionPMAClone(sourceMaterial) : sprite.ToAtlasRegion(new Material(sourceMaterial) { mainTexture = sprite.texture } );
if (!pivotShiftsMeshUVCoords && o is MeshAttachment) {
// prevent non-central sprite pivot setting offsetX/Y and shifting uv coords out of mesh bounds
atlasRegion.offsetX = 0;
atlasRegion.offsetY = 0;
}
return o.GetRemappedClone(atlasRegion, cloneMeshAsLinked, useOriginalRegionSize, 1f/sprite.pixelsPerUnit); return o.GetRemappedClone(atlasRegion, cloneMeshAsLinked, useOriginalRegionSize, 1f/sprite.pixelsPerUnit);
} }

View File

@ -1,195 +1,195 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions. * Last updated January 1, 2020. Replaces all prior versions.
* *
* Copyright (c) 2013-2020, Esoteric Software LLC * Copyright (c) 2013-2020, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively, * or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * 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 * (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. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
namespace Spine { namespace Spine {
public struct VertexPositionColorTextureColor : IVertexType { public struct VertexPositionColorTextureColor : IVertexType {
public Vector3 Position; public Vector3 Position;
public Color Color; public Color Color;
public Vector2 TextureCoordinate; public Vector2 TextureCoordinate;
public Color Color2; public Color Color2;
public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration
( (
new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0), new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
new VertexElement(12, VertexElementFormat.Color, VertexElementUsage.Color, 0), new VertexElement(12, VertexElementFormat.Color, VertexElementUsage.Color, 0),
new VertexElement(16, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0), new VertexElement(16, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
new VertexElement(24, VertexElementFormat.Color, VertexElementUsage.Color, 1) new VertexElement(24, VertexElementFormat.Color, VertexElementUsage.Color, 1)
); );
VertexDeclaration IVertexType.VertexDeclaration { VertexDeclaration IVertexType.VertexDeclaration {
get { return VertexDeclaration; } get { return VertexDeclaration; }
} }
} }
// #region License // #region License
// /* // /*
// Microsoft Public License (Ms-PL) // Microsoft Public License (Ms-PL)
// MonoGame - Copyright <20> 2009 The MonoGame Team // MonoGame - Copyright <20> 2009 The MonoGame Team
// //
// All rights reserved. // All rights reserved.
// //
// This license governs use of the accompanying software. If you use the software, you accept this license. If you do not // This license governs use of the accompanying software. If you use the software, you accept this license. If you do not
// accept the license, do not use the software. // accept the license, do not use the software.
// //
// 1. Definitions // 1. Definitions
// The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under // The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under
// U.S. copyright law. // U.S. copyright law.
// //
// A "contribution" is the original software, or any additions or changes to the software. // A "contribution" is the original software, or any additions or changes to the software.
// A "contributor" is any person that distributes its contribution under this license. // A "contributor" is any person that distributes its contribution under this license.
// "Licensed patents" are a contributor's patent claims that read directly on its contribution. // "Licensed patents" are a contributor's patent claims that read directly on its contribution.
// //
// 2. Grant of Rights // 2. Grant of Rights
// (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, // (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
// each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. // each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
// (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, // (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
// each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. // each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
// //
// 3. Conditions and Limitations // 3. Conditions and Limitations
// (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. // (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
// (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, // (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software,
// your patent license from such contributor to the software ends automatically. // your patent license from such contributor to the software ends automatically.
// (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution // (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution
// notices that are present in the software. // notices that are present in the software.
// (D) If you distribute any portion of the software in source code form, you may do so only under this license by including // (D) If you distribute any portion of the software in source code form, you may do so only under this license by including
// a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object // a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object
// code form, you may only do so under a license that complies with this license. // code form, you may only do so under a license that complies with this license.
// (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees // (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees
// or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent // or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent
// permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular // permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular
// purpose and non-infringement. // purpose and non-infringement.
// */ // */
// #endregion License // #endregion License
// //
/// <summary>Draws batched meshes.</summary> /// <summary>Draws batched meshes.</summary>
public class MeshBatcher { public class MeshBatcher {
private readonly List<MeshItem> items; private readonly List<MeshItem> items;
private readonly Queue<MeshItem> freeItems; private readonly Queue<MeshItem> freeItems;
private VertexPositionColorTextureColor[] vertexArray = { }; private VertexPositionColorTextureColor[] vertexArray = { };
private short[] triangles = { }; private short[] triangles = { };
public MeshBatcher () { public MeshBatcher () {
items = new List<MeshItem>(256); items = new List<MeshItem>(256);
freeItems = new Queue<MeshItem>(256); freeItems = new Queue<MeshItem>(256);
EnsureCapacity(256, 512); EnsureCapacity(256, 512);
} }
/// <summary>Returns a pooled MeshItem.</summary> /// <summary>Returns a pooled MeshItem.</summary>
public MeshItem NextItem (int vertexCount, int triangleCount) { public MeshItem NextItem (int vertexCount, int triangleCount) {
MeshItem item = freeItems.Count > 0 ? freeItems.Dequeue() : new MeshItem(); MeshItem item = freeItems.Count > 0 ? freeItems.Dequeue() : new MeshItem();
if (item.vertices.Length < vertexCount) item.vertices = new VertexPositionColorTextureColor[vertexCount]; if (item.vertices.Length < vertexCount) item.vertices = new VertexPositionColorTextureColor[vertexCount];
if (item.triangles.Length < triangleCount) item.triangles = new int[triangleCount]; if (item.triangles.Length < triangleCount) item.triangles = new int[triangleCount];
item.vertexCount = vertexCount; item.vertexCount = vertexCount;
item.triangleCount = triangleCount; item.triangleCount = triangleCount;
items.Add(item); items.Add(item);
return item; return item;
} }
private void EnsureCapacity (int vertexCount, int triangleCount) { private void EnsureCapacity (int vertexCount, int triangleCount) {
if (vertexArray.Length < vertexCount) vertexArray = new VertexPositionColorTextureColor[vertexCount]; if (vertexArray.Length < vertexCount) vertexArray = new VertexPositionColorTextureColor[vertexCount];
if (triangles.Length < triangleCount) triangles = new short[triangleCount]; if (triangles.Length < triangleCount) triangles = new short[triangleCount];
} }
public void Draw (GraphicsDevice device) { public void Draw (GraphicsDevice device) {
if (items.Count == 0) return; if (items.Count == 0) return;
int itemCount = items.Count; int itemCount = items.Count;
int vertexCount = 0, triangleCount = 0; int vertexCount = 0, triangleCount = 0;
for (int i = 0; i < itemCount; i++) { for (int i = 0; i < itemCount; i++) {
MeshItem item = items[i]; MeshItem item = items[i];
vertexCount += item.vertexCount; vertexCount += item.vertexCount;
triangleCount += item.triangleCount; triangleCount += item.triangleCount;
} }
EnsureCapacity(vertexCount, triangleCount); EnsureCapacity(vertexCount, triangleCount);
vertexCount = 0; vertexCount = 0;
triangleCount = 0; triangleCount = 0;
Texture2D lastTexture = null; Texture2D lastTexture = null;
for (int i = 0; i < itemCount; i++) { for (int i = 0; i < itemCount; i++) {
MeshItem item = items[i]; MeshItem item = items[i];
int itemVertexCount = item.vertexCount; int itemVertexCount = item.vertexCount;
if (item.texture != lastTexture || vertexCount + itemVertexCount > short.MaxValue) { if (item.texture != lastTexture || vertexCount + itemVertexCount > short.MaxValue) {
FlushVertexArray(device, vertexCount, triangleCount); FlushVertexArray(device, vertexCount, triangleCount);
vertexCount = 0; vertexCount = 0;
triangleCount = 0; triangleCount = 0;
lastTexture = item.texture; lastTexture = item.texture;
device.Textures[0] = lastTexture; device.Textures[0] = lastTexture;
if (item.textureLayers != null) { if (item.textureLayers != null) {
for (int layer = 1; layer < item.textureLayers.Length; ++layer) for (int layer = 1; layer < item.textureLayers.Length; ++layer)
device.Textures[layer] = item.textureLayers[layer]; device.Textures[layer] = item.textureLayers[layer];
} }
} }
int[] itemTriangles = item.triangles; int[] itemTriangles = item.triangles;
int itemTriangleCount = item.triangleCount; int itemTriangleCount = item.triangleCount;
for (int ii = 0, t = triangleCount; ii < itemTriangleCount; ii++, t++) for (int ii = 0, t = triangleCount; ii < itemTriangleCount; ii++, t++)
triangles[t] = (short)(itemTriangles[ii] + vertexCount); triangles[t] = (short)(itemTriangles[ii] + vertexCount);
triangleCount += itemTriangleCount; triangleCount += itemTriangleCount;
Array.Copy(item.vertices, 0, vertexArray, vertexCount, itemVertexCount); Array.Copy(item.vertices, 0, vertexArray, vertexCount, itemVertexCount);
vertexCount += itemVertexCount; vertexCount += itemVertexCount;
} }
FlushVertexArray(device, vertexCount, triangleCount); FlushVertexArray(device, vertexCount, triangleCount);
} }
public void AfterLastDrawPass () { public void AfterLastDrawPass () {
int itemCount = items.Count; int itemCount = items.Count;
for (int i = 0; i < itemCount; i++) { for (int i = 0; i < itemCount; i++) {
var item = items[i]; var item = items[i];
item.texture = null; item.texture = null;
freeItems.Enqueue(item); freeItems.Enqueue(item);
} }
items.Clear(); items.Clear();
} }
private void FlushVertexArray (GraphicsDevice device, int vertexCount, int triangleCount) { private void FlushVertexArray (GraphicsDevice device, int vertexCount, int triangleCount) {
if (vertexCount == 0) return; if (vertexCount == 0) return;
device.DrawUserIndexedPrimitives( device.DrawUserIndexedPrimitives(
PrimitiveType.TriangleList, PrimitiveType.TriangleList,
vertexArray, 0, vertexCount, vertexArray, 0, vertexCount,
triangles, 0, triangleCount / 3, triangles, 0, triangleCount / 3,
VertexPositionColorTextureColor.VertexDeclaration); VertexPositionColorTextureColor.VertexDeclaration);
} }
} }
public class MeshItem { public class MeshItem {
public Texture2D texture = null; public Texture2D texture = null;
public Texture2D[] textureLayers = null; public Texture2D[] textureLayers = null;
public int vertexCount, triangleCount; public int vertexCount, triangleCount;
public VertexPositionColorTextureColor[] vertices = { }; public VertexPositionColorTextureColor[] vertices = { };
public int[] triangles = { }; public int[] triangles = { };
} }
} }

View File

@ -1,79 +1,79 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions. * Last updated January 1, 2020. Replaces all prior versions.
* *
* Copyright (c) 2013-2020, Esoteric Software LLC * Copyright (c) 2013-2020, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively, * or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * 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 * (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. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System; using System;
using System.IO; using System.IO;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
#if WINDOWS_STOREAPP #if WINDOWS_STOREAPP
using System.Threading.Tasks; using System.Threading.Tasks;
using Windows.Storage; using Windows.Storage;
#endif #endif
namespace Spine { namespace Spine {
static public class Util { static public class Util {
#if WINDOWS_STOREAPP #if WINDOWS_STOREAPP
private static async Task<Texture2D> LoadFile(GraphicsDevice device, String path) { private static async Task<Texture2D> LoadFile(GraphicsDevice device, String path) {
var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
var file = await folder.GetFileAsync(path).AsTask().ConfigureAwait(false); var file = await folder.GetFileAsync(path).AsTask().ConfigureAwait(false);
try { try {
return Util.LoadTexture(device, await file.OpenStreamForReadAsync().ConfigureAwait(false)); return Util.LoadTexture(device, await file.OpenStreamForReadAsync().ConfigureAwait(false));
} catch (Exception ex) { } catch (Exception ex) {
throw new Exception("Error reading texture file: " + path, ex); throw new Exception("Error reading texture file: " + path, ex);
} }
} }
static public Texture2D LoadTexture (GraphicsDevice device, String path) { static public Texture2D LoadTexture (GraphicsDevice device, String path) {
return LoadFile(device, path).Result; return LoadFile(device, path).Result;
} }
#else #else
static public Texture2D LoadTexture (GraphicsDevice device, String path) { static public Texture2D LoadTexture (GraphicsDevice device, String path) {
#if WINDOWS_PHONE #if WINDOWS_PHONE
Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path); Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path);
using (Stream input = stream) { using (Stream input = stream) {
#else #else
using (Stream input = new FileStream(path, FileMode.Open, FileAccess.Read)) { using (Stream input = new FileStream(path, FileMode.Open, FileAccess.Read)) {
#endif #endif
try { try {
return Util.LoadTexture(device, input); return Util.LoadTexture(device, input);
} catch (Exception ex) { } catch (Exception ex) {
throw new Exception("Error reading texture file: " + path, ex); throw new Exception("Error reading texture file: " + path, ex);
} }
} }
} }
#endif #endif
static public Texture2D LoadTexture (GraphicsDevice device, Stream input) { static public Texture2D LoadTexture (GraphicsDevice device, Stream input) {
return Texture2D.FromStream(device, input); return Texture2D.FromStream(device, input);
} }
} }
} }

View File

@ -1,94 +1,94 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions. * Last updated January 1, 2020. Replaces all prior versions.
* *
* Copyright (c) 2013-2020, Esoteric Software LLC * Copyright (c) 2013-2020, Esoteric Software LLC
* *
* Integration of the Spine Runtimes into software or otherwise creating * Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and * derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement: * conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license * http://esotericsoftware.com/spine-editor-license
* *
* Otherwise, it is permitted to integrate the Spine Runtimes into software * Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively, * or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own * "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must * Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice. * include this license and copyright notice.
* *
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * 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 * (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. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
using System; using System;
using System.IO; using System.IO;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
namespace Spine { namespace Spine {
public class XnaTextureLoader : TextureLoader { public class XnaTextureLoader : TextureLoader {
GraphicsDevice device; GraphicsDevice device;
string[] textureLayerSuffixes = null; string[] textureLayerSuffixes = null;
/// <summary> /// <summary>
/// Constructor. /// Constructor.
/// </summary> /// </summary>
/// <param name="device">The graphics device to be used.</param> /// <param name="device">The graphics device to be used.</param>
/// <param name="loadMultipleTextureLayers">If <c>true</c> multiple textures layers /// <param name="loadMultipleTextureLayers">If <c>true</c> multiple textures layers
/// (e.g. a diffuse/albedo texture and a normal map) are loaded instead of a single texture. /// (e.g. a diffuse/albedo texture and a normal map) are loaded instead of a single texture.
/// Names are constructed based on suffixes added according to the <c>textureSuffixes</c> parameter.</param> /// Names are constructed based on suffixes added according to the <c>textureSuffixes</c> parameter.</param>
/// <param name="textureSuffixes">If <c>loadMultipleTextureLayers</c> is <c>true</c>, the strings of this array /// <param name="textureSuffixes">If <c>loadMultipleTextureLayers</c> is <c>true</c>, the strings of this array
/// define the path name suffix of each layer to be loaded. Array size must be equal to the number of layers to be loaded. /// define the path name suffix of each layer to be loaded. Array size must be equal to the number of layers to be loaded.
/// The first array entry is the suffix to be <c>replaced</c> (e.g. "_albedo", or "" for a first layer without a suffix), /// The first array entry is the suffix to be <c>replaced</c> (e.g. "_albedo", or "" for a first layer without a suffix),
/// subsequent array entries contain the suffix to replace the first entry with (e.g. "_normals"). /// subsequent array entries contain the suffix to replace the first entry with (e.g. "_normals").
/// ///
/// An example would be: /// An example would be:
/// <code>new string[] { "", "_normals" }</code> for loading a base diffuse texture named "skeletonname.png" and /// <code>new string[] { "", "_normals" }</code> for loading a base diffuse texture named "skeletonname.png" and
/// a normalmap named "skeletonname_normals.png".</param> /// a normalmap named "skeletonname_normals.png".</param>
public XnaTextureLoader (GraphicsDevice device, bool loadMultipleTextureLayers = false, string[] textureSuffixes = null) { public XnaTextureLoader (GraphicsDevice device, bool loadMultipleTextureLayers = false, string[] textureSuffixes = null) {
this.device = device; this.device = device;
if (loadMultipleTextureLayers) if (loadMultipleTextureLayers)
this.textureLayerSuffixes = textureSuffixes; this.textureLayerSuffixes = textureSuffixes;
} }
public void Load (AtlasPage page, String path) { public void Load (AtlasPage page, String path) {
Texture2D texture = Util.LoadTexture(device, path); Texture2D texture = Util.LoadTexture(device, path);
page.width = texture.Width; page.width = texture.Width;
page.height = texture.Height; page.height = texture.Height;
if (textureLayerSuffixes == null) { if (textureLayerSuffixes == null) {
page.rendererObject = texture; page.rendererObject = texture;
} }
else { else {
Texture2D[] textureLayersArray = new Texture2D[textureLayerSuffixes.Length]; Texture2D[] textureLayersArray = new Texture2D[textureLayerSuffixes.Length];
textureLayersArray[0] = texture; textureLayersArray[0] = texture;
for (int layer = 1; layer < textureLayersArray.Length; ++layer) { for (int layer = 1; layer < textureLayersArray.Length; ++layer) {
string layerPath = GetLayerName(path, textureLayerSuffixes[0], textureLayerSuffixes[layer]); string layerPath = GetLayerName(path, textureLayerSuffixes[0], textureLayerSuffixes[layer]);
textureLayersArray[layer] = Util.LoadTexture(device, layerPath); textureLayersArray[layer] = Util.LoadTexture(device, layerPath);
} }
page.rendererObject = textureLayersArray; page.rendererObject = textureLayersArray;
} }
} }
public void Unload (Object texture) { public void Unload (Object texture) {
((Texture2D)texture).Dispose(); ((Texture2D)texture).Dispose();
} }
private string GetLayerName (string firstLayerPath, string firstLayerSuffix, string replacementSuffix) { private string GetLayerName (string firstLayerPath, string firstLayerSuffix, string replacementSuffix) {
int suffixLocation = firstLayerPath.LastIndexOf(firstLayerSuffix + "."); int suffixLocation = firstLayerPath.LastIndexOf(firstLayerSuffix + ".");
if (suffixLocation == -1) { if (suffixLocation == -1) {
throw new Exception(string.Concat("Error composing texture layer name: first texture layer name '", firstLayerPath, throw new Exception(string.Concat("Error composing texture layer name: first texture layer name '", firstLayerPath,
"' does not contain suffix to be replaced: '", firstLayerSuffix, "'")); "' does not contain suffix to be replaced: '", firstLayerSuffix, "'"));
} }
return firstLayerPath.Remove(suffixLocation, firstLayerSuffix.Length).Insert(suffixLocation, replacementSuffix); return firstLayerPath.Remove(suffixLocation, firstLayerSuffix.Length).Insert(suffixLocation, replacementSuffix);
} }
} }
} }