diff --git a/CHANGELOG.md b/CHANGELOG.md
index c63f22cc6..1182315d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -375,6 +375,7 @@
* 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 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**
* `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`.
diff --git a/spine-unity/Assets/Spine Examples/Scripts/MixAndMatch.cs b/spine-unity/Assets/Spine Examples/Scripts/MixAndMatch.cs
index 3d6286301..580d8aa61 100644
--- a/spine-unity/Assets/Spine Examples/Scripts/MixAndMatch.cs
+++ b/spine-unity/Assets/Spine Examples/Scripts/MixAndMatch.cs
@@ -94,13 +94,13 @@ namespace Spine.Unity.Examples {
// 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.
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
// And now for the gun.
int gunSlotIndex = skeleton.FindSlotIndex(gunSlot);
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
// customSkin.RemoveAttachment(gunSlotIndex, gunKey); // To remove an item.
diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollower.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollower.cs
index 82aae46da..f841a02ef 100644
--- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollower.cs
+++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollower.cs
@@ -115,6 +115,8 @@ namespace Spine.Unity {
nameTable.Clear();
var skeleton = skeletonRenderer.skeleton;
+ if (skeleton == null)
+ return;
slot = skeleton.FindSlot(slotName);
int slotIndex = skeleton.FindSlotIndex(slotName);
diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs
index 106a9810d..674a0fb04 100644
--- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs
+++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs
@@ -115,6 +115,8 @@ namespace Spine.Unity {
nameTable.Clear();
var skeleton = skeletonGraphic.Skeleton;
+ if (skeleton == null)
+ return;
slot = skeleton.FindSlot(slotName);
int slotIndex = skeleton.FindSlotIndex(slotName);
diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs
index f122df3ba..8657ea69d 100644
--- a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs
+++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs
@@ -45,8 +45,18 @@ namespace Spine.Unity.AttachmentTools {
/// If true, a premultiply alpha clone of the original texture will be created.
/// If true MeshAttachments will be cloned as linked meshes and will inherit animation from the original attachment.
/// If true the size of the original attachment will be followed, instead of using the Sprite size.
- public static Attachment GetRemappedClone (this Attachment o, Sprite sprite, Material sourceMaterial, bool premultiplyAlpha = true, bool cloneMeshAsLinked = true, bool useOriginalRegionSize = false) {
+ /// If true 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.
+ 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 } );
+ 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);
}
diff --git a/spine-xna/src/MeshBatcher.cs b/spine-xna/src/MeshBatcher.cs
index 5a81d2575..bcca36aeb 100644
--- a/spine-xna/src/MeshBatcher.cs
+++ b/spine-xna/src/MeshBatcher.cs
@@ -1,195 +1,195 @@
-/******************************************************************************
- * 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 Microsoft.Xna.Framework.Graphics;
-using Microsoft.Xna.Framework;
-
-namespace Spine {
- public struct VertexPositionColorTextureColor : IVertexType {
- public Vector3 Position;
- public Color Color;
- public Vector2 TextureCoordinate;
- public Color Color2;
-
- public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration
- (
- new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
- new VertexElement(12, VertexElementFormat.Color, VertexElementUsage.Color, 0),
- new VertexElement(16, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
- new VertexElement(24, VertexElementFormat.Color, VertexElementUsage.Color, 1)
- );
-
- VertexDeclaration IVertexType.VertexDeclaration {
- get { return VertexDeclaration; }
- }
- }
-
- // #region License
- // /*
- // Microsoft Public License (Ms-PL)
- // MonoGame - Copyright � 2009 The MonoGame Team
- //
- // All rights reserved.
- //
- // 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.
- //
- // 1. Definitions
- // The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under
- // U.S. copyright law.
- //
- // 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.
- // "Licensed patents" are a contributor's patent claims that read directly on its contribution.
- //
- // 2. Grant of Rights
- // (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.
- // (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.
- //
- // 3. Conditions and Limitations
- // (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,
- // 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
- // 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
- // 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.
- // (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
- // permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular
- // purpose and non-infringement.
- // */
- // #endregion License
- //
-
- /// Draws batched meshes.
- public class MeshBatcher {
- private readonly List items;
- private readonly Queue freeItems;
- private VertexPositionColorTextureColor[] vertexArray = { };
- private short[] triangles = { };
-
- public MeshBatcher () {
- items = new List(256);
- freeItems = new Queue(256);
- EnsureCapacity(256, 512);
- }
-
- /// Returns a pooled MeshItem.
- public MeshItem NextItem (int vertexCount, int triangleCount) {
- MeshItem item = freeItems.Count > 0 ? freeItems.Dequeue() : new MeshItem();
- if (item.vertices.Length < vertexCount) item.vertices = new VertexPositionColorTextureColor[vertexCount];
- if (item.triangles.Length < triangleCount) item.triangles = new int[triangleCount];
- item.vertexCount = vertexCount;
- item.triangleCount = triangleCount;
- items.Add(item);
- return item;
- }
-
- private void EnsureCapacity (int vertexCount, int triangleCount) {
- if (vertexArray.Length < vertexCount) vertexArray = new VertexPositionColorTextureColor[vertexCount];
- if (triangles.Length < triangleCount) triangles = new short[triangleCount];
- }
-
- public void Draw (GraphicsDevice device) {
- if (items.Count == 0) return;
-
- int itemCount = items.Count;
- int vertexCount = 0, triangleCount = 0;
- for (int i = 0; i < itemCount; i++) {
- MeshItem item = items[i];
- vertexCount += item.vertexCount;
- triangleCount += item.triangleCount;
- }
- EnsureCapacity(vertexCount, triangleCount);
-
- vertexCount = 0;
- triangleCount = 0;
- Texture2D lastTexture = null;
- for (int i = 0; i < itemCount; i++) {
- MeshItem item = items[i];
- int itemVertexCount = item.vertexCount;
-
- if (item.texture != lastTexture || vertexCount + itemVertexCount > short.MaxValue) {
- FlushVertexArray(device, vertexCount, triangleCount);
- vertexCount = 0;
- triangleCount = 0;
- lastTexture = item.texture;
- device.Textures[0] = lastTexture;
- if (item.textureLayers != null) {
- for (int layer = 1; layer < item.textureLayers.Length; ++layer)
- device.Textures[layer] = item.textureLayers[layer];
- }
- }
-
- int[] itemTriangles = item.triangles;
- int itemTriangleCount = item.triangleCount;
- for (int ii = 0, t = triangleCount; ii < itemTriangleCount; ii++, t++)
- triangles[t] = (short)(itemTriangles[ii] + vertexCount);
- triangleCount += itemTriangleCount;
-
- Array.Copy(item.vertices, 0, vertexArray, vertexCount, itemVertexCount);
- vertexCount += itemVertexCount;
- }
- FlushVertexArray(device, vertexCount, triangleCount);
- }
-
- public void AfterLastDrawPass () {
- int itemCount = items.Count;
- for (int i = 0; i < itemCount; i++) {
- var item = items[i];
- item.texture = null;
- freeItems.Enqueue(item);
- }
- items.Clear();
- }
-
- private void FlushVertexArray (GraphicsDevice device, int vertexCount, int triangleCount) {
- if (vertexCount == 0) return;
- device.DrawUserIndexedPrimitives(
- PrimitiveType.TriangleList,
- vertexArray, 0, vertexCount,
- triangles, 0, triangleCount / 3,
- VertexPositionColorTextureColor.VertexDeclaration);
- }
- }
-
- public class MeshItem {
- public Texture2D texture = null;
- public Texture2D[] textureLayers = null;
- public int vertexCount, triangleCount;
- public VertexPositionColorTextureColor[] vertices = { };
- public int[] triangles = { };
- }
-}
+/******************************************************************************
+ * 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 Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework;
+
+namespace Spine {
+ public struct VertexPositionColorTextureColor : IVertexType {
+ public Vector3 Position;
+ public Color Color;
+ public Vector2 TextureCoordinate;
+ public Color Color2;
+
+ public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration
+ (
+ new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
+ new VertexElement(12, VertexElementFormat.Color, VertexElementUsage.Color, 0),
+ new VertexElement(16, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
+ new VertexElement(24, VertexElementFormat.Color, VertexElementUsage.Color, 1)
+ );
+
+ VertexDeclaration IVertexType.VertexDeclaration {
+ get { return VertexDeclaration; }
+ }
+ }
+
+ // #region License
+ // /*
+ // Microsoft Public License (Ms-PL)
+ // MonoGame - Copyright � 2009 The MonoGame Team
+ //
+ // All rights reserved.
+ //
+ // 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.
+ //
+ // 1. Definitions
+ // The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under
+ // U.S. copyright law.
+ //
+ // 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.
+ // "Licensed patents" are a contributor's patent claims that read directly on its contribution.
+ //
+ // 2. Grant of Rights
+ // (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.
+ // (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.
+ //
+ // 3. Conditions and Limitations
+ // (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,
+ // 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
+ // 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
+ // 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.
+ // (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
+ // permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular
+ // purpose and non-infringement.
+ // */
+ // #endregion License
+ //
+
+ /// Draws batched meshes.
+ public class MeshBatcher {
+ private readonly List items;
+ private readonly Queue freeItems;
+ private VertexPositionColorTextureColor[] vertexArray = { };
+ private short[] triangles = { };
+
+ public MeshBatcher () {
+ items = new List(256);
+ freeItems = new Queue(256);
+ EnsureCapacity(256, 512);
+ }
+
+ /// Returns a pooled MeshItem.
+ public MeshItem NextItem (int vertexCount, int triangleCount) {
+ MeshItem item = freeItems.Count > 0 ? freeItems.Dequeue() : new MeshItem();
+ if (item.vertices.Length < vertexCount) item.vertices = new VertexPositionColorTextureColor[vertexCount];
+ if (item.triangles.Length < triangleCount) item.triangles = new int[triangleCount];
+ item.vertexCount = vertexCount;
+ item.triangleCount = triangleCount;
+ items.Add(item);
+ return item;
+ }
+
+ private void EnsureCapacity (int vertexCount, int triangleCount) {
+ if (vertexArray.Length < vertexCount) vertexArray = new VertexPositionColorTextureColor[vertexCount];
+ if (triangles.Length < triangleCount) triangles = new short[triangleCount];
+ }
+
+ public void Draw (GraphicsDevice device) {
+ if (items.Count == 0) return;
+
+ int itemCount = items.Count;
+ int vertexCount = 0, triangleCount = 0;
+ for (int i = 0; i < itemCount; i++) {
+ MeshItem item = items[i];
+ vertexCount += item.vertexCount;
+ triangleCount += item.triangleCount;
+ }
+ EnsureCapacity(vertexCount, triangleCount);
+
+ vertexCount = 0;
+ triangleCount = 0;
+ Texture2D lastTexture = null;
+ for (int i = 0; i < itemCount; i++) {
+ MeshItem item = items[i];
+ int itemVertexCount = item.vertexCount;
+
+ if (item.texture != lastTexture || vertexCount + itemVertexCount > short.MaxValue) {
+ FlushVertexArray(device, vertexCount, triangleCount);
+ vertexCount = 0;
+ triangleCount = 0;
+ lastTexture = item.texture;
+ device.Textures[0] = lastTexture;
+ if (item.textureLayers != null) {
+ for (int layer = 1; layer < item.textureLayers.Length; ++layer)
+ device.Textures[layer] = item.textureLayers[layer];
+ }
+ }
+
+ int[] itemTriangles = item.triangles;
+ int itemTriangleCount = item.triangleCount;
+ for (int ii = 0, t = triangleCount; ii < itemTriangleCount; ii++, t++)
+ triangles[t] = (short)(itemTriangles[ii] + vertexCount);
+ triangleCount += itemTriangleCount;
+
+ Array.Copy(item.vertices, 0, vertexArray, vertexCount, itemVertexCount);
+ vertexCount += itemVertexCount;
+ }
+ FlushVertexArray(device, vertexCount, triangleCount);
+ }
+
+ public void AfterLastDrawPass () {
+ int itemCount = items.Count;
+ for (int i = 0; i < itemCount; i++) {
+ var item = items[i];
+ item.texture = null;
+ freeItems.Enqueue(item);
+ }
+ items.Clear();
+ }
+
+ private void FlushVertexArray (GraphicsDevice device, int vertexCount, int triangleCount) {
+ if (vertexCount == 0) return;
+ device.DrawUserIndexedPrimitives(
+ PrimitiveType.TriangleList,
+ vertexArray, 0, vertexCount,
+ triangles, 0, triangleCount / 3,
+ VertexPositionColorTextureColor.VertexDeclaration);
+ }
+ }
+
+ public class MeshItem {
+ public Texture2D texture = null;
+ public Texture2D[] textureLayers = null;
+ public int vertexCount, triangleCount;
+ public VertexPositionColorTextureColor[] vertices = { };
+ public int[] triangles = { };
+ }
+}
diff --git a/spine-xna/src/Util.cs b/spine-xna/src/Util.cs
index 54d495ac5..5c6479ad8 100644
--- a/spine-xna/src/Util.cs
+++ b/spine-xna/src/Util.cs
@@ -1,79 +1,79 @@
-/******************************************************************************
- * 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.IO;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Graphics;
-
-#if WINDOWS_STOREAPP
-using System.Threading.Tasks;
-using Windows.Storage;
-#endif
-
-namespace Spine {
-
- static public class Util {
-#if WINDOWS_STOREAPP
- private static async Task LoadFile(GraphicsDevice device, String path) {
- var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
- var file = await folder.GetFileAsync(path).AsTask().ConfigureAwait(false);
- try {
- return Util.LoadTexture(device, await file.OpenStreamForReadAsync().ConfigureAwait(false));
- } catch (Exception ex) {
- throw new Exception("Error reading texture file: " + path, ex);
- }
- }
-
- static public Texture2D LoadTexture (GraphicsDevice device, String path) {
- return LoadFile(device, path).Result;
- }
-#else
- static public Texture2D LoadTexture (GraphicsDevice device, String path) {
-
-#if WINDOWS_PHONE
- Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path);
- using (Stream input = stream) {
-#else
- using (Stream input = new FileStream(path, FileMode.Open, FileAccess.Read)) {
-#endif
- try {
- return Util.LoadTexture(device, input);
- } catch (Exception ex) {
- throw new Exception("Error reading texture file: " + path, ex);
- }
- }
- }
-#endif
-
- static public Texture2D LoadTexture (GraphicsDevice device, Stream input) {
- return Texture2D.FromStream(device, input);
- }
- }
-}
+/******************************************************************************
+ * 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.IO;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+#if WINDOWS_STOREAPP
+using System.Threading.Tasks;
+using Windows.Storage;
+#endif
+
+namespace Spine {
+
+ static public class Util {
+#if WINDOWS_STOREAPP
+ private static async Task LoadFile(GraphicsDevice device, String path) {
+ var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
+ var file = await folder.GetFileAsync(path).AsTask().ConfigureAwait(false);
+ try {
+ return Util.LoadTexture(device, await file.OpenStreamForReadAsync().ConfigureAwait(false));
+ } catch (Exception ex) {
+ throw new Exception("Error reading texture file: " + path, ex);
+ }
+ }
+
+ static public Texture2D LoadTexture (GraphicsDevice device, String path) {
+ return LoadFile(device, path).Result;
+ }
+#else
+ static public Texture2D LoadTexture (GraphicsDevice device, String path) {
+
+#if WINDOWS_PHONE
+ Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path);
+ using (Stream input = stream) {
+#else
+ using (Stream input = new FileStream(path, FileMode.Open, FileAccess.Read)) {
+#endif
+ try {
+ return Util.LoadTexture(device, input);
+ } catch (Exception ex) {
+ throw new Exception("Error reading texture file: " + path, ex);
+ }
+ }
+ }
+#endif
+
+ static public Texture2D LoadTexture (GraphicsDevice device, Stream input) {
+ return Texture2D.FromStream(device, input);
+ }
+ }
+}
diff --git a/spine-xna/src/XnaTextureLoader.cs b/spine-xna/src/XnaTextureLoader.cs
index f31921cba..3aa77e5c1 100644
--- a/spine-xna/src/XnaTextureLoader.cs
+++ b/spine-xna/src/XnaTextureLoader.cs
@@ -1,94 +1,94 @@
-/******************************************************************************
- * 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.IO;
-using Microsoft.Xna.Framework;
-using Microsoft.Xna.Framework.Graphics;
-
-namespace Spine {
- public class XnaTextureLoader : TextureLoader {
- GraphicsDevice device;
- string[] textureLayerSuffixes = null;
-
- ///
- /// Constructor.
- ///
- /// The graphics device to be used.
- /// If true multiple textures layers
- /// (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 textureSuffixes parameter.
- /// If loadMultipleTextureLayers is true, 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.
- /// The first array entry is the suffix to be replaced (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").
- ///
- /// An example would be:
- /// new string[] { "", "_normals" } for loading a base diffuse texture named "skeletonname.png" and
- /// a normalmap named "skeletonname_normals.png".
- public XnaTextureLoader (GraphicsDevice device, bool loadMultipleTextureLayers = false, string[] textureSuffixes = null) {
- this.device = device;
- if (loadMultipleTextureLayers)
- this.textureLayerSuffixes = textureSuffixes;
- }
-
- public void Load (AtlasPage page, String path) {
- Texture2D texture = Util.LoadTexture(device, path);
- page.width = texture.Width;
- page.height = texture.Height;
-
- if (textureLayerSuffixes == null) {
- page.rendererObject = texture;
- }
- else {
- Texture2D[] textureLayersArray = new Texture2D[textureLayerSuffixes.Length];
- textureLayersArray[0] = texture;
- for (int layer = 1; layer < textureLayersArray.Length; ++layer) {
- string layerPath = GetLayerName(path, textureLayerSuffixes[0], textureLayerSuffixes[layer]);
- textureLayersArray[layer] = Util.LoadTexture(device, layerPath);
- }
- page.rendererObject = textureLayersArray;
- }
- }
-
- public void Unload (Object texture) {
- ((Texture2D)texture).Dispose();
- }
-
- private string GetLayerName (string firstLayerPath, string firstLayerSuffix, string replacementSuffix) {
-
- int suffixLocation = firstLayerPath.LastIndexOf(firstLayerSuffix + ".");
- if (suffixLocation == -1) {
- throw new Exception(string.Concat("Error composing texture layer name: first texture layer name '", firstLayerPath,
- "' does not contain suffix to be replaced: '", firstLayerSuffix, "'"));
- }
- return firstLayerPath.Remove(suffixLocation, firstLayerSuffix.Length).Insert(suffixLocation, replacementSuffix);
- }
- }
-}
+/******************************************************************************
+ * 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.IO;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Spine {
+ public class XnaTextureLoader : TextureLoader {
+ GraphicsDevice device;
+ string[] textureLayerSuffixes = null;
+
+ ///
+ /// Constructor.
+ ///
+ /// The graphics device to be used.
+ /// If true multiple textures layers
+ /// (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 textureSuffixes parameter.
+ /// If loadMultipleTextureLayers is true, 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.
+ /// The first array entry is the suffix to be replaced (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").
+ ///
+ /// An example would be:
+ /// new string[] { "", "_normals" } for loading a base diffuse texture named "skeletonname.png" and
+ /// a normalmap named "skeletonname_normals.png".
+ public XnaTextureLoader (GraphicsDevice device, bool loadMultipleTextureLayers = false, string[] textureSuffixes = null) {
+ this.device = device;
+ if (loadMultipleTextureLayers)
+ this.textureLayerSuffixes = textureSuffixes;
+ }
+
+ public void Load (AtlasPage page, String path) {
+ Texture2D texture = Util.LoadTexture(device, path);
+ page.width = texture.Width;
+ page.height = texture.Height;
+
+ if (textureLayerSuffixes == null) {
+ page.rendererObject = texture;
+ }
+ else {
+ Texture2D[] textureLayersArray = new Texture2D[textureLayerSuffixes.Length];
+ textureLayersArray[0] = texture;
+ for (int layer = 1; layer < textureLayersArray.Length; ++layer) {
+ string layerPath = GetLayerName(path, textureLayerSuffixes[0], textureLayerSuffixes[layer]);
+ textureLayersArray[layer] = Util.LoadTexture(device, layerPath);
+ }
+ page.rendererObject = textureLayersArray;
+ }
+ }
+
+ public void Unload (Object texture) {
+ ((Texture2D)texture).Dispose();
+ }
+
+ private string GetLayerName (string firstLayerPath, string firstLayerSuffix, string replacementSuffix) {
+
+ int suffixLocation = firstLayerPath.LastIndexOf(firstLayerSuffix + ".");
+ if (suffixLocation == -1) {
+ throw new Exception(string.Concat("Error composing texture layer name: first texture layer name '", firstLayerPath,
+ "' does not contain suffix to be replaced: '", firstLayerSuffix, "'"));
+ }
+ return firstLayerPath.Remove(suffixLocation, firstLayerSuffix.Length).Insert(suffixLocation, replacementSuffix);
+ }
+ }
+}