diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs index 17284f978..874dc6aaa 100644 --- a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs @@ -87,9 +87,9 @@ public class SkeletonRendererInspector : Editor { String[] skins = new String[component.skeleton.Data.Skins.Count]; int skinIndex = 0; for (int i = 0; i < skins.Length; i++) { - String name = component.skeleton.Data.Skins.Items[i].Name; - skins[i] = name; - if (name == initialSkinName.stringValue) + String skinNameString = component.skeleton.Data.Skins.Items[i].Name; + skins[i] = skinNameString; + if (skinNameString == initialSkinName.stringValue) skinIndex = i; } @@ -121,9 +121,15 @@ public class SkeletonRendererInspector : Editor { const float MaxZSpacing = 0f; EditorGUILayout.Slider(zSpacing, MinZSpacing, MaxZSpacing); - EditorGUILayout.PropertyField(normals); - EditorGUILayout.PropertyField(tangents); - EditorGUILayout.PropertyField(front); + if (normals != null) { + EditorGUILayout.PropertyField(normals); + EditorGUILayout.PropertyField(tangents); + } + + if (front != null) { + EditorGUILayout.PropertyField(front); + } + EditorGUILayout.Separator(); EditorGUI.indentLevel--; } diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysBuffers.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysBuffers.cs deleted file mode 100644 index 883f7dbf6..000000000 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysBuffers.cs +++ /dev/null @@ -1,149 +0,0 @@ -using UnityEngine; -using System.Collections; - -namespace Spine.Unity.MeshGeneration { - public static class ArraysBuffers { - - public static void Fill (Skeleton skeleton, int startSlot, int endSlot, float zSpacing, bool pmaColors, Vector3[] vertices, Vector2[] uvs, Color32[] colors32, ref int vertexIndex, ref float[] attVertBuffer, ref Vector3 meshBoundsMin, ref Vector3 meshBoundsMax) { - Color32 color; - var skeletonDrawOrderItems = skeleton.DrawOrder.Items; - float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b; - - // drawOrder[endSlot] is excluded - for (int slotIndex = startSlot; slotIndex < endSlot; slotIndex++) { - var slot = skeletonDrawOrderItems[slotIndex]; - var attachment = slot.attachment; - float z = slotIndex * zSpacing; - - var regionAttachment = attachment as RegionAttachment; - if (regionAttachment != null) { - regionAttachment.ComputeWorldVertices(slot.bone, attVertBuffer); - - float x1 = attVertBuffer[RegionAttachment.X1], y1 = attVertBuffer[RegionAttachment.Y1]; - float x2 = attVertBuffer[RegionAttachment.X2], y2 = attVertBuffer[RegionAttachment.Y2]; - float x3 = attVertBuffer[RegionAttachment.X3], y3 = attVertBuffer[RegionAttachment.Y3]; - float x4 = attVertBuffer[RegionAttachment.X4], y4 = attVertBuffer[RegionAttachment.Y4]; - vertices[vertexIndex].x = x1; vertices[vertexIndex].y = y1; vertices[vertexIndex].z = z; - vertices[vertexIndex + 1].x = x4; vertices[vertexIndex + 1].y = y4; vertices[vertexIndex + 1].z = z; - vertices[vertexIndex + 2].x = x2; vertices[vertexIndex + 2].y = y2; vertices[vertexIndex + 2].z = z; - vertices[vertexIndex + 3].x = x3; vertices[vertexIndex + 3].y = y3; vertices[vertexIndex + 3].z = z; - - if (pmaColors) { - color.a = (byte)(a * slot.a * regionAttachment.a); - color.r = (byte)(r * slot.r * regionAttachment.r * color.a); - color.g = (byte)(g * slot.g * regionAttachment.g * color.a); - color.b = (byte)(b * slot.b * regionAttachment.b * color.a); - if (slot.data.blendMode == BlendMode.additive) color.a = 0; - } else { - color.a = (byte)(a * slot.a * regionAttachment.a); - color.r = (byte)(r * slot.r * regionAttachment.r * 255); - color.g = (byte)(g * slot.g * regionAttachment.g * 255); - color.b = (byte)(b * slot.b * regionAttachment.b * 255); - } - - colors32[vertexIndex] = color; colors32[vertexIndex + 1] = color; colors32[vertexIndex + 2] = color; colors32[vertexIndex + 3] = color; - - float[] regionUVs = regionAttachment.uvs; - uvs[vertexIndex].x = regionUVs[RegionAttachment.X1]; uvs[vertexIndex].y = regionUVs[RegionAttachment.Y1]; - uvs[vertexIndex + 1].x = regionUVs[RegionAttachment.X4]; uvs[vertexIndex + 1].y = regionUVs[RegionAttachment.Y4]; - uvs[vertexIndex + 2].x = regionUVs[RegionAttachment.X2]; uvs[vertexIndex + 2].y = regionUVs[RegionAttachment.Y2]; - uvs[vertexIndex + 3].x = regionUVs[RegionAttachment.X3]; uvs[vertexIndex + 3].y = regionUVs[RegionAttachment.Y3]; - - // Calculate min/max X - if (x1 < meshBoundsMin.x) meshBoundsMin.x = x1; - else if (x1 > meshBoundsMax.x) meshBoundsMax.x = x1; - if (x2 < meshBoundsMin.x) meshBoundsMin.x = x2; - else if (x2 > meshBoundsMax.x) meshBoundsMax.x = x2; - if (x3 < meshBoundsMin.x) meshBoundsMin.x = x3; - else if (x3 > meshBoundsMax.x) meshBoundsMax.x = x3; - if (x4 < meshBoundsMin.x) meshBoundsMin.x = x4; - else if (x4 > meshBoundsMax.x) meshBoundsMax.x = x4; - - // Calculate min/max Y - if (y1 < meshBoundsMin.y) meshBoundsMin.y = y1; - else if (y1 > meshBoundsMax.y) meshBoundsMax.y = y1; - if (y2 < meshBoundsMin.y) meshBoundsMin.y = y2; - else if (y2 > meshBoundsMax.y) meshBoundsMax.y = y2; - if (y3 < meshBoundsMin.y) meshBoundsMin.y = y3; - else if (y3 > meshBoundsMax.y) meshBoundsMax.y = y3; - if (y4 < meshBoundsMin.y) meshBoundsMin.y = y4; - else if (y4 > meshBoundsMax.y) meshBoundsMax.y = y4; - - vertexIndex += 4; - } else { - var meshAttachment = attachment as MeshAttachment; - if (meshAttachment != null) { - int meshVertexCount = meshAttachment.vertices.Length; - if (attVertBuffer.Length < meshVertexCount) attVertBuffer = new float[meshVertexCount]; - meshAttachment.ComputeWorldVertices(slot, attVertBuffer); - - if (pmaColors) { - color.a = (byte)(a * slot.a * meshAttachment.a); - color.r = (byte)(r * slot.r * meshAttachment.r * color.a); - color.g = (byte)(g * slot.g * meshAttachment.g * color.a); - color.b = (byte)(b * slot.b * meshAttachment.b * color.a); - if (slot.data.blendMode == BlendMode.additive) color.a = 0; - } else { - color.a = (byte)(a * slot.a * meshAttachment.a); - color.r = (byte)(r * slot.r * meshAttachment.r * 255); - color.g = (byte)(g * slot.g * meshAttachment.g * 255); - color.b = (byte)(b * slot.b * meshAttachment.b * 255); - } - - float[] attachmentUVs = meshAttachment.uvs; - for (int iii = 0; iii < meshVertexCount; iii += 2) { - float x = attVertBuffer[iii], y = attVertBuffer[iii + 1]; - vertices[vertexIndex].x = x; vertices[vertexIndex].y = y; vertices[vertexIndex].z = z; - colors32[vertexIndex] = color; uvs[vertexIndex].x = attachmentUVs[iii]; uvs[vertexIndex].y = attachmentUVs[iii + 1]; - - if (x < meshBoundsMin.x) meshBoundsMin.x = x; - else if (x > meshBoundsMax.x) meshBoundsMax.x = x; - - if (y < meshBoundsMin.y) meshBoundsMin.y = y; - else if (y > meshBoundsMax.y) meshBoundsMax.y = y; - - vertexIndex++; - } - } else { - var weightedMeshAttachment = attachment as WeightedMeshAttachment; - if (weightedMeshAttachment != null) { - int meshVertexCount = weightedMeshAttachment.uvs.Length; - if (attVertBuffer.Length < meshVertexCount) attVertBuffer = new float[meshVertexCount]; - weightedMeshAttachment.ComputeWorldVertices(slot, attVertBuffer); - - if (pmaColors) { - color.a = (byte)(a * slot.a * weightedMeshAttachment.a); - color.r = (byte)(r * slot.r * weightedMeshAttachment.r * color.a); - color.g = (byte)(g * slot.g * weightedMeshAttachment.g * color.a); - color.b = (byte)(b * slot.b * weightedMeshAttachment.b * color.a); - if (slot.data.blendMode == BlendMode.additive) color.a = 0; - } else { - color.a = (byte)(a * slot.a * weightedMeshAttachment.a); - color.r = (byte)(r * slot.r * weightedMeshAttachment.r * 255); - color.g = (byte)(g * slot.g * weightedMeshAttachment.g * 255); - color.b = (byte)(b * slot.b * weightedMeshAttachment.b * 255); - } - - float[] attachmentUVs = weightedMeshAttachment.uvs; - for (int iii = 0; iii < meshVertexCount; iii += 2) { - float x = attVertBuffer[iii], y = attVertBuffer[iii + 1]; - vertices[vertexIndex].x = x; vertices[vertexIndex].y = y; vertices[vertexIndex].z = z; - colors32[vertexIndex] = color; - uvs[vertexIndex].x = attachmentUVs[iii]; uvs[vertexIndex].y = attachmentUVs[iii + 1]; - - if (x < meshBoundsMin.x) meshBoundsMin.x = x; - else if (x > meshBoundsMax.x) meshBoundsMax.x = x; - if (y < meshBoundsMin.y) meshBoundsMin.y = y; - else if (y > meshBoundsMax.y) meshBoundsMax.y = y; - - vertexIndex++; - } - } - } - } - } - } // Fill(...) - - - } -} diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysBuffers.cs.meta b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysBuffers.cs.meta deleted file mode 100644 index c5548da2a..000000000 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysBuffers.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 043e864df13214e4989d29c17a863b08 -timeCreated: 1458056200 -licenseType: Free -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs new file mode 100644 index 000000000..56358fcf1 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs @@ -0,0 +1,327 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.3 + * + * Copyright (c) 2013-2015, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to use, install, execute and perform the Spine + * Runtimes Software (the "Software") and derivative works solely for personal + * or internal use. Without the written permission of Esoteric Software (see + * Section 2 of the Spine Software License Agreement), you may not (a) modify, + * translate, adapt or otherwise create derivative works, improvements of the + * Software or develop new applications using the Software or (b) remove, + * delete, alter or obscure any trademarks or any copyright, trademark, patent + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) 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 THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +using UnityEngine; + +namespace Spine.Unity.MeshGeneration { + public class ArraysMeshGenerator { + #region Settings + protected bool premultiplyVertexColors = true; + public bool PremultiplyVertexColors { get { return this.premultiplyVertexColors; } set { this.premultiplyVertexColors = value; } } + #endregion + + protected float[] attachmentVertexBuffer = new float[8]; + protected Vector3[] meshVertices; + protected Color32[] meshColors32; + protected Vector2[] meshUVs; + + public static bool EnsureSize (int targetVertexCount, ref Vector3[] vertices, ref Vector2[] uvs, ref Color32[] colors) { + Vector3[] verts = vertices; + bool verticesWasResized = verts == null || targetVertexCount > verts.Length; + if (verticesWasResized) { + // Not enough space, increase size. + vertices = new Vector3[targetVertexCount]; + colors = new Color32[targetVertexCount]; + uvs = new Vector2[targetVertexCount]; + } else { + // Too many vertices, zero the extra. + Vector3 zero = Vector3.zero; + for (int i = targetVertexCount, n = verts.Length; i < n; i++) + verts[i] = zero; + } + return verticesWasResized; + } + + public static bool EnsureTriangleBuffersSize (ExposedList submeshBuffers, int targetSubmeshCount, SubmeshInstruction[] instructionItems) { + bool submeshBuffersWasResized = submeshBuffers.Count < targetSubmeshCount; + if (submeshBuffersWasResized) { + submeshBuffers.GrowIfNeeded(targetSubmeshCount - submeshBuffers.Count); + for (int i = submeshBuffers.Count; submeshBuffers.Count < targetSubmeshCount; i++) + submeshBuffers.Add(new SubmeshTriangleBuffer(instructionItems[i].triangleCount)); + } + return submeshBuffersWasResized; + } + + /// + /// Fills vertex arrays. + /// + /// Spine.Skeleton source of the drawOrder array + /// Slot index of the first slot. + /// The index bounding the slot list. endSlot - 1 is the last slot to be added. + /// Spacing along the z-axis between attachments. + /// If set to true, vertex colors will be premultiplied. This will also enable additive. + /// Vertex positions array. + /// Vertex UV array. + /// Vertex color array (Color32). + /// A reference to the running vertex index. This is used when more than one submesh is to be added. + /// A temporary vertex position buffer for attachment position values. + /// Reference to the running calculated minimum bounds. + /// Reference to the running calculated maximum bounds. + public static void FillVerts (Skeleton skeleton, int startSlot, int endSlot, float zSpacing, bool pmaColors, Vector3[] verts, Vector2[] uvs, Color32[] colors, ref int vertexIndex, ref float[] tempVertBuffer, ref Vector3 boundsMin, ref Vector3 boundsMax) { + Color32 color; + var skeletonDrawOrderItems = skeleton.DrawOrder.Items; + float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b; + + int vi = vertexIndex; + var tempVerts = tempVertBuffer; + Vector3 bmin = boundsMin; + Vector3 bmax = boundsMax; + + // drawOrder[endSlot] is excluded + for (int slotIndex = startSlot; slotIndex < endSlot; slotIndex++) { + var slot = skeletonDrawOrderItems[slotIndex]; + var attachment = slot.attachment; + float z = slotIndex * zSpacing; + + var regionAttachment = attachment as RegionAttachment; + if (regionAttachment != null) { + regionAttachment.ComputeWorldVertices(slot.bone, tempVerts); + + float x1 = tempVerts[RegionAttachment.X1], y1 = tempVerts[RegionAttachment.Y1]; + float x2 = tempVerts[RegionAttachment.X2], y2 = tempVerts[RegionAttachment.Y2]; + float x3 = tempVerts[RegionAttachment.X3], y3 = tempVerts[RegionAttachment.Y3]; + float x4 = tempVerts[RegionAttachment.X4], y4 = tempVerts[RegionAttachment.Y4]; + verts[vi].x = x1; verts[vi].y = y1; verts[vi].z = z; + verts[vi + 1].x = x4; verts[vi + 1].y = y4; verts[vi + 1].z = z; + verts[vi + 2].x = x2; verts[vi + 2].y = y2; verts[vi + 2].z = z; + verts[vi + 3].x = x3; verts[vi + 3].y = y3; verts[vi + 3].z = z; + + if (pmaColors) { + color.a = (byte)(a * slot.a * regionAttachment.a); + color.r = (byte)(r * slot.r * regionAttachment.r * color.a); + color.g = (byte)(g * slot.g * regionAttachment.g * color.a); + color.b = (byte)(b * slot.b * regionAttachment.b * color.a); + if (slot.data.blendMode == BlendMode.additive) color.a = 0; + } else { + color.a = (byte)(a * slot.a * regionAttachment.a); + color.r = (byte)(r * slot.r * regionAttachment.r * 255); + color.g = (byte)(g * slot.g * regionAttachment.g * 255); + color.b = (byte)(b * slot.b * regionAttachment.b * 255); + } + + colors[vi] = color; colors[vi + 1] = color; colors[vi + 2] = color; colors[vi + 3] = color; + + float[] regionUVs = regionAttachment.uvs; + uvs[vi].x = regionUVs[RegionAttachment.X1]; uvs[vi].y = regionUVs[RegionAttachment.Y1]; + uvs[vi + 1].x = regionUVs[RegionAttachment.X4]; uvs[vi + 1].y = regionUVs[RegionAttachment.Y4]; + uvs[vi + 2].x = regionUVs[RegionAttachment.X2]; uvs[vi + 2].y = regionUVs[RegionAttachment.Y2]; + uvs[vi + 3].x = regionUVs[RegionAttachment.X3]; uvs[vi + 3].y = regionUVs[RegionAttachment.Y3]; + + // Calculate min/max X + if (x1 < bmin.x) bmin.x = x1; + else if (x1 > bmax.x) bmax.x = x1; + if (x2 < bmin.x) bmin.x = x2; + else if (x2 > bmax.x) bmax.x = x2; + if (x3 < bmin.x) bmin.x = x3; + else if (x3 > bmax.x) bmax.x = x3; + if (x4 < bmin.x) bmin.x = x4; + else if (x4 > bmax.x) bmax.x = x4; + + // Calculate min/max Y + if (y1 < bmin.y) bmin.y = y1; + else if (y1 > bmax.y) bmax.y = y1; + if (y2 < bmin.y) bmin.y = y2; + else if (y2 > bmax.y) bmax.y = y2; + if (y3 < bmin.y) bmin.y = y3; + else if (y3 > bmax.y) bmax.y = y3; + if (y4 < bmin.y) bmin.y = y4; + else if (y4 > bmax.y) bmax.y = y4; + + vi += 4; + } else { + var meshAttachment = attachment as MeshAttachment; + if (meshAttachment != null) { + int meshVertexCount = meshAttachment.vertices.Length; + if (tempVerts.Length < meshVertexCount) tempVerts = new float[meshVertexCount]; + meshAttachment.ComputeWorldVertices(slot, tempVerts); + + if (pmaColors) { + color.a = (byte)(a * slot.a * meshAttachment.a); + color.r = (byte)(r * slot.r * meshAttachment.r * color.a); + color.g = (byte)(g * slot.g * meshAttachment.g * color.a); + color.b = (byte)(b * slot.b * meshAttachment.b * color.a); + if (slot.data.blendMode == BlendMode.additive) color.a = 0; + } else { + color.a = (byte)(a * slot.a * meshAttachment.a); + color.r = (byte)(r * slot.r * meshAttachment.r * 255); + color.g = (byte)(g * slot.g * meshAttachment.g * 255); + color.b = (byte)(b * slot.b * meshAttachment.b * 255); + } + + float[] attachmentUVs = meshAttachment.uvs; + for (int iii = 0; iii < meshVertexCount; iii += 2) { + float x = tempVerts[iii], y = tempVerts[iii + 1]; + verts[vi].x = x; verts[vi].y = y; verts[vi].z = z; + colors[vi] = color; uvs[vi].x = attachmentUVs[iii]; uvs[vi].y = attachmentUVs[iii + 1]; + + if (x < bmin.x) bmin.x = x; + else if (x > bmax.x) bmax.x = x; + + if (y < bmin.y) bmin.y = y; + else if (y > bmax.y) bmax.y = y; + + vi++; + } + } else { + var weightedMeshAttachment = attachment as WeightedMeshAttachment; + if (weightedMeshAttachment != null) { + int meshVertexCount = weightedMeshAttachment.uvs.Length; + if (tempVerts.Length < meshVertexCount) tempVerts = new float[meshVertexCount]; + weightedMeshAttachment.ComputeWorldVertices(slot, tempVerts); + + if (pmaColors) { + color.a = (byte)(a * slot.a * weightedMeshAttachment.a); + color.r = (byte)(r * slot.r * weightedMeshAttachment.r * color.a); + color.g = (byte)(g * slot.g * weightedMeshAttachment.g * color.a); + color.b = (byte)(b * slot.b * weightedMeshAttachment.b * color.a); + if (slot.data.blendMode == BlendMode.additive) color.a = 0; + } else { + color.a = (byte)(a * slot.a * weightedMeshAttachment.a); + color.r = (byte)(r * slot.r * weightedMeshAttachment.r * 255); + color.g = (byte)(g * slot.g * weightedMeshAttachment.g * 255); + color.b = (byte)(b * slot.b * weightedMeshAttachment.b * 255); + } + + float[] attachmentUVs = weightedMeshAttachment.uvs; + for (int iii = 0; iii < meshVertexCount; iii += 2) { + float x = tempVerts[iii], y = tempVerts[iii + 1]; + verts[vi].x = x; verts[vi].y = y; verts[vi].z = z; + colors[vi] = color; + uvs[vi].x = attachmentUVs[iii]; uvs[vi].y = attachmentUVs[iii + 1]; + + if (x < bmin.x) bmin.x = x; + else if (x > bmax.x) bmax.x = x; + if (y < bmin.y) bmin.y = y; + else if (y > bmax.y) bmax.y = y; + + vi++; + } + } + } + } + } + + // ref return values + vertexIndex = vi; + tempVertBuffer = tempVerts; + boundsMin = bmin; + boundsMax = bmax; + } + + + /// + /// Fills a submesh triangle buffer array. + /// + /// Spine.Skeleton source of draw order slots. + /// The target triangle count. + /// First vertex of this submesh. + /// Start slot. + /// End slot. + /// The triangle buffer array to be filled. This reference will be replaced in case the triangle values don't fit. + /// The current triangle count of the submesh buffer. This is not always equal to triangleBuffer.Length because for last submeshes, length may be larger than needed. + /// If set to true, the triangle buffer is allowed to be larger than needed. + public static void FillTriangles (Skeleton skeleton, int triangleCount, int firstVertex, int startSlot, int endSlot, ref int[] triangleBuffer, ref int bufferTriangleCount, bool isLastSubmesh) { + int trianglesCapacity = triangleBuffer.Length; + var tris = triangleBuffer; + + // Ensure triangleBuffer size. + if (isLastSubmesh) { + bufferTriangleCount = triangleCount; + if (trianglesCapacity > triangleCount) { + for (int i = triangleCount; i < trianglesCapacity; i++) + tris[i] = 0; + } else if (trianglesCapacity < triangleCount) { + triangleBuffer = tris = new int[triangleCount]; + bufferTriangleCount = 0; + } + } else if (trianglesCapacity != triangleCount) { + triangleBuffer = tris = new int[triangleCount]; + bufferTriangleCount = 0; + } + + // Iterate through submesh slots and store the triangles. + int triangleIndex = 0; + int afv = firstVertex; // attachment first vertex + var skeletonDrawOrderItems = skeleton.drawOrder.Items; + for (int i = startSlot, n = endSlot; i < n; i++) { + var attachment = skeletonDrawOrderItems[i].attachment; + + if (attachment is RegionAttachment) { + tris[triangleIndex] = afv; tris[triangleIndex + 1] = afv + 2; tris[triangleIndex + 2] = afv + 1; + tris[triangleIndex + 3] = afv + 2; tris[triangleIndex + 4] = afv + 3; tris[triangleIndex + 5] = afv + 1; + + triangleIndex += 6; + afv += 4; + } else { + int[] attachmentTriangles; + int attachmentVertexCount; + var meshAttachment = attachment as MeshAttachment; + if (meshAttachment != null) { + attachmentVertexCount = meshAttachment.vertices.Length >> 1; // length/2 + attachmentTriangles = meshAttachment.triangles; + } else { + var weightedMeshAttachment = attachment as WeightedMeshAttachment; + if (weightedMeshAttachment != null) { + attachmentVertexCount = weightedMeshAttachment.uvs.Length >> 1; // length/2 + attachmentTriangles = weightedMeshAttachment.triangles; + } else + continue; + } + + for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++) + tris[triangleIndex] = afv + attachmentTriangles[ii]; + + afv += attachmentVertexCount; + } + } // Done adding current submesh triangles + } + + + public static Bounds ToBounds (Vector3 boundsMin, Vector3 boundsMax) { + Vector3 size = (boundsMax - boundsMin); + Vector3 center = boundsMin + size * 0.5f; + return new Bounds(center, size); + } + + #region SubmeshTriangleBuffer + public class SubmeshTriangleBuffer { + public int[] triangles; + public int triangleCount; + + public SubmeshTriangleBuffer (int triangleCount) { + triangles = new int[triangleCount]; + this.triangleCount = triangleCount; + } + } + #endregion + + } +} + diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/SubmeshTriangleBuffer.cs.meta b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs.meta similarity index 76% rename from spine-unity/Assets/spine-unity/Mesh Generation/Arrays/SubmeshTriangleBuffer.cs.meta rename to spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs.meta index 6ec21ecf0..e2048bb20 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/SubmeshTriangleBuffer.cs.meta +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 4b4bb4dc3775d6548b9405f681601abb -timeCreated: 1458056219 +guid: ed047fa8737dedb4081579983c193db5 +timeCreated: 1458124926 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs index 29df4e9da..0cd767dce 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs @@ -28,42 +28,30 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ - using UnityEngine; -using System.Collections; namespace Spine.Unity.MeshGeneration { - public class ArraysSimpleMeshGenerator : ISimpleMeshGenerator { + public class ArraysSimpleMeshGenerator : ArraysMeshGenerator, ISimpleMeshGenerator { #region Settings protected float scale = 1f; public float Scale { get { return scale; } set { scale = value; } } - - public bool renderMeshes = true; - - public bool premultiplyVertexColors = true; - #endregion - - #region Buffers - readonly DoubleBufferedMesh doubleBufferedMesh = new DoubleBufferedMesh(); - private float[] tempVertices = new float[8]; - private Vector3[] vertices; - private Color32[] colors; - private Vector2[] uvs; - private int[] triangles; #endregion private Mesh lastGeneratedMesh; public Mesh LastGeneratedMesh { get { return lastGeneratedMesh; } } + readonly DoubleBufferedMesh doubleBufferedMesh = new DoubleBufferedMesh(); + int[] triangles; + int triangleBufferCount; + public Mesh GenerateMesh (Skeleton skeleton) { int totalVertexCount = 0; // size of vertex arrays int totalTriangleCount = 0; // size of index array - // Step 1 : Count verts and tris to determine array sizes. - // + // STEP 1 : GenerateInstruction(). Count verts and tris to determine array sizes. var drawOrderItems = skeleton.drawOrder.Items; int drawOrderCount = skeleton.drawOrder.Count; for (int i = 0; i < drawOrderCount; i++) { @@ -75,7 +63,6 @@ namespace Spine.Unity.MeshGeneration { attachmentVertexCount = 4; attachmentTriangleCount = 6; } else { - if (!renderMeshes) continue; var meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { attachmentVertexCount = meshAttachment.vertices.Length >> 1; @@ -93,33 +80,13 @@ namespace Spine.Unity.MeshGeneration { totalVertexCount += attachmentVertexCount; } - - // Step 2 : Prepare vertex arrays. - // - Vector3[] vertices = this.vertices; - bool verticesDontFit = vertices == null || totalVertexCount > vertices.Length; - if (verticesDontFit) { - // Not enough space, increase size. - this.vertices = vertices = new Vector3[totalVertexCount]; - this.colors = new Color32[totalVertexCount]; - this.uvs = new Vector2[totalVertexCount]; - - } else { - // Too many vertices, zero the extra. - Vector3 zero = Vector3.zero; - for (int i = totalVertexCount, n = vertices.Length; i < n; i++) - vertices[i] = zero; - } + // STEP 2 : Ensure buffers are the correct size + ArraysMeshGenerator.EnsureSize(totalVertexCount, ref this.meshVertices, ref this.meshUVs, ref this.meshColors32); + this.triangles = this.triangles ?? new int[totalTriangleCount]; - - // Step 3 : Push vertices to arrays - // + // STEP 3 : Update vertex buffer const float zSpacing = 0; const float zFauxHalfThickness = 0.01f; // Somehow needs this thickness for bounds to work properly in some cases (eg, Unity UI clipping) - float[] tempVertices = this.tempVertices; - Vector2[] uvs = this.uvs; - Color32[] colors = this.colors; - Vector3 meshBoundsMin; Vector3 meshBoundsMax; if (totalVertexCount == 0) { @@ -130,98 +97,34 @@ namespace Spine.Unity.MeshGeneration { meshBoundsMin.y = int.MaxValue; meshBoundsMax.x = int.MinValue; meshBoundsMax.y = int.MinValue; - meshBoundsMin.z = -zFauxHalfThickness; - meshBoundsMax.z = zFauxHalfThickness; + meshBoundsMin.z = -zFauxHalfThickness * scale; + meshBoundsMax.z = zFauxHalfThickness * scale; int vertexIndex = 0; - ArraysBuffers.Fill(skeleton, 0, drawOrderCount, zSpacing, this.premultiplyVertexColors, vertices, uvs, colors, ref vertexIndex, ref tempVertices, ref meshBoundsMin, ref meshBoundsMax); - this.tempVertices = tempVertices; + ArraysMeshGenerator.FillVerts(skeleton, 0, drawOrderCount, zSpacing, this.premultiplyVertexColors, this.meshVertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax); // Apply scale to vertices + meshBoundsMax.x *= scale; meshBoundsMax.y *= scale; + meshBoundsMin.x *= scale; meshBoundsMax.y *= scale; + var vertices = this.meshVertices; for (int i = 0; i < totalVertexCount; i++) { - var v = vertices[i]; - v.x *= scale; - v.y *= scale; - vertices[i] = v; - } - - meshBoundsMax.x *= scale; - meshBoundsMax.y *= scale; - meshBoundsMin.x *= scale; - meshBoundsMax.y *= scale; - - } - - - // Step 3 : Ensure correct triangle array size - // - var triangles = this.triangles; - bool trianglesDontFit = triangles == null || totalTriangleCount > triangles.Length; - if (trianglesDontFit) { - // Not enough space, increase size - this.triangles = triangles = new int[totalTriangleCount]; - } else { - // Too many indices, zero the extra. - for (int i = totalTriangleCount, n = triangles.Length; i < n; i++) - triangles[i] = 0; - } - - - // Step 4 : Push triangles to triangle array. - // - int triangleArrayIndex = 0; // next triangle index. modified by loop - int firstAttachmentVertex = 0; - for (int i = 0, n = drawOrderCount; i < n; i++) { - Attachment attachment = drawOrderItems[i].attachment; - - if (attachment is RegionAttachment) { - triangles[triangleArrayIndex] = firstAttachmentVertex; - triangles[triangleArrayIndex + 1] = firstAttachmentVertex + 2; - triangles[triangleArrayIndex + 2] = firstAttachmentVertex + 1; - triangles[triangleArrayIndex + 3] = firstAttachmentVertex + 2; - triangles[triangleArrayIndex + 4] = firstAttachmentVertex + 3; - triangles[triangleArrayIndex + 5] = firstAttachmentVertex + 1; - - triangleArrayIndex += 6; - firstAttachmentVertex += 4; - continue; - } else { - if (!renderMeshes) continue; - int[] attachmentTriangles; - int attachmentVertexCount; - var meshAttachment = attachment as MeshAttachment; - if (meshAttachment != null) { - attachmentVertexCount = meshAttachment.vertices.Length >> 1; // length/2 - attachmentTriangles = meshAttachment.triangles; - } else { - var skinnedMeshAttachment = attachment as WeightedMeshAttachment; - if (skinnedMeshAttachment != null) { - attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1; // length/2 - attachmentTriangles = skinnedMeshAttachment.triangles; - } else - continue; - } - - for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleArrayIndex++) - triangles[triangleArrayIndex] = firstAttachmentVertex + attachmentTriangles[ii]; - - firstAttachmentVertex += attachmentVertexCount; + Vector3 p = vertices[i]; + p.x *= scale; + p.y *= scale; + vertices[i] = p; } } + + // Step 4 : Update Triangles buffer + ArraysMeshGenerator.FillTriangles(skeleton, totalTriangleCount, 0, 0, drawOrderCount, ref this.triangles, ref this.triangleBufferCount, true); - - // Step 5 : Push Data To Mesh - // + // Step 5 : Update Mesh with buffers var mesh = doubleBufferedMesh.GetNextMesh(); - mesh.vertices = vertices; - mesh.colors32 = colors; - mesh.uv = uvs; - - Vector3 meshBoundsExtents = (meshBoundsMax - meshBoundsMin) * scale; - Vector3 meshCenter = (meshBoundsMin * scale) + meshBoundsExtents * 0.5f; - mesh.bounds = new Bounds(meshCenter, meshBoundsExtents); - - mesh.SetTriangles(triangles, 0); + mesh.vertices = this.meshVertices; + mesh.colors32 = meshColors32; + mesh.uv = meshUVs; + mesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax); + mesh.triangles = triangles; lastGeneratedMesh = mesh; return mesh; diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSingleSubmeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSingleSubmeshGenerator.cs deleted file mode 100644 index 2a6975e4b..000000000 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSingleSubmeshGenerator.cs +++ /dev/null @@ -1,185 +0,0 @@ -using UnityEngine; -using System.Collections; - -namespace Spine.Unity.MeshGeneration { - public class ArraysSingleSubmeshGenerator : ISingleSubmeshGenerator { - - public float zSpacing = 0f; - - bool premultiplyVertexColors = true; - public bool PremultiplyVertexColors { get { return this.premultiplyVertexColors; } set { this.premultiplyVertexColors = value; } } - - public Mesh GenerateMesh (SubmeshInstruction instruction) { - float zSpacing = this.zSpacing; - float[] attVertBuffer = this.attachmentVertexBuffer; - Vector2[] uvs = this.meshUVs; - Color32[] colors32 = this.meshColors32; - var attachmentList = this.attachmentListBuffer; - attachmentList.Clear(); - - // Ensure correct buffer sizes. - Vector3[] vertices = this.meshVertices; - - int instructionVertexCount = instruction.vertexCount; - bool newVertices = vertices == null || instructionVertexCount > vertices.Length; - if (newVertices) { - this.meshVertices = vertices = new Vector3[instructionVertexCount]; - this.meshColors32 = colors32 = new Color32[instructionVertexCount]; - this.meshUVs = uvs = new Vector2[instructionVertexCount]; - } else { - var zero = Vector3.zero; - for (int i = instructionVertexCount, n = this.meshVertices.Length; i < n; i++) - vertices[i] = zero; - } - - Vector3 meshBoundsMin; - Vector3 meshBoundsMax; - - int attachmentCount = instruction.endSlot - instruction.startSlot; - - // Initial values for manual Mesh Bounds calculation - if (attachmentCount <= 0) { - meshBoundsMin = new Vector3(0, 0, 0); - meshBoundsMax = new Vector3(0, 0, 0); - } else { - meshBoundsMin.x = int.MaxValue; - meshBoundsMin.y = int.MaxValue; - meshBoundsMax.x = int.MinValue; - meshBoundsMax.y = int.MinValue; - - if (zSpacing > 0f) { - meshBoundsMin.z = 0f; - meshBoundsMax.z = zSpacing * (attachmentCount - 1); - } else { - meshBoundsMin.z = zSpacing * (attachmentCount - 1); - meshBoundsMax.z = 0f; - } - } - - var skeleton = instruction.skeleton; - int vertexIndex = 0; - ArraysBuffers.Fill(skeleton, instruction.startSlot, instruction.endSlot, this.zSpacing, this.premultiplyVertexColors, vertices, uvs, colors32, ref vertexIndex, ref attVertBuffer, ref meshBoundsMin, ref meshBoundsMax); - this.attachmentVertexBuffer = attVertBuffer; - - var smartMesh = this.doubleBufferedSmartMesh.GetNext(); - var mesh = smartMesh.mesh; - - bool structureDoesntMatch = newVertices || smartMesh.StructureDoesntMatch(attachmentList, instruction); - - // Push triangles in this submesh - if (structureDoesntMatch) { - mesh.Clear(); - - int triangleCount = instruction.triangleCount; - - int[] thisTriangles = this.triangles; - if (triangles == null || triangles.Length < triangleCount) { - this.triangles = thisTriangles = new int[triangleCount]; - } else if (triangles.Length > triangleCount) { - for (int i = triangleCount; i < triangles.Length; i++) - thisTriangles[i] = 0; - } - - // Iterate through submesh slots and store the triangles. - int triangleIndex = 0; - int afv = 0; // attachment first vertex, for single submesh, don't use instructions.firstVertexIndex - var skeletonDrawOrderItems = skeleton.drawOrder.Items; - for (int i = instruction.startSlot, n = instruction.endSlot; i < n; i++) { - var attachment = skeletonDrawOrderItems[i].attachment; - - if (attachment is RegionAttachment) { - thisTriangles[triangleIndex] = afv; thisTriangles[triangleIndex + 1] = afv + 2; thisTriangles[triangleIndex + 2] = afv + 1; - thisTriangles[triangleIndex + 3] = afv + 2; thisTriangles[triangleIndex + 4] = afv + 3; thisTriangles[triangleIndex + 5] = afv + 1; - - triangleIndex += 6; - afv += 4; - } else { - int[] attachmentTriangles; - int attachmentVertexCount; - var meshAttachment = attachment as MeshAttachment; - if (meshAttachment != null) { - attachmentVertexCount = meshAttachment.vertices.Length >> 1; // length/2 - attachmentTriangles = meshAttachment.triangles; - } else { - var weightedMeshAttachment = attachment as WeightedMeshAttachment; - if (weightedMeshAttachment != null) { - attachmentVertexCount = weightedMeshAttachment.uvs.Length >> 1; // length/2 - attachmentTriangles = weightedMeshAttachment.triangles; - } else - continue; - } - - for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++) - thisTriangles[triangleIndex] = afv + attachmentTriangles[ii]; - - afv += attachmentVertexCount; - } - } // Done adding current submesh triangles - } - - Vector3 meshBoundsExtents = (meshBoundsMax - meshBoundsMin); - Vector3 meshCenter = meshBoundsMin + meshBoundsExtents * 0.5f; - - smartMesh.Set(this.meshVertices, this.meshUVs, this.meshColors32, attachmentList, instruction); - mesh.bounds = new Bounds(meshCenter, meshBoundsExtents); - - if (structureDoesntMatch) { - mesh.triangles = triangles; - } - - return smartMesh.mesh; - } - - readonly DoubleBuffered doubleBufferedSmartMesh = new DoubleBuffered(); - readonly ExposedList attachmentListBuffer = new ExposedList(); - - float[] attachmentVertexBuffer = new float[8]; - Vector3[] meshVertices; - Color32[] meshColors32; - Vector2[] meshUVs; - int[] triangles; - - class SmartMesh { - public readonly Mesh mesh = SpineMesh.NewMesh(); - SubmeshInstruction instructionsUsed; - readonly ExposedList attachmentsUsed = new ExposedList(); - - public void Set (Vector3[] verts, Vector2[] uvs, Color32[] colors, ExposedList attachmentList, SubmeshInstruction instructions) { - mesh.vertices = verts; - mesh.uv = uvs; - mesh.colors32 = colors; - instructionsUsed = instructions; - - attachmentsUsed.Clear(); - attachmentsUsed.GrowIfNeeded(attachmentList.Capacity); - attachmentsUsed.Count = attachmentList.Count; - attachmentList.CopyTo(attachmentsUsed.Items); - } - - public bool StructureDoesntMatch (ExposedList attachmentList, SubmeshInstruction instructions) { - // Check each submesh instructions for equal arrangement. - var thisInstructions = instructionsUsed; - if ( - instructions.skeleton != thisInstructions.skeleton || - instructions.material.GetInstanceID() != thisInstructions.material.GetInstanceID() || - instructions.startSlot != thisInstructions.startSlot || - instructions.endSlot != thisInstructions.endSlot || - instructions.triangleCount != thisInstructions.triangleCount || - instructions.vertexCount != thisInstructions.vertexCount - ) return true; - //Debug.Log("structure matched"); - - // Check count inequality. - if (attachmentList.Count != this.attachmentsUsed.Count) return true; - var attachmentsPassed = attachmentList.Items; - var myAttachments = this.attachmentsUsed.Items; - for (int i = 0, n = attachmentsUsed.Count; i < n; i++) - if (attachmentsPassed[i] != myAttachments[i]) return true; - - //Debug.Log("attachments matched"); - - return false; - } - } - } -} diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSingleSubmeshGenerator.cs.meta b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSingleSubmeshGenerator.cs.meta deleted file mode 100644 index 62a4b1275..000000000 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSingleSubmeshGenerator.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: 8bde87b725a537d4d9ff09a3ec7da8b5 -timeCreated: 1456493071 -licenseType: Free -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs index 0c62237bd..2d7075a0e 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs @@ -1,65 +1,74 @@ -using UnityEngine; -using System.Collections; -using Spine; +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.3 + * + * Copyright (c) 2013-2015, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to use, install, execute and perform the Spine + * Runtimes Software (the "Software") and derivative works solely for personal + * or internal use. Without the written permission of Esoteric Software (see + * Section 2 of the Spine Software License Agreement), you may not (a) modify, + * translate, adapt or otherwise create derivative works, improvements of the + * Software or develop new applications using the Software or (b) remove, + * delete, alter or obscure any trademarks or any copyright, trademark, patent + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) 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 THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +using UnityEngine; namespace Spine.Unity.MeshGeneration { - public class ArraysSubmeshSetMeshGenerator : ISubmeshSetMeshGenerator { + public class ArraysSubmeshSetMeshGenerator : ArraysMeshGenerator, ISubmeshSetMeshGenerator { + #region Settings public float zSpacing = 0f; - public bool premultiplyVertexColors = true; + #endregion + + readonly DoubleBuffered doubleBufferedSmartMesh = new DoubleBuffered(); + readonly ExposedList currentInstructions = new ExposedList(); + readonly ExposedList currentAttachments = new ExposedList(); + readonly ExposedList submeshBuffers = new ExposedList(); + Material[] sharedMaterials = new Material[0]; public MeshAndMaterials GenerateMesh (ExposedList instructions, int startSubmesh, int endSubmesh) { + // STEP 0: Prepare instructions. var paramItems = instructions.Items; currentInstructions.Clear(false); for (int i = startSubmesh, n = endSubmesh; i < n; i++) { this.currentInstructions.Add(paramItems[i]); } - var smartMesh = doubleBufferedSmartMesh.GetNext(); var mesh = smartMesh.mesh; - int submeshCount = currentInstructions.Count; var currentInstructionsItems = currentInstructions.Items; - int vertexCount = 0; for (int i = 0; i < submeshCount; i++) { - // Ensure current instructions have correct cached values. - currentInstructionsItems[i].firstVertexIndex = vertexCount; - - // vertexCount will also be used for the rest of this method. - vertexCount += currentInstructionsItems[i].vertexCount; - } - - float[] attVertBuffer = this.attachmentVertexBuffer; - Vector2[] uvs = this.meshUVs; - Color32[] colors32 = this.meshColors32; - - // Ensure correct buffer sizes. - Vector3[] vertices = this.meshVertices; - - bool newVertices = vertices == null || vertexCount > vertices.Length; - if (newVertices) { - this.meshVertices = vertices = new Vector3[vertexCount]; - this.meshColors32 = colors32 = new Color32[vertexCount]; - this.meshUVs = uvs = new Vector2[vertexCount]; - } else { - var zero = Vector3.zero; - for (int i = vertexCount, n = this.meshVertices.Length; i < n; i++) - vertices[i] = zero; + currentInstructionsItems[i].firstVertexIndex = vertexCount;// Ensure current instructions have correct cached values. + vertexCount += currentInstructionsItems[i].vertexCount; // vertexCount will also be used for the rest of this method. } - bool newSubmeshBuffers = submeshBuffers.Count < submeshCount; - if (newSubmeshBuffers) { - submeshBuffers.GrowIfNeeded(submeshCount); - for (int i = submeshBuffers.Count; submeshBuffers.Count < submeshCount; i++) { - submeshBuffers.Add(new SubmeshTriangleBuffer(currentInstructionsItems[i].triangleCount)); - } - } + // STEP 1: Ensure correct buffer sizes. + bool vertBufferResized = ArraysMeshGenerator.EnsureSize(vertexCount, ref this.meshVertices, ref this.meshUVs, ref this.meshColors32); + bool submeshBuffersResized = ArraysMeshGenerator.EnsureTriangleBuffersSize(submeshBuffers, submeshCount, currentInstructionsItems); + // STEP 2: Update buffers based on Skeleton. + + // Initial values for manual Mesh Bounds calculation Vector3 meshBoundsMin; Vector3 meshBoundsMax; - float zSpacing = this.zSpacing; - // Initial values for manual Mesh Bounds calculation if (vertexCount <= 0) { meshBoundsMin = new Vector3(0, 0, 0); meshBoundsMax = new Vector3(0, 0, 0); @@ -69,250 +78,50 @@ namespace Spine.Unity.MeshGeneration { meshBoundsMax.x = int.MinValue; meshBoundsMax.y = int.MinValue; + int endSlot = currentInstructionsItems[submeshCount - 1].endSlot; if (zSpacing > 0f) { meshBoundsMin.z = 0f; - meshBoundsMax.z = zSpacing * (currentInstructionsItems[submeshCount - 1].endSlot); + meshBoundsMax.z = zSpacing * endSlot; } else { - meshBoundsMin.z = zSpacing * (currentInstructionsItems[submeshCount - 1].endSlot); + meshBoundsMin.z = zSpacing * endSlot; meshBoundsMax.z = 0f; } } - - bool structureDoesntMatch = newVertices || newSubmeshBuffers || smartMesh.StructureDoesntMatch(currentAttachments, currentInstructions); + + // For each submesh, add vertex data from attachments. + var currentAttachments_ = this.currentAttachments; + bool structureDoesntMatch = vertBufferResized || submeshBuffersResized || smartMesh.StructureDoesntMatch(currentAttachments_, currentInstructions); + currentAttachments_.Clear(false); + int vertexIndex = 0; // modified by FillVerts + for (int submeshIndex = 0; submeshIndex < submeshCount; submeshIndex++) { + var currentInstruction = currentInstructionsItems[submeshIndex]; + int startSlot = currentInstruction.startSlot; + int endSlot = currentInstruction.endSlot; + var skeleton = currentInstruction.skeleton; + var skeletonDrawOrderItems = skeleton.DrawOrder.Items; + for (int i = startSlot; i < endSlot; i++) { + var ca = skeletonDrawOrderItems[i].attachment; + if (ca != null) currentAttachments_.Add(ca); // Includes BoundingBoxes. This is ok. + } + ArraysMeshGenerator.FillVerts(skeleton, startSlot, endSlot, zSpacing, this.premultiplyVertexColors, this.meshVertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax); + if (structureDoesntMatch) { + var currentBuffer = submeshBuffers.Items[submeshIndex]; + bool isLastSubmesh = (submeshIndex == submeshCount - 1); + ArraysMeshGenerator.FillTriangles(skeleton, currentInstruction.triangleCount, currentInstruction.firstVertexIndex, startSlot, endSlot, ref currentBuffer.triangles, ref currentBuffer.triangleCount, isLastSubmesh); + } + } if (structureDoesntMatch) { mesh.Clear(); - - if (submeshCount == sharedMaterials.Length) - currentInstructions.FillMaterialArray(this.sharedMaterials); - else - this.sharedMaterials = currentInstructions.GetNewMaterialArray(); + this.sharedMaterials = currentInstructions.GetUpdatedMaterialArray(this.sharedMaterials); } - currentAttachments.Clear(false); - int vertexIndex = 0; - // For each submesh, add vertex data from attachments. - for (int submeshIndex = 0; submeshIndex < submeshCount; submeshIndex++) { - var currentSubmeshInstruction = currentInstructionsItems[submeshIndex]; - var skeleton = currentSubmeshInstruction.skeleton; - -// for (int slotIndex = currentSubmeshInstruction.startSlot, endSlot = currentSubmeshInstruction.endSlot; slotIndex < endSlot; slotIndex++) { -// var slot = skeletonDrawOrderItems[slotIndex]; -// var attachment = slot.attachment; -// float z = slotIndex * zSpacing; -// -// var regionAttachment = attachment as RegionAttachment; -// if (regionAttachment != null) { -// regionAttachment.ComputeWorldVertices(slot.bone, attVertBuffer); -// -// float x1 = attVertBuffer[RegionAttachment.X1], y1 = attVertBuffer[RegionAttachment.Y1]; -// float x2 = attVertBuffer[RegionAttachment.X2], y2 = attVertBuffer[RegionAttachment.Y2]; -// float x3 = attVertBuffer[RegionAttachment.X3], y3 = attVertBuffer[RegionAttachment.Y3]; -// float x4 = attVertBuffer[RegionAttachment.X4], y4 = attVertBuffer[RegionAttachment.Y4]; -// vertices[vertexIndex].x = x1; vertices[vertexIndex].y = y1; vertices[vertexIndex].z = z; -// vertices[vertexIndex + 1].x = x4; vertices[vertexIndex + 1].y = y4; vertices[vertexIndex + 1].z = z; -// vertices[vertexIndex + 2].x = x2; vertices[vertexIndex + 2].y = y2; vertices[vertexIndex + 2].z = z; -// vertices[vertexIndex + 3].x = x3; vertices[vertexIndex + 3].y = y3; vertices[vertexIndex + 3].z = z; -// -// if (premultiplyVertexColors) { -// color.a = (byte)(a * slot.a * regionAttachment.a); -// color.r = (byte)(r * slot.r * regionAttachment.r * color.a); -// color.g = (byte)(g * slot.g * regionAttachment.g * color.a); -// color.b = (byte)(b * slot.b * regionAttachment.b * color.a); -// if (slot.data.blendMode == BlendMode.additive) color.a = 0; -// } else { -// color.a = (byte)(a * slot.a * regionAttachment.a); -// color.r = (byte)(r * slot.r * regionAttachment.r * 255); -// color.g = (byte)(g * slot.g * regionAttachment.g * 255); -// color.b = (byte)(b * slot.b * regionAttachment.b * 255); -// } -// -// colors32[vertexIndex] = color; colors32[vertexIndex + 1] = color; colors32[vertexIndex + 2] = color; colors32[vertexIndex + 3] = color; -// -// float[] regionUVs = regionAttachment.uvs; -// uvs[vertexIndex].x = regionUVs[RegionAttachment.X1]; uvs[vertexIndex].y = regionUVs[RegionAttachment.Y1]; -// uvs[vertexIndex + 1].x = regionUVs[RegionAttachment.X4]; uvs[vertexIndex + 1].y = regionUVs[RegionAttachment.Y4]; -// uvs[vertexIndex + 2].x = regionUVs[RegionAttachment.X2]; uvs[vertexIndex + 2].y = regionUVs[RegionAttachment.Y2]; -// uvs[vertexIndex + 3].x = regionUVs[RegionAttachment.X3]; uvs[vertexIndex + 3].y = regionUVs[RegionAttachment.Y3]; -// -// // Calculate min/max X -// if (x1 < meshBoundsMin.x) meshBoundsMin.x = x1; -// else if (x1 > meshBoundsMax.x) meshBoundsMax.x = x1; -// if (x2 < meshBoundsMin.x) meshBoundsMin.x = x2; -// else if (x2 > meshBoundsMax.x) meshBoundsMax.x = x2; -// if (x3 < meshBoundsMin.x) meshBoundsMin.x = x3; -// else if (x3 > meshBoundsMax.x) meshBoundsMax.x = x3; -// if (x4 < meshBoundsMin.x) meshBoundsMin.x = x4; -// else if (x4 > meshBoundsMax.x) meshBoundsMax.x = x4; -// -// // Calculate min/max Y -// if (y1 < meshBoundsMin.y) meshBoundsMin.y = y1; -// else if (y1 > meshBoundsMax.y) meshBoundsMax.y = y1; -// if (y2 < meshBoundsMin.y) meshBoundsMin.y = y2; -// else if (y2 > meshBoundsMax.y) meshBoundsMax.y = y2; -// if (y3 < meshBoundsMin.y) meshBoundsMin.y = y3; -// else if (y3 > meshBoundsMax.y) meshBoundsMax.y = y3; -// if (y4 < meshBoundsMin.y) meshBoundsMin.y = y4; -// else if (y4 > meshBoundsMax.y) meshBoundsMax.y = y4; -// -// currentAttachments.Add(regionAttachment); -// vertexIndex += 4; -// } else { -// var meshAttachment = attachment as MeshAttachment; -// if (meshAttachment != null) { -// int meshVertexCount = meshAttachment.vertices.Length; -// if (attVertBuffer.Length < meshVertexCount) this.attachmentVertexBuffer = attVertBuffer = new float[meshVertexCount]; -// meshAttachment.ComputeWorldVertices(slot, attVertBuffer); -// -// if (premultiplyVertexColors) { -// color.a = (byte)(a * slot.a * meshAttachment.a); -// color.r = (byte)(r * slot.r * meshAttachment.r * color.a); -// color.g = (byte)(g * slot.g * meshAttachment.g * color.a); -// color.b = (byte)(b * slot.b * meshAttachment.b * color.a); -// if (slot.data.blendMode == BlendMode.additive) color.a = 0; -// } else { -// color.a = (byte)(a * slot.a * meshAttachment.a); -// color.r = (byte)(r * slot.r * meshAttachment.r * 255); -// color.g = (byte)(g * slot.g * meshAttachment.g * 255); -// color.b = (byte)(b * slot.b * meshAttachment.b * 255); -// } -// -// float[] attachmentUVs = meshAttachment.uvs; -// for (int iii = 0; iii < meshVertexCount; iii += 2) { -// float x = attVertBuffer[iii], y = attVertBuffer[iii + 1]; -// vertices[vertexIndex].x = x; vertices[vertexIndex].y = y; vertices[vertexIndex].z = z; -// colors32[vertexIndex] = color; uvs[vertexIndex].x = attachmentUVs[iii]; uvs[vertexIndex].y = attachmentUVs[iii + 1]; -// -// if (x < meshBoundsMin.x) meshBoundsMin.x = x; -// else if (x > meshBoundsMax.x) meshBoundsMax.x = x; -// -// if (y < meshBoundsMin.y) meshBoundsMin.y = y; -// else if (y > meshBoundsMax.y) meshBoundsMax.y = y; -// -// currentAttachments.Add(meshAttachment); -// vertexIndex++; -// } -// } else { -// var weightedMeshAttachment = attachment as WeightedMeshAttachment; -// if (weightedMeshAttachment != null) { -// int meshVertexCount = weightedMeshAttachment.uvs.Length; -// if (attVertBuffer.Length < meshVertexCount) this.attachmentVertexBuffer = attVertBuffer = new float[meshVertexCount]; -// weightedMeshAttachment.ComputeWorldVertices(slot, attVertBuffer); -// -// if (premultiplyVertexColors) { -// color.a = (byte)(a * slot.a * weightedMeshAttachment.a); -// color.r = (byte)(r * slot.r * weightedMeshAttachment.r * color.a); -// color.g = (byte)(g * slot.g * weightedMeshAttachment.g * color.a); -// color.b = (byte)(b * slot.b * weightedMeshAttachment.b * color.a); -// if (slot.data.blendMode == BlendMode.additive) color.a = 0; -// } else { -// color.a = (byte)(a * slot.a * weightedMeshAttachment.a); -// color.r = (byte)(r * slot.r * weightedMeshAttachment.r * 255); -// color.g = (byte)(g * slot.g * weightedMeshAttachment.g * 255); -// color.b = (byte)(b * slot.b * weightedMeshAttachment.b * 255); -// } -// -// float[] attachmentUVs = weightedMeshAttachment.uvs; -// for (int iii = 0; iii < meshVertexCount; iii += 2) { -// float x = attVertBuffer[iii], y = attVertBuffer[iii + 1]; -// vertices[vertexIndex].x = x; vertices[vertexIndex].y = y; vertices[vertexIndex].z = z; -// colors32[vertexIndex] = color; -// uvs[vertexIndex].x = attachmentUVs[iii]; uvs[vertexIndex].y = attachmentUVs[iii + 1]; -// -// if (x < meshBoundsMin.x) meshBoundsMin.x = x; -// else if (x > meshBoundsMax.x) meshBoundsMax.x = x; -// if (y < meshBoundsMin.y) meshBoundsMin.y = y; -// else if (y > meshBoundsMax.y) meshBoundsMax.y = y; -// -// currentAttachments.Add(weightedMeshAttachment); -// vertexIndex++; -// } -// } -// } -// } -// } - var skeletonDrawOrderItems = skeleton.DrawOrder.Items; - int startSlot = currentSubmeshInstruction.startSlot; - int endSlot = currentSubmeshInstruction.endSlot; - - for (int i = startSlot, n = currentSubmeshInstruction.endSlot; i < n; i++) { - var ca = skeletonDrawOrderItems[i].attachment; - if (ca != null) { - // Includes BoundingBoxes. This is ok. - currentAttachments.Add(ca); - } - } - - ArraysBuffers.Fill(skeleton, startSlot, endSlot, zSpacing, this.premultiplyVertexColors, vertices, uvs, colors32, ref vertexIndex, ref attVertBuffer, ref meshBoundsMin, ref meshBoundsMax); - - // Push triangles in this submesh - if (structureDoesntMatch) { - smartMesh.mesh.Clear(); // rebuild triangle array. - - var currentSubmesh = submeshBuffers.Items[submeshIndex]; - bool isLastSubmesh = (submeshIndex == submeshCount - 1); - - int triangleCount = currentSubmesh.triangleCount = currentSubmeshInstruction.triangleCount; - int trianglesCapacity = currentSubmesh.triangles.Length; - - int[] triangles = currentSubmesh.triangles; - if (isLastSubmesh) { - if (trianglesCapacity > triangleCount) { - for (int i = triangleCount; i < trianglesCapacity; i++) - triangles[i] = 0; - } - } else if (trianglesCapacity != triangleCount) { - triangles = currentSubmesh.triangles = new int[triangleCount]; - currentSubmesh.triangleCount = 0; - } - - // Iterate through submesh slots and store the triangles. - int triangleIndex = 0; - int afv = currentSubmeshInstruction.firstVertexIndex; // attachment first vertex - - for (int i = currentSubmeshInstruction.startSlot, n = currentSubmeshInstruction.endSlot; i < n; i++) { - var attachment = skeletonDrawOrderItems[i].attachment; - - if (attachment is RegionAttachment) { - triangles[triangleIndex] = afv; triangles[triangleIndex + 1] = afv + 2; triangles[triangleIndex + 2] = afv + 1; - triangles[triangleIndex + 3] = afv + 2; triangles[triangleIndex + 4] = afv + 3; triangles[triangleIndex + 5] = afv + 1; - - triangleIndex += 6; - afv += 4; - } else { - int[] attachmentTriangles; - int attachmentVertexCount; - var meshAttachment = attachment as MeshAttachment; - if (meshAttachment != null) { - attachmentVertexCount = meshAttachment.vertices.Length >> 1; // length/2 - attachmentTriangles = meshAttachment.triangles; - } else { - var weightedMeshAttachment = attachment as WeightedMeshAttachment; - if (weightedMeshAttachment != null) { - attachmentVertexCount = weightedMeshAttachment.uvs.Length >> 1; // length/2 - attachmentTriangles = weightedMeshAttachment.triangles; - } else - continue; - } - - for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++) - triangles[triangleIndex] = afv + attachmentTriangles[ii]; - - afv += attachmentVertexCount; - } - } // Done adding current submesh triangles - } - } - - this.attachmentVertexBuffer = attVertBuffer; - Vector3 meshBoundsExtents = (meshBoundsMax - meshBoundsMin); - Vector3 meshCenter = meshBoundsMin + meshBoundsExtents * 0.5f; - + // STEP 3: Assign the buffers into the Mesh. smartMesh.Set(this.meshVertices, this.meshUVs, this.meshColors32, currentAttachments, currentInstructions); - mesh.bounds = new Bounds(meshCenter, meshBoundsExtents); + mesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax); if (structureDoesntMatch) { - // push new triangles if doesn't match. + // Push new triangles if doesn't match. mesh.subMeshCount = submeshCount; for (int i = 0; i < submeshCount; i++) mesh.SetTriangles(submeshBuffers.Items[i].triangles, i); @@ -321,19 +130,6 @@ namespace Spine.Unity.MeshGeneration { return new MeshAndMaterials(smartMesh.mesh, sharedMaterials); } - #region Internals - readonly DoubleBuffered doubleBufferedSmartMesh = new DoubleBuffered(); - readonly ExposedList currentInstructions = new ExposedList(); - readonly ExposedList currentAttachments = new ExposedList(); - - float[] attachmentVertexBuffer = new float[8]; - Vector3[] meshVertices; - Color32[] meshColors32; - Vector2[] meshUVs; - Material[] sharedMaterials = new Material[0]; - readonly ExposedList submeshBuffers = new ExposedList(); - #endregion - #region Types // A SmartMesh is a Mesh (with submeshes) that knows what attachments and instructions were used to generate it. class SmartMesh { diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs index 83a8c9e06..641fc9cdc 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs @@ -1,21 +1,57 @@ -using UnityEngine; -using System.Collections; +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.3 + * + * Copyright (c) 2013-2015, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to use, install, execute and perform the Spine + * Runtimes Software (the "Software") and derivative works solely for personal + * or internal use. Without the written permission of Esoteric Software (see + * Section 2 of the Spine Software License Agreement), you may not (a) modify, + * translate, adapt or otherwise create derivative works, improvements of the + * Software or develop new applications using the Software or (b) remove, + * delete, alter or obscure any trademarks or any copyright, trademark, patent + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) 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 THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +//#define SPINE_OPTIONAL_NORMALS + +using UnityEngine; using System.Collections.Generic; -using Spine; -using Spine.Unity; - namespace Spine.Unity.MeshGeneration { - public class ArraysSubmeshedMeshGenerator : ISubmeshedMeshGenerator { + /// + /// Arrays submeshed mesh generator. + /// + public class ArraysSubmeshedMeshGenerator : ArraysMeshGenerator, ISubmeshedMeshGenerator { readonly List separators = new List(); public List Separators { get { return this.separators; } } - public bool premultiplyVertexColors = true; public float zSpacing = 0f; + #if SPINE_OPTIONAL_NORMALS + public bool generateNormals; + public bool generateTangents; + #endif - // public bool generateNormals; - // public bool generateTangents; + readonly DoubleBuffered doubleBufferedSmartMesh = new DoubleBuffered(); + readonly SubmeshedMeshInstruction currentInstructions = new SubmeshedMeshInstruction(); + readonly ExposedList submeshBuffers = new ExposedList(); + Material[] sharedMaterials = new Material[0]; public SubmeshedMeshInstruction GenerateInstruction (Skeleton skeleton) { if (skeleton == null) throw new System.ArgumentNullException("skeleton"); @@ -71,8 +107,8 @@ namespace Spine.Unity.MeshGeneration { var attachmentMaterial = (Material)((AtlasRegion)rendererObject).page.rendererObject; // Populate submesh when material changes. (or when forced to separate by a submeshSeparator) - if (( runningVertexCount > 0 && lastMaterial.GetInstanceID() != attachmentMaterial.GetInstanceID() ) || - ( separatorCount > 0 && separators.Contains(slot) )) { + bool separatedBySlot = ( separatorCount > 0 && separators.Contains(slot) ); + if (( runningVertexCount > 0 && lastMaterial.GetInstanceID() != attachmentMaterial.GetInstanceID() ) || separatedBySlot) { instructionList.Add( new SubmeshInstruction { @@ -82,7 +118,8 @@ namespace Spine.Unity.MeshGeneration { vertexCount = submeshVertexCount, startSlot = submeshStartSlotIndex, endSlot = i, - firstVertexIndex = submeshFirstVertex + firstVertexIndex = submeshFirstVertex, + separatedBySlot = separatedBySlot } ); @@ -109,7 +146,8 @@ namespace Spine.Unity.MeshGeneration { vertexCount = submeshVertexCount, startSlot = submeshStartSlotIndex, endSlot = drawOrderCount, - firstVertexIndex = submeshFirstVertex + firstVertexIndex = submeshFirstVertex, + separatedBySlot = false } ); @@ -117,50 +155,25 @@ namespace Spine.Unity.MeshGeneration { return currentInstructions; } + // ISubmeshedMeshGenerator.GenerateMesh + /// Generates a mesh based on SubmeshedMeshInstructions public MeshAndMaterials GenerateMesh (SubmeshedMeshInstruction meshInstructions) { var smartMesh = doubleBufferedSmartMesh.GetNext(); var mesh = smartMesh.mesh; - int submeshCount = meshInstructions.submeshInstructions.Count; - var instructionList = meshInstructions.submeshInstructions; - float zSpacing = this.zSpacing; - float[] attVertBuffer = this.attachmentVertexBuffer; - Vector2[] uvs = this.meshUVs; - Color32[] colors32 = this.meshColors32; - // Ensure correct buffer sizes. + // STEP 1: Ensure correct buffer sizes. + bool submeshBuffersResized = ArraysMeshGenerator.EnsureTriangleBuffersSize(submeshBuffers, submeshCount, instructionList.Items); + bool vertBufferResized = ArraysMeshGenerator.EnsureSize(meshInstructions.vertexCount, ref this.meshVertices, ref this.meshUVs, ref this.meshColors32); Vector3[] vertices = this.meshVertices; - bool newVertices = vertices == null || meshInstructions.vertexCount > vertices.Length; - int instructionVertexCount = meshInstructions.vertexCount; - if (newVertices) { - this.meshVertices = vertices = new Vector3[instructionVertexCount]; - this.meshColors32 = colors32 = new Color32[instructionVertexCount]; - this.meshUVs = uvs = new Vector2[instructionVertexCount]; - } else { - var zero = Vector3.zero; - for (int i = instructionVertexCount, n = this.meshVertices.Length; i < n; i++) - vertices[i] = zero; - } - - bool newSubmeshBuffers = submeshBuffers.Count < submeshCount; - if (newSubmeshBuffers) { - submeshBuffers.GrowIfNeeded(submeshCount); - for (int i = submeshBuffers.Count; submeshBuffers.Count < submeshCount; i++) { - submeshBuffers.Add(new SubmeshTriangleBuffer(instructionList.Items[i].triangleCount)); - //submeshBuffers.Items[i] = new SubmeshTriangleBuffer(tc); - //submeshBuffers.Count = i; - } - } - + // STEP 2: Update buffers based on Skeleton. + float zSpacing = this.zSpacing; Vector3 meshBoundsMin; Vector3 meshBoundsMax; - int attachmentCount = meshInstructions.attachmentList.Count; - - // Initial values for manual Mesh Bounds calculation - if (meshInstructions.attachmentList.Count <= 0) { + if (attachmentCount <= 0) { meshBoundsMin = new Vector3(0, 0, 0); meshBoundsMax = new Vector3(0, 0, 0); } else { @@ -177,134 +190,60 @@ namespace Spine.Unity.MeshGeneration { meshBoundsMax.z = 0f; } } - - bool structureDoesntMatch = newVertices || newSubmeshBuffers || smartMesh.StructureDoesntMatch(meshInstructions); - - if (structureDoesntMatch) { - mesh.Clear(); - - if (submeshCount == sharedMaterials.Length) - meshInstructions.FillMaterialArray(this.sharedMaterials); - else - this.sharedMaterials = meshInstructions.GetNewMaterialArray(); - } - - int vertexIndex = 0; - - // For each submesh, add vertex data from attachments. + bool structureDoesntMatch = vertBufferResized || submeshBuffersResized || smartMesh.StructureDoesntMatch(meshInstructions); + // For each submesh, add vertex data from attachments. Also triangles, but only if needed. + int vertexIndex = 0; // modified by FillVerts for (int submeshIndex = 0; submeshIndex < submeshCount; submeshIndex++) { - var currentSubmeshInstruction = instructionList.Items[submeshIndex]; - var skeleton = currentSubmeshInstruction.skeleton; - - ArraysBuffers.Fill(skeleton, currentSubmeshInstruction.startSlot, currentSubmeshInstruction.endSlot, zSpacing, this.premultiplyVertexColors, vertices, uvs, colors32, ref vertexIndex, ref attVertBuffer, ref meshBoundsMin, ref meshBoundsMax); - - // Push triangles in this submesh + var submeshInstruction = instructionList.Items[submeshIndex]; + int start = submeshInstruction.startSlot; + int end = submeshInstruction.endSlot; + var skeleton = submeshInstruction.skeleton; + ArraysMeshGenerator.FillVerts(skeleton, start, end, zSpacing, this.premultiplyVertexColors, vertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax); if (structureDoesntMatch) { - smartMesh.mesh.Clear(); // rebuild triangle array. - - var currentSubmesh = submeshBuffers.Items[submeshIndex]; + var currentBuffer = submeshBuffers.Items[submeshIndex]; bool isLastSubmesh = (submeshIndex == submeshCount - 1); - - int triangleCount = currentSubmesh.triangleCount = currentSubmeshInstruction.triangleCount; - int trianglesCapacity = currentSubmesh.triangles.Length; - - int[] triangles = currentSubmesh.triangles; - if (isLastSubmesh) { - if (trianglesCapacity > triangleCount) { - for (int i = triangleCount; i < trianglesCapacity; i++) - triangles[i] = 0; - } - } else if (trianglesCapacity != triangleCount) { - triangles = currentSubmesh.triangles = new int[triangleCount]; - currentSubmesh.triangleCount = 0; - } - - // Iterate through submesh slots and store the triangles. - int triangleIndex = 0; - int afv = currentSubmeshInstruction.firstVertexIndex; // attachment first vertex - var skeletonDrawOrderItems = skeleton.DrawOrder.Items; - for (int i = currentSubmeshInstruction.startSlot, n = currentSubmeshInstruction.endSlot; i < n; i++) { - var attachment = skeletonDrawOrderItems[i].attachment; - - if (attachment is RegionAttachment) { - triangles[triangleIndex] = afv; triangles[triangleIndex + 1] = afv + 2; triangles[triangleIndex + 2] = afv + 1; - triangles[triangleIndex + 3] = afv + 2; triangles[triangleIndex + 4] = afv + 3; triangles[triangleIndex + 5] = afv + 1; - - triangleIndex += 6; - afv += 4; - } else { - int[] attachmentTriangles; - int attachmentVertexCount; - var meshAttachment = attachment as MeshAttachment; - if (meshAttachment != null) { - attachmentVertexCount = meshAttachment.vertices.Length >> 1; // length/2 - attachmentTriangles = meshAttachment.triangles; - } else { - var weightedMeshAttachment = attachment as WeightedMeshAttachment; - if (weightedMeshAttachment != null) { - attachmentVertexCount = weightedMeshAttachment.uvs.Length >> 1; // length/2 - attachmentTriangles = weightedMeshAttachment.triangles; - } else - continue; - } - - for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++) - triangles[triangleIndex] = afv + attachmentTriangles[ii]; - - afv += attachmentVertexCount; - } - } // Done adding current submesh triangles + ArraysMeshGenerator.FillTriangles(skeleton, submeshInstruction.triangleCount, submeshInstruction.firstVertexIndex, start, end, ref currentBuffer.triangles, ref currentBuffer.triangleCount, isLastSubmesh); } } - this.attachmentVertexBuffer = attVertBuffer; - Vector3 meshBoundsExtents = (meshBoundsMax - meshBoundsMin); - Vector3 meshCenter = meshBoundsMin + meshBoundsExtents * 0.5f; + if (structureDoesntMatch) { + mesh.Clear(); + this.sharedMaterials = meshInstructions.GetUpdatedMaterialArray(this.sharedMaterials); + } + // STEP 3: Assign the buffers into the Mesh. smartMesh.Set(this.meshVertices, this.meshUVs, this.meshColors32, meshInstructions); - mesh.bounds = new Bounds(meshCenter, meshBoundsExtents); + mesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax); if (structureDoesntMatch) { - -// if (generateNormals) { -// int vertexCount = meshInstructions.vertexCount; -// Vector3[] normals = new Vector3[vertexCount]; -// Vector3 normal = new Vector3(0, 0, -1); -// for (int i = 0; i < vertexCount; i++) -// normals[i] = normal; -// mesh.normals = normals; -// -// if (generateTangents) { -// Vector4[] tangents = new Vector4[vertexCount]; -// Vector4 tangent = new Vector4(1, 0, 0, -1); -// for (int i = 0; i < vertexCount; i++) -// tangents[i] = tangent; -// mesh.tangents = tangents; -// } -// } - - // push new triangles if doesn't match. + // Push new triangles if doesn't match. mesh.subMeshCount = submeshCount; for (int i = 0; i < submeshCount; i++) mesh.SetTriangles(submeshBuffers.Items[i].triangles, i); + + #if SPINE_OPTIONAL_NORMALS + if (generateNormals) { + int vertexCount = meshInstructions.vertexCount; + Vector3[] normals = new Vector3[vertexCount]; + Vector3 normal = new Vector3(0, 0, -1); + for (int i = 0; i < vertexCount; i++) + normals[i] = normal; + mesh.normals = normals; + + if (generateTangents) { + Vector4[] tangents = new Vector4[vertexCount]; + Vector4 tangent = new Vector4(1, 0, 0, -1); + for (int i = 0; i < vertexCount; i++) + tangents[i] = tangent; + mesh.tangents = tangents; + } + } + #endif } - - + return new MeshAndMaterials(smartMesh.mesh, sharedMaterials); } - #region Internals - readonly DoubleBuffered doubleBufferedSmartMesh = new DoubleBuffered(); - readonly SubmeshedMeshInstruction currentInstructions = new SubmeshedMeshInstruction(); - - float[] attachmentVertexBuffer = new float[8]; - Vector3[] meshVertices; - Color32[] meshColors32; - Vector2[] meshUVs; - Material[] sharedMaterials = new Material[0]; - readonly ExposedList submeshBuffers = new ExposedList(); - #endregion - #region Types // A SmartMesh is a Mesh (with submeshes) that knows what attachments and instructions were used to generate it. class SmartMesh { diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/SubmeshTriangleBuffer.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/SubmeshTriangleBuffer.cs deleted file mode 100644 index a193b0124..000000000 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/SubmeshTriangleBuffer.cs +++ /dev/null @@ -1,14 +0,0 @@ -using UnityEngine; -using System.Collections; - -namespace Spine.Unity.MeshGeneration { - public class SubmeshTriangleBuffer { - public int[] triangles; - public int triangleCount; - - public SubmeshTriangleBuffer (int triangleCount) { - triangles = new int[triangleCount]; - this.triangleCount = triangleCount; - } - } -} \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Simple/ISimpleMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/ISimpleMeshGenerator.cs similarity index 92% rename from spine-unity/Assets/spine-unity/Mesh Generation/Simple/ISimpleMeshGenerator.cs rename to spine-unity/Assets/spine-unity/Mesh Generation/ISimpleMeshGenerator.cs index 32ed3db51..1fdb9e67a 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Simple/ISimpleMeshGenerator.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/ISimpleMeshGenerator.cs @@ -1,4 +1,4 @@ -namespace Spine.Unity { +namespace Spine.Unity.MeshGeneration { // Typically, each ISpineMeshGenerator implementation will handle double-buffering meshes, handling any other optimization behavior // and operating on assumptions (eg, only handling one skeleton, not updating triangles all the time). // The Scale property allows generated mesh to match external systems like Canvas referencePixelsPerUnit diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Simple/ISimpleMeshGenerator.cs.meta b/spine-unity/Assets/spine-unity/Mesh Generation/ISimpleMeshGenerator.cs.meta similarity index 100% rename from spine-unity/Assets/spine-unity/Mesh Generation/Simple/ISimpleMeshGenerator.cs.meta rename to spine-unity/Assets/spine-unity/Mesh Generation/ISimpleMeshGenerator.cs.meta diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/ISubmeshedMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/ISubmeshedMeshGenerator.cs similarity index 70% rename from spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/ISubmeshedMeshGenerator.cs rename to spine-unity/Assets/spine-unity/Mesh Generation/ISubmeshedMeshGenerator.cs index 72d088fe1..5049da3cc 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/ISubmeshedMeshGenerator.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/ISubmeshedMeshGenerator.cs @@ -24,32 +24,15 @@ namespace Spine.Unity.MeshGeneration { MeshAndMaterials GenerateMesh (ExposedList instructions, int startSubmesh, int endSubmesh); } - // ISingleSubmeshGenerator - // How to use: - // Step 1: Have a single SubmeshInstruction - // Step 2: - public interface ISingleSubmeshGenerator { - Mesh GenerateMesh (SubmeshInstruction instruction); - } - /// Primarily a collection of Submesh Instructions. This constitutes instructions for how to construct a mesh containing submeshes. public class SubmeshedMeshInstruction { public readonly ExposedList submeshInstructions = new ExposedList(); public readonly ExposedList attachmentList = new ExposedList(); public int vertexCount = -1; - /// Allocates a new material array to render this mesh and its constituent submeshes. - public Material[] GetNewMaterialArray () { - var materials = new Material[submeshInstructions.Count]; - FillMaterialArray(materials); - return materials; - } - - /// Fills a given array with the materials needed to render this submeshed mesh. - public void FillMaterialArray (Material[] materialArray) { - var instructionsItems = submeshInstructions.Items; - for (int i = 0, n = materialArray.Length; i < n; i++) - materialArray[i] = instructionsItems[i].material; + /// Returns a material array of the SubmeshedMeshInstruction. Fills the passed array if it's the correct size. Creates a new array if it's a different size. + public Material[] GetUpdatedMaterialArray (Material[] materials) { + return submeshInstructions.GetUpdatedMaterialArray(materials); } } @@ -74,14 +57,16 @@ namespace Spine.Unity.MeshGeneration { } public static class SubmeshInstructionExtensions { - public static void FillMaterialArray (this ExposedList instructions, Material[] materialArray) { - for (int i = 0, n = materialArray.Length; i < n; i++) - materialArray[i] = instructions.Items[i].material; - } + /// Returns a material array of the instructions. Fills the passed array if it's the correct size. Creates a new array if it's a different size. + public static Material[] GetUpdatedMaterialArray (this ExposedList instructions, Material[] materials) { + int submeshCount = instructions.Count; + + if (submeshCount != materials.Length) + materials = new Material[submeshCount]; + + for (int i = 0, n = materials.Length; i < n; i++) + materials[i] = instructions.Items[i].material; - public static Material[] GetNewMaterialArray (this ExposedList instructions) { - var materials = new Material[instructions.Count]; - instructions.FillMaterialArray(materials); return materials; } } @@ -94,6 +79,5 @@ namespace Spine.Unity.MeshGeneration { this.mesh = mesh; this.materials = materials; } - } } \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/ISubmeshedMeshGenerator.cs.meta b/spine-unity/Assets/spine-unity/Mesh Generation/ISubmeshedMeshGenerator.cs.meta similarity index 100% rename from spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/ISubmeshedMeshGenerator.cs.meta rename to spine-unity/Assets/spine-unity/Mesh Generation/ISubmeshedMeshGenerator.cs.meta diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Simple.meta b/spine-unity/Assets/spine-unity/Mesh Generation/Simple.meta deleted file mode 100644 index 49e80b2f1..000000000 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Simple.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 8e1503fd3294b7042a676e58798e4136 -folderAsset: yes -timeCreated: 1455486312 -licenseType: Free -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed.meta b/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed.meta deleted file mode 100644 index a6dc6017c..000000000 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 93a799664eb27fd4183aed06719b306c -folderAsset: yes -timeCreated: 1455486322 -licenseType: Free -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/spine-unity/Assets/spine-unity/Modules/Mesh Generation Samples/VertexHelperSpineMeshGenerator.cs b/spine-unity/Assets/spine-unity/Modules/Mesh Generation Samples/VertexHelperSpineMeshGenerator.cs index 2afc09e6a..0569a6f01 100644 --- a/spine-unity/Assets/spine-unity/Modules/Mesh Generation Samples/VertexHelperSpineMeshGenerator.cs +++ b/spine-unity/Assets/spine-unity/Modules/Mesh Generation Samples/VertexHelperSpineMeshGenerator.cs @@ -28,18 +28,16 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ - #if (UNITY_5_0 || UNITY_5_1 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7) #define PREUNITY_5_2 #endif using UnityEngine; using System.Collections.Generic; -using System.Collections; #if !(PREUNITY_5_2) -namespace Spine.Unity { - /// This is for testing and educational purposes only. This takes about 10 times longer to render than ArraySpineMeshGenerator. +namespace Spine.Unity.MeshGeneration { + /// This is for testing and educational purposes only. This takes about 10 times longer to render than the Arrays implementations. public class VertexHelperSpineMeshGenerator : ISimpleMeshGenerator { public float scale = 1f; diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs index 6b2b8c9b5..5ea33c939 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs @@ -1,195 +1,226 @@ -#if (UNITY_5_0 || UNITY_5_1 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7) +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.3 + * + * Copyright (c) 2013-2015, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to use, install, execute and perform the Spine + * Runtimes Software (the "Software") and derivative works solely for personal + * or internal use. Without the written permission of Esoteric Software (see + * Section 2 of the Spine Software License Agreement), you may not (a) modify, + * translate, adapt or otherwise create derivative works, improvements of the + * Software or develop new applications using the Software or (b) remove, + * delete, alter or obscure any trademarks or any copyright, trademark, patent + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) 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 THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +#if (UNITY_5_0 || UNITY_5_1 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7) #define PREUNITY_5_2 #endif using UnityEngine; -using System.Collections; - using UnityEditor; using Spine; -[CustomEditor(typeof(SkeletonGraphic))] -public class SkeletonGraphicInspector : Editor { - SerializedProperty material_, color_; - SerializedProperty skeletonDataAsset_, initialSkinName_; - SerializedProperty startingAnimation_, startingLoop_, timeScale_, freeze_; -#if !PREUNITY_5_2 - SerializedProperty raycastTarget_; +namespace Spine.Unity { + + [CustomEditor(typeof(SkeletonGraphic))] + public class SkeletonGraphicInspector : Editor { + SerializedProperty material_, color_; + SerializedProperty skeletonDataAsset_, initialSkinName_; + SerializedProperty startingAnimation_, startingLoop_, timeScale_, freeze_; + #if !PREUNITY_5_2 + SerializedProperty raycastTarget_; - SkeletonGraphic thisSkeletonGraphic; + SkeletonGraphic thisSkeletonGraphic; - void OnEnable () { - var so = this.serializedObject; - thisSkeletonGraphic = target as SkeletonGraphic; + void OnEnable () { + var so = this.serializedObject; + thisSkeletonGraphic = target as SkeletonGraphic; - // MaskableGraphic - material_ = so.FindProperty("m_Material"); - color_ = so.FindProperty("m_Color"); - raycastTarget_ = so.FindProperty("m_RaycastTarget"); + // MaskableGraphic + material_ = so.FindProperty("m_Material"); + color_ = so.FindProperty("m_Color"); + raycastTarget_ = so.FindProperty("m_RaycastTarget"); - // SkeletonRenderer - skeletonDataAsset_ = so.FindProperty("skeletonDataAsset"); - initialSkinName_ = so.FindProperty("initialSkinName"); + // SkeletonRenderer + skeletonDataAsset_ = so.FindProperty("skeletonDataAsset"); + initialSkinName_ = so.FindProperty("initialSkinName"); - // SkeletonAnimation - startingAnimation_ = so.FindProperty("startingAnimation"); - startingLoop_ = so.FindProperty("startingLoop"); - timeScale_ = so.FindProperty("timeScale"); - freeze_ = so.FindProperty("freeze"); - } - - public override void OnInspectorGUI () { - EditorGUI.BeginChangeCheck(); - - EditorGUILayout.PropertyField(skeletonDataAsset_); - EditorGUILayout.PropertyField(material_); - EditorGUILayout.PropertyField(color_); - - if (thisSkeletonGraphic.skeletonDataAsset == null) { - EditorGUILayout.HelpBox("You need to assign a SkeletonDataAsset first.", MessageType.Info); - serializedObject.ApplyModifiedProperties(); - serializedObject.Update(); - return; + // SkeletonAnimation + startingAnimation_ = so.FindProperty("startingAnimation"); + startingLoop_ = so.FindProperty("startingLoop"); + timeScale_ = so.FindProperty("timeScale"); + freeze_ = so.FindProperty("freeze"); } - EditorGUILayout.Space(); - EditorGUILayout.PropertyField(initialSkinName_); - EditorGUILayout.Space(); - EditorGUILayout.LabelField("Animation", EditorStyles.boldLabel); - EditorGUILayout.PropertyField(startingAnimation_); - EditorGUILayout.PropertyField(startingLoop_); - EditorGUILayout.PropertyField(timeScale_); - EditorGUILayout.Space(); - EditorGUILayout.PropertyField(freeze_); - EditorGUILayout.Space(); - EditorGUILayout.LabelField("UI", EditorStyles.boldLabel); - EditorGUILayout.PropertyField(raycastTarget_); + public override void OnInspectorGUI () { + EditorGUI.BeginChangeCheck(); - bool wasChanged = EditorGUI.EndChangeCheck(); + EditorGUILayout.PropertyField(skeletonDataAsset_); + EditorGUILayout.PropertyField(material_); + EditorGUILayout.PropertyField(color_); - if (wasChanged) { - serializedObject.ApplyModifiedProperties(); - } - } - - #region Menus - [MenuItem("CONTEXT/SkeletonGraphic/Match RectTransform with Mesh Bounds")] - static void MatchRectTransformWithBounds (MenuCommand command) { - var skeletonGraphic = (SkeletonGraphic)command.context; - var mesh = skeletonGraphic.SpineMeshGenerator.LastGeneratedMesh; - - var bounds = mesh.bounds; - var size = bounds.size; - var center = bounds.center; - var p = new Vector2( - 0.5f - (center.x / size.x), - 0.5f - (center.y / size.y) - ); - - skeletonGraphic.rectTransform.sizeDelta = size; - skeletonGraphic.rectTransform.pivot = p; - } - - public static Material DefaultSkeletonGraphicMaterial { - get { - var guids = AssetDatabase.FindAssets("SkeletonGraphicDefault t:material"); - if (guids.Length <= 0) - return null; - var firstAssetPath = AssetDatabase.GUIDToAssetPath(guids[0]); - if (string.IsNullOrEmpty(firstAssetPath)) - return null; - var firstMaterial = AssetDatabase.LoadAssetAtPath(firstAssetPath); - return firstMaterial; - } - } - - [MenuItem("GameObject/Spine/SkeletonGraphic (UnityUI)", false, 10)] - static public void SkeletonGraphicCreateMenuItem () { - var parentGameObject = Selection.activeObject as GameObject; - var parentTransform = parentGameObject == null ? null : parentGameObject.GetComponent(); - - if (parentTransform == null) { - Debug.LogWarning("Your new SkeletonGraphic will not be visible until it is placed under a Canvas"); - } - - var gameObject = NewSkeletonGraphicGameObject("New SkeletonGraphic"); - gameObject.transform.SetParent(parentTransform, false); - EditorUtility.FocusProjectWindow(); - Selection.activeObject = gameObject; - EditorGUIUtility.PingObject(Selection.activeObject); - } - - [MenuItem("Assets/Spine/Instantiate (UnityUI)", false, 0)] - static void InstantiateSkeletonGraphic () { - Object[] arr = Selection.objects; - foreach (Object o in arr) { - string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(o)); - string skinName = EditorPrefs.GetString(guid + "_lastSkin", ""); - - InstantiateSkeletonGraphic((SkeletonDataAsset)o, skinName); - SceneView.RepaintAll(); - } - } - - [MenuItem("Assets/Spine/Instantiate (UnityUI)", true, 0)] - static bool ValidateInstantiateSkeletonGraphic () { - Object[] arr = Selection.objects; - - if (arr.Length == 0) - return false; - - foreach (var selected in arr) { - if (selected.GetType() != typeof(SkeletonDataAsset)) - return false; - } - - return true; - } - - public static SkeletonGraphic InstantiateSkeletonGraphic (SkeletonDataAsset skeletonDataAsset, string skinName) { - return InstantiateSkeletonGraphic(skeletonDataAsset, skeletonDataAsset.GetSkeletonData(true).FindSkin(skinName)); - } - - public static SkeletonGraphic InstantiateSkeletonGraphic (SkeletonDataAsset skeletonDataAsset, Skin skin = null) { - string spineGameObjectName = string.Format("SkeletonGraphic ({0})", skeletonDataAsset.name.Replace("_SkeletonData", "")); - var go = NewSkeletonGraphicGameObject(spineGameObjectName); - var graphic = go.GetComponent(); - graphic.skeletonDataAsset = skeletonDataAsset; - - SkeletonData data = skeletonDataAsset.GetSkeletonData(true); - - if (data == null) { - for (int i = 0; i < skeletonDataAsset.atlasAssets.Length; i++) { - string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAssets[i]); - skeletonDataAsset.atlasAssets[i] = (AtlasAsset)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAsset)); + if (thisSkeletonGraphic.skeletonDataAsset == null) { + EditorGUILayout.HelpBox("You need to assign a SkeletonDataAsset first.", MessageType.Info); + serializedObject.ApplyModifiedProperties(); + serializedObject.Update(); + return; } - data = skeletonDataAsset.GetSkeletonData(true); + EditorGUILayout.Space(); + EditorGUILayout.PropertyField(initialSkinName_); + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Animation", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(startingAnimation_); + EditorGUILayout.PropertyField(startingLoop_); + EditorGUILayout.PropertyField(timeScale_); + EditorGUILayout.Space(); + EditorGUILayout.PropertyField(freeze_); + EditorGUILayout.Space(); + EditorGUILayout.LabelField("UI", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(raycastTarget_); + + bool wasChanged = EditorGUI.EndChangeCheck(); + + if (wasChanged) { + serializedObject.ApplyModifiedProperties(); + } } - if (skin == null) - skin = data.DefaultSkin; + #region Menus + [MenuItem("CONTEXT/SkeletonGraphic/Match RectTransform with Mesh Bounds")] + static void MatchRectTransformWithBounds (MenuCommand command) { + var skeletonGraphic = (SkeletonGraphic)command.context; + var mesh = skeletonGraphic.SpineMeshGenerator.LastGeneratedMesh; - if (skin == null) - skin = data.Skins.Items[0]; + var bounds = mesh.bounds; + var size = bounds.size; + var center = bounds.center; + var p = new Vector2( + 0.5f - (center.x / size.x), + 0.5f - (center.y / size.y) + ); - graphic.Initialize(false); - graphic.Skeleton.SetSkin(skin); - graphic.initialSkinName = skin.Name; - graphic.Skeleton.UpdateWorldTransform(); - graphic.UpdateMesh(); + skeletonGraphic.rectTransform.sizeDelta = size; + skeletonGraphic.rectTransform.pivot = p; + } - return graphic; + public static Material DefaultSkeletonGraphicMaterial { + get { + var guids = AssetDatabase.FindAssets("SkeletonGraphicDefault t:material"); + if (guids.Length <= 0) + return null; + var firstAssetPath = AssetDatabase.GUIDToAssetPath(guids[0]); + if (string.IsNullOrEmpty(firstAssetPath)) + return null; + var firstMaterial = AssetDatabase.LoadAssetAtPath(firstAssetPath); + return firstMaterial; + } + } + + [MenuItem("GameObject/Spine/SkeletonGraphic (UnityUI)", false, 10)] + static public void SkeletonGraphicCreateMenuItem () { + var parentGameObject = Selection.activeObject as GameObject; + var parentTransform = parentGameObject == null ? null : parentGameObject.GetComponent(); + + if (parentTransform == null) { + Debug.LogWarning("Your new SkeletonGraphic will not be visible until it is placed under a Canvas"); + } + + var gameObject = NewSkeletonGraphicGameObject("New SkeletonGraphic"); + gameObject.transform.SetParent(parentTransform, false); + EditorUtility.FocusProjectWindow(); + Selection.activeObject = gameObject; + EditorGUIUtility.PingObject(Selection.activeObject); + } + + [MenuItem("Assets/Spine/Instantiate (UnityUI)", false, 0)] + static void InstantiateSkeletonGraphic () { + Object[] arr = Selection.objects; + foreach (Object o in arr) { + string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(o)); + string skinName = EditorPrefs.GetString(guid + "_lastSkin", ""); + + InstantiateSkeletonGraphic((SkeletonDataAsset)o, skinName); + SceneView.RepaintAll(); + } + } + + [MenuItem("Assets/Spine/Instantiate (UnityUI)", true, 0)] + static bool ValidateInstantiateSkeletonGraphic () { + Object[] arr = Selection.objects; + + if (arr.Length == 0) + return false; + + foreach (var selected in arr) { + if (selected.GetType() != typeof(SkeletonDataAsset)) + return false; + } + + return true; + } + + public static SkeletonGraphic InstantiateSkeletonGraphic (SkeletonDataAsset skeletonDataAsset, string skinName) { + return InstantiateSkeletonGraphic(skeletonDataAsset, skeletonDataAsset.GetSkeletonData(true).FindSkin(skinName)); + } + + public static SkeletonGraphic InstantiateSkeletonGraphic (SkeletonDataAsset skeletonDataAsset, Skin skin = null) { + string spineGameObjectName = string.Format("SkeletonGraphic ({0})", skeletonDataAsset.name.Replace("_SkeletonData", "")); + var go = NewSkeletonGraphicGameObject(spineGameObjectName); + var graphic = go.GetComponent(); + graphic.skeletonDataAsset = skeletonDataAsset; + + SkeletonData data = skeletonDataAsset.GetSkeletonData(true); + + if (data == null) { + for (int i = 0; i < skeletonDataAsset.atlasAssets.Length; i++) { + string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAssets[i]); + skeletonDataAsset.atlasAssets[i] = (AtlasAsset)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAsset)); + } + + data = skeletonDataAsset.GetSkeletonData(true); + } + + if (skin == null) + skin = data.DefaultSkin; + + if (skin == null) + skin = data.Skins.Items[0]; + + graphic.Initialize(false); + graphic.Skeleton.SetSkin(skin); + graphic.initialSkinName = skin.Name; + graphic.Skeleton.UpdateWorldTransform(); + graphic.UpdateMesh(); + + return graphic; + } + + static GameObject NewSkeletonGraphicGameObject (string gameObjectName) { + var go = new GameObject(gameObjectName, typeof(RectTransform), typeof(CanvasRenderer), typeof(SkeletonGraphic)); + var graphic = go.GetComponent(); + graphic.material = SkeletonGraphicInspector.DefaultSkeletonGraphicMaterial; + return go; + } + + #endregion + + #endif } - - static GameObject NewSkeletonGraphicGameObject (string gameObjectName) { - var go = new GameObject(gameObjectName, typeof(RectTransform), typeof(CanvasRenderer), typeof(SkeletonGraphic)); - var graphic = go.GetComponent(); - graphic.material = SkeletonGraphicInspector.DefaultSkeletonGraphicMaterial; - return go; - } - - #endregion - -#endif -} +} \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs index 778495f65..39c101b35 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs @@ -28,194 +28,194 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ - #if (UNITY_5_0 || UNITY_5_1 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7) #define PREUNITY_5_2 #endif using UnityEngine; -using System.Collections; using UnityEngine.UI; using Spine; -[ExecuteInEditMode, RequireComponent(typeof(CanvasRenderer), typeof(RectTransform)), DisallowMultipleComponent] -[AddComponentMenu("Spine/SkeletonGraphic (Unity UI Canvas)")] -public class SkeletonGraphic : MaskableGraphic { +namespace Spine.Unity { + [ExecuteInEditMode, RequireComponent(typeof(CanvasRenderer), typeof(RectTransform)), DisallowMultipleComponent] + [AddComponentMenu("Spine/SkeletonGraphic (Unity UI Canvas)")] + public class SkeletonGraphic : MaskableGraphic { - #region Inspector - public SkeletonDataAsset skeletonDataAsset; + #region Inspector + public SkeletonDataAsset skeletonDataAsset; - [SpineSkin(dataField:"skeletonDataAsset")] - public string initialSkinName = "default"; + [SpineSkin(dataField:"skeletonDataAsset")] + public string initialSkinName = "default"; - [SpineAnimation(dataField:"skeletonDataAsset")] - public string startingAnimation; - public bool startingLoop; - public float timeScale = 1f; - public bool freeze; + [SpineAnimation(dataField:"skeletonDataAsset")] + public string startingAnimation; + public bool startingLoop; + public float timeScale = 1f; + public bool freeze; - #if UNITY_EDITOR - protected override void OnValidate () { - // This handles Scene View preview. - base.OnValidate (); - #if !PREUNITY_5_2 - if (this.IsValid) { - if (skeletonDataAsset == null) { - Clear(); - startingAnimation = ""; - } else if (skeletonDataAsset.GetSkeletonData(true) != skeleton.data) { - Clear(); - Initialize(true); - startingAnimation = ""; - if (skeletonDataAsset.atlasAssets.Length > 1 || skeletonDataAsset.atlasAssets[0].materials.Length > 1) { - Debug.LogError("Unity UI does not support multiple textures per Renderer. Your skeleton will not be rendered correctly. Recommend using SkeletonAnimation instead. This requires the use of a Screen space camera canvas."); + #if UNITY_EDITOR + protected override void OnValidate () { + // This handles Scene View preview. + base.OnValidate (); + #if !PREUNITY_5_2 + if (this.IsValid) { + if (skeletonDataAsset == null) { + Clear(); + startingAnimation = ""; + } else if (skeletonDataAsset.GetSkeletonData(true) != skeleton.data) { + Clear(); + Initialize(true); + startingAnimation = ""; + if (skeletonDataAsset.atlasAssets.Length > 1 || skeletonDataAsset.atlasAssets[0].materials.Length > 1) { + Debug.LogError("Unity UI does not support multiple textures per Renderer. Your skeleton will not be rendered correctly. Recommend using SkeletonAnimation instead. This requires the use of a Screen space camera canvas."); + } + } else { + if (freeze) return; + skeleton.SetToSetupPose(); + if (!string.IsNullOrEmpty(startingAnimation)) { + skeleton.PoseWithAnimation(startingAnimation, 0f, false); + } } } else { - if (freeze) return; - skeleton.SetToSetupPose(); - if (!string.IsNullOrEmpty(startingAnimation)) { - skeleton.PoseWithAnimation(startingAnimation, 0f, false); - } + if (skeletonDataAsset != null) + Initialize(true); + } + #else + Debug.LogWarning("SkeletonGraphic requres Unity 5.2 or higher.\nUnityEngine.UI 5.1 and below does not accept meshes and can't be used to render Spine skeletons. You may delete the SkeletonGraphic folder under `Modules` if you want to exclude it from your project." ); + #endif + + } + + protected override void Reset () { + base.Reset(); + if (canvas == null) { + Debug.LogWarningFormat("SkeletonGraphic requires a Canvas to be visible. Move this GameObject ({0}) in the Hierarchy so it becomes a child of a Canvas.", gameObject.name); + } + + if (material == null || material.shader != Shader.Find("Spine/SkeletonGraphic (Premultiply Alpha)")) { + Debug.LogWarning("SkeletonGraphic works best with the SkeletonGraphic material."); } - } else { - if (skeletonDataAsset != null) - Initialize(true); } - #else - Debug.LogWarning("SkeletonGraphic requres Unity 5.2 or higher.\nUnityEngine.UI 5.1 and below does not accept meshes and can't be used to render Spine skeletons. You may delete the SkeletonGraphic folder under `Modules` if you want to exclude it from your project." ); #endif - - } + #endregion - protected override void Reset () { - base.Reset(); - if (canvas == null) { - Debug.LogWarningFormat("SkeletonGraphic requires a Canvas to be visible. Move this GameObject ({0}) in the Hierarchy so it becomes a child of a Canvas.", gameObject.name); + #if !PREUNITY_5_2 + #region Internals + // This is used by the UI system to determine what to put in the MaterialPropertyBlock. + public override Texture mainTexture { + get { + // Fail loudly when incorrectly set up. + return skeletonDataAsset == null ? null : skeletonDataAsset.atlasAssets[0].materials[0].mainTexture; + } } - if (material == null || material.shader != Shader.Find("Spine/SkeletonGraphic (Premultiply Alpha)")) { - Debug.LogWarning("SkeletonGraphic works best with the SkeletonGraphic material."); + protected override void Awake () { + base.Awake (); + if (!this.IsValid) { + Initialize(false); + Rebuild(CanvasUpdate.PreRender); + } } - } - #endif - #endregion - #if !PREUNITY_5_2 - #region Internals - // This is used by the UI system to determine what to put in the MaterialPropertyBlock. - public override Texture mainTexture { - get { - // Fail loudly when incorrectly set up. - return skeletonDataAsset == null ? null : skeletonDataAsset.atlasAssets[0].materials[0].mainTexture; + public override void Rebuild (CanvasUpdate update) { + base.Rebuild(update); + if (canvasRenderer.cull) return; + if (update == CanvasUpdate.PreRender) UpdateMesh(); } - } - protected override void Awake () { - base.Awake (); - if (!this.IsValid) { - Initialize(false); - Rebuild(CanvasUpdate.PreRender); + public virtual void Update () { + if (freeze) return; + Update(Time.deltaTime); } - } - public override void Rebuild (CanvasUpdate update) { - base.Rebuild(update); - if (canvasRenderer.cull) return; - if (update == CanvasUpdate.PreRender) UpdateMesh(); - } + public virtual void Update (float deltaTime) { + if (!this.IsValid) return; - public virtual void Update () { - if (freeze) return; - Update(Time.deltaTime); - } + deltaTime *= timeScale; + skeleton.Update(deltaTime); + state.Update(deltaTime); + state.Apply(skeleton); - public virtual void Update (float deltaTime) { - if (!this.IsValid) return; + if (UpdateLocal != null) UpdateLocal(this); - deltaTime *= timeScale; - skeleton.Update(deltaTime); - state.Update(deltaTime); - state.Apply(skeleton); - - if (UpdateLocal != null) UpdateLocal(this); - - skeleton.UpdateWorldTransform(); - - if (UpdateWorld != null) { - UpdateWorld(this); skeleton.UpdateWorldTransform(); + + if (UpdateWorld != null) { + UpdateWorld(this); + skeleton.UpdateWorldTransform(); + } + + if (UpdateComplete != null) UpdateComplete(this); } - if (UpdateComplete != null) UpdateComplete(this); - } + void LateUpdate () { + if (freeze) return; + //this.SetVerticesDirty(); // Which is better? + UpdateMesh(); + } + #endregion - void LateUpdate () { - if (freeze) return; - //this.SetVerticesDirty(); // Which is better? - UpdateMesh(); - } - #endregion + #region API + protected Skeleton skeleton; + public Skeleton Skeleton { get { return skeleton; } } + public SkeletonData SkeletonData { get { return skeleton == null ? null : skeleton.data; } } + public bool IsValid { get { return skeleton != null; } } - #region API - protected Skeleton skeleton; - public Skeleton Skeleton { get { return skeleton; } } - public SkeletonData SkeletonData { get { return skeleton == null ? null : skeleton.data; } } - public bool IsValid { get { return skeleton != null; } } + protected Spine.AnimationState state; + public Spine.AnimationState AnimationState { get { return state; } } - protected Spine.AnimationState state; - public Spine.AnimationState AnimationState { get { return state; } } + // This is any object that can give you a mesh when you give it a skeleton to render. + protected Spine.Unity.MeshGeneration.ISimpleMeshGenerator spineMeshGenerator; + public Spine.Unity.MeshGeneration.ISimpleMeshGenerator SpineMeshGenerator { get { return this.spineMeshGenerator; } } - // This is any object that can give you a mesh when you give it a skeleton to render. - protected Spine.Unity.ISimpleMeshGenerator spineMeshGenerator; - public Spine.Unity.ISimpleMeshGenerator SpineMeshGenerator { get { return this.spineMeshGenerator; } } + public delegate void UpdateDelegate (SkeletonGraphic skeletonGraphic); + public event UpdateDelegate UpdateLocal; + public event UpdateDelegate UpdateWorld; + public event UpdateDelegate UpdateComplete; - public delegate void UpdateDelegate (SkeletonGraphic skeletonGraphic); - public event UpdateDelegate UpdateLocal; - public event UpdateDelegate UpdateWorld; - public event UpdateDelegate UpdateComplete; - - public void Clear () { - skeleton = null; - canvasRenderer.Clear(); - } - - public void Initialize (bool overwrite) { - if (this.IsValid && !overwrite) return; - - // Make sure none of the stuff is null - if (this.skeletonDataAsset == null) return; - var skeletonData = this.skeletonDataAsset.GetSkeletonData(false); - if (skeletonData == null) return; - - if (skeletonDataAsset.atlasAssets.Length <= 0 || skeletonDataAsset.atlasAssets[0].materials.Length <= 0) return; - - this.state = new Spine.AnimationState(skeletonDataAsset.GetAnimationStateData()); - if (state == null) { - Clear(); - return; + public void Clear () { + skeleton = null; + canvasRenderer.Clear(); } - this.skeleton = new Skeleton(skeletonData); - this.spineMeshGenerator = new Spine.Unity.ArraysSimpleMeshGenerator(); // You can switch this out with any other implementer of ISpineMeshGenerator + public void Initialize (bool overwrite) { + if (this.IsValid && !overwrite) return; - // Set the initial Skin and Animation - if (!string.IsNullOrEmpty(initialSkinName)) - skeleton.SetSkin(initialSkinName); + // Make sure none of the stuff is null + if (this.skeletonDataAsset == null) return; + var skeletonData = this.skeletonDataAsset.GetSkeletonData(false); + if (skeletonData == null) return; - if (!string.IsNullOrEmpty(startingAnimation)) - state.SetAnimation(0, startingAnimation, startingLoop); - } + if (skeletonDataAsset.atlasAssets.Length <= 0 || skeletonDataAsset.atlasAssets[0].materials.Length <= 0) return; - public void UpdateMesh () { - if (this.IsValid) { - skeleton.SetColor(this.color); - if (canvas != null) - spineMeshGenerator.Scale = canvas.referencePixelsPerUnit; // TODO: move this to a listener to of the canvas? + this.state = new Spine.AnimationState(skeletonDataAsset.GetAnimationStateData()); + if (state == null) { + Clear(); + return; + } - canvasRenderer.SetMesh(spineMeshGenerator.GenerateMesh(skeleton)); - this.UpdateMaterial(); + this.skeleton = new Skeleton(skeletonData); + this.spineMeshGenerator = new Spine.Unity.MeshGeneration.ArraysSimpleMeshGenerator(); // You can switch this out with any other implementer of Spine.Unity.MeshGeneration.ISimpleMeshGenerator + + // Set the initial Skin and Animation + if (!string.IsNullOrEmpty(initialSkinName)) + skeleton.SetSkin(initialSkinName); + + if (!string.IsNullOrEmpty(startingAnimation)) + state.SetAnimation(0, startingAnimation, startingLoop); } + + public void UpdateMesh () { + if (this.IsValid) { + skeleton.SetColor(this.color); + if (canvas != null) + spineMeshGenerator.Scale = canvas.referencePixelsPerUnit; // TODO: move this to a listener to of the canvas? + + canvasRenderer.SetMesh(spineMeshGenerator.GenerateMesh(skeleton)); + this.UpdateMaterial(); + } + } + #endregion + #endif } - #endregion - #endif -} +} \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs index 57480528f..870a5bec8 100644 --- a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs +++ b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs @@ -28,6 +28,9 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ +#define SPINE_OPTIONAL_NORMALS +#define SPINE_OPTIONAL_FRONTFACING + using System; using System.Collections.Generic; using UnityEngine; @@ -46,10 +49,14 @@ public class SkeletonRenderer : MonoBehaviour { public String initialSkinName; #region Advanced + #if SPINE_OPTIONAL_NORMALS public bool calculateNormals, calculateTangents; + #endif public float zSpacing; public bool renderMeshes = true, immutableTriangles; + #if SPINE_OPTIONAL_FRONTFACING public bool frontFacing; + #endif public bool logErrors = false; // Submesh Separation @@ -83,8 +90,10 @@ public class SkeletonRenderer : MonoBehaviour { readonly ExposedList submeshMaterials = new ExposedList(); Material[] sharedMaterials = new Material[0]; + #if SPINE_OPTIONAL_NORMALS Vector3[] normals; Vector4[] tangents; + #endif #region Runtime Instantiation public static T NewSpineGameObject (SkeletonDataAsset skeletonDataAsset) where T : SkeletonRenderer { @@ -169,7 +178,7 @@ public class SkeletonRenderer : MonoBehaviour { if (!meshRenderer.enabled && GenerateMeshOverride == null) return; - // Step 1. Determine a SmartMesh.Instruction. Split up instructions into submeshes. + // STEP 1. Determine a SmartMesh.Instruction. Split up instructions into submeshes. // This method caches several .Items arrays. // Never mutate their overlying ExposedList objects. @@ -187,12 +196,13 @@ public class SkeletonRenderer : MonoBehaviour { workingAttachments.Count = drawOrderCount; var workingAttachmentsItems = workingInstruction.attachments.Items; - // SPINE_DETECT_FLIPS + #if SPINE_OPTIONAL_FRONTFACING var workingFlips = workingInstruction.attachmentFlips; workingFlips.Clear(false); workingFlips.GrowIfNeeded(drawOrderCount); workingFlips.Count = drawOrderCount; var workingFlipsItems = workingFlips.Items; + #endif var workingSubmeshInstructions = workingInstruction.submeshInstructions; // Items array should not be cached. There is dynamic writing to this list. workingSubmeshInstructions.Clear(false); @@ -209,9 +219,10 @@ public class SkeletonRenderer : MonoBehaviour { workingAttachmentsItems[i] = attachment; - // SPINE_DETECT_FLIPS + #if SPINE_OPTIONAL_FRONTFACING bool flip = frontFacing && (slot.bone.WorldSignX != slot.bone.WorldSignY); workingFlipsItems[i] = flip; + #endif object rendererObject; // An AtlasRegion in plain Spine-Unity. Spine-TK2D hooks into TK2D's system. eventual source of Material object. int attachmentVertexCount, attachmentTriangleCount; @@ -298,14 +309,16 @@ public class SkeletonRenderer : MonoBehaviour { workingInstruction.vertexCount = vertexCount; workingInstruction.immutableTriangles = this.immutableTriangles; + #if SPINE_OPTIONAL_FRONTFACING workingInstruction.frontFacing = this.frontFacing; + #endif if (GenerateMeshOverride != null) { GenerateMeshOverride(workingInstruction); return; } - // Step 2. Update vertex buffer based on verts from the attachments. + // STEP 2. Update vertex buffer based on verts from the attachments. // Uses values that were also stored in workingInstruction. Vector3[] vertices = this.vertices; bool vertexCountIncreased = vertexCount > vertices.Length; @@ -315,6 +328,7 @@ public class SkeletonRenderer : MonoBehaviour { this.colors = new Color32[vertexCount]; this.uvs = new Vector2[vertexCount]; + #if SPINE_OPTIONAL_NORMALS if (calculateNormals) { Vector3[] localNormals = this.normals = new Vector3[vertexCount]; Vector3 normal = new Vector3(0, 0, -1); @@ -328,6 +342,7 @@ public class SkeletonRenderer : MonoBehaviour { localTangents[i] = tangent; } } + #endif } else { Vector3 zero = Vector3.zero; for (int i = vertexCount, n = vertices.Length; i < n; i++) @@ -526,6 +541,7 @@ public class SkeletonRenderer : MonoBehaviour { currentMesh.colors32 = colors; currentMesh.uv = uvs; var currentSmartMeshInstructionUsed = currentSmartMesh.instructionUsed; + #if SPINE_OPTIONAL_NORMALS if (currentSmartMeshInstructionUsed.vertexCount < vertexCount) { if (calculateNormals) { currentMesh.normals = normals; @@ -534,6 +550,7 @@ public class SkeletonRenderer : MonoBehaviour { } } } + #endif // Check if the triangles should also be updated. // This thorough structure check is cheaper than updating triangles every frame. @@ -553,7 +570,11 @@ public class SkeletonRenderer : MonoBehaviour { for (int i = 0, last = submeshCount - 1; i < submeshCount; i++) { var submeshInstruction = workingSubmeshInstructions.Items[i]; if (mutableTriangles || i >= oldSubmeshCount) - SetSubmesh(i, submeshInstruction, currentInstructions.attachmentFlips, i == last); + SetSubmesh(i, submeshInstruction, + #if SPINE_OPTIONAL_FRONTFACING + currentInstructions.attachmentFlips, + #endif + i == last); thisSubmeshMaterials.Add(submeshInstruction.material); } @@ -627,7 +648,7 @@ public class SkeletonRenderer : MonoBehaviour { return true; } - // SPINE_DETECT_FLIPS + #if SPINE_OPTIONAL_FRONTFACING if (a.frontFacing != b.frontFacing) { // if settings changed return true; } else if (a.frontFacing) { // if settings matched, only need to check one. @@ -638,6 +659,7 @@ public class SkeletonRenderer : MonoBehaviour { return true; } } + #endif // Submesh count changed int submeshCountA = a.submeshInstructions.Count; @@ -664,8 +686,12 @@ public class SkeletonRenderer : MonoBehaviour { return false; } - + + #if SPINE_OPTIONAL_FRONTFACING void SetSubmesh (int submeshIndex, Spine.Unity.MeshGeneration.SubmeshInstruction submeshInstructions, ExposedList flipStates, bool isLastSubmesh) { + #else + void SetSubmesh (int submeshIndex, Spine.Unity.MeshGeneration.SubmeshInstruction submeshInstructions, bool isLastSubmesh) { + #endif SubmeshTriangleBuffer currentSubmesh = submeshes.Items[submeshIndex]; int[] triangles = currentSubmesh.triangles; @@ -686,7 +712,11 @@ public class SkeletonRenderer : MonoBehaviour { currentSubmesh.triangleCount = 0; } + #if SPINE_OPTIONAL_FRONTFACING if (!this.renderMeshes && !this.frontFacing) { + #else + if (!this.renderMeshes) { + #endif // Use stored triangles if possible. if (currentSubmesh.firstVertex != firstVertex || currentSubmesh.triangleCount < triangleCount) { //|| currentSubmesh.triangleCount == 0 currentSubmesh.triangleCount = triangleCount; @@ -707,20 +737,20 @@ public class SkeletonRenderer : MonoBehaviour { // This method caches several .Items arrays. // Never mutate their overlying ExposedList objects. + #if SPINE_OPTIONAL_FRONTFACING + var flipStatesItems = flipStates.Items; + #endif + // Iterate through all slots and store their triangles. var drawOrderItems = skeleton.DrawOrder.Items; - // SPINE_DETECT_FLIPS - var flipStatesItems = flipStates.Items; - int triangleIndex = 0; // Modified by loop for (int i = submeshInstructions.startSlot, n = submeshInstructions.endSlot; i < n; i++) { Attachment attachment = drawOrderItems[i].attachment; - // SPINE_DETECT_FLIPS + #if SPINE_OPTIONAL_FRONTFACING bool flip = frontFacing && flipStatesItems[i]; // Add RegionAttachment triangles if (attachment is RegionAttachment) { - // SPINE_DETECT_FLIPS if (!flip) { triangles[triangleIndex] = firstVertex; triangles[triangleIndex + 1] = firstVertex + 2; @@ -741,6 +771,20 @@ public class SkeletonRenderer : MonoBehaviour { firstVertex += 4; continue; } + #else + if (attachment is RegionAttachment) { + triangles[triangleIndex] = firstVertex; + triangles[triangleIndex + 1] = firstVertex + 2; + triangles[triangleIndex + 2] = firstVertex + 1; + triangles[triangleIndex + 3] = firstVertex + 2; + triangles[triangleIndex + 4] = firstVertex + 3; + triangles[triangleIndex + 5] = firstVertex + 1; + + triangleIndex += 6; + firstVertex += 4; + continue; + } + #endif // Add (Weighted)MeshAttachment triangles int[] attachmentTriangles; @@ -758,7 +802,7 @@ public class SkeletonRenderer : MonoBehaviour { continue; } - // SPINE_DETECT_FLIPS + #if SPINE_OPTIONAL_FRONTFACING if (flip) { for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii += 3, triangleIndex += 3) { triangles[triangleIndex + 2] = firstVertex + attachmentTriangles[ii]; @@ -770,6 +814,12 @@ public class SkeletonRenderer : MonoBehaviour { triangles[triangleIndex] = firstVertex + attachmentTriangles[ii]; } } + #else + for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++) { + triangles[triangleIndex] = firstVertex + attachmentTriangles[ii]; + } + #endif + firstVertex += attachmentVertexCount; } } @@ -797,21 +847,26 @@ public class SkeletonRenderer : MonoBehaviour { public class Instruction { public bool immutableTriangles; - public bool frontFacing; public int vertexCount = -1; public readonly ExposedList attachments = new ExposedList(); - public readonly ExposedList attachmentFlips = new ExposedList(); public readonly ExposedList submeshInstructions = new ExposedList(); + #if SPINE_OPTIONAL_FRONTFACING + public bool frontFacing; + public readonly ExposedList attachmentFlips = new ExposedList(); + #endif + public void Clear () { this.attachments.Clear(false); - this.attachmentFlips.Clear(false); this.submeshInstructions.Clear(false); + + #if SPINE_OPTIONAL_FRONTFACING + this.attachmentFlips.Clear(false); + #endif } public void Set (Instruction other) { this.immutableTriangles = other.immutableTriangles; - this.frontFacing = other.frontFacing; this.vertexCount = other.vertexCount; this.attachments.Clear(false); @@ -819,13 +874,14 @@ public class SkeletonRenderer : MonoBehaviour { this.attachments.Count = other.attachments.Count; other.attachments.CopyTo(this.attachments.Items); - // SPINE_DETECT_FLIPS + #if SPINE_OPTIONAL_FRONTFACING + this.frontFacing = other.frontFacing; this.attachmentFlips.Clear(false); this.attachmentFlips.GrowIfNeeded(other.attachmentFlips.Capacity); this.attachmentFlips.Count = other.attachmentFlips.Count; if (this.frontFacing) other.attachmentFlips.CopyTo(this.attachmentFlips.Items); - + #endif this.submeshInstructions.Clear(false); this.submeshInstructions.GrowIfNeeded(other.submeshInstructions.Capacity);