From 8e8b5e39049f1ced18a63f826c34d7fc86830716 Mon Sep 17 00:00:00 2001 From: pharan Date: Wed, 16 Mar 2016 02:47:22 +0800 Subject: [PATCH] Multiple submeshes per part. --- .../{Submeshed => }/Arrays.meta | 0 .../Mesh Generation/Arrays/ArraysBuffers.cs | 149 ++++++ .../Arrays/ArraysBuffers.cs.meta} | 4 +- .../ArraysSimpleMeshGenerator.cs | 130 +---- .../ArraysSimpleMeshGenerator.cs.meta | 0 .../Arrays/ArraysSingleSubmeshGenerator.cs | 185 +++++++ .../ArraysSingleSubmeshGenerator.cs.meta | 0 .../Arrays/ArraysSubmeshSetMeshGenerator.cs | 394 ++++++++++++++ .../ArraysSubmeshSetMeshGenerator.cs.meta} | 4 +- .../Arrays/ArraysSubmeshedMeshGenerator.cs | 365 +++++++++++++ .../ArraysSubmeshedMeshGenerator.cs.meta | 0 .../Arrays/SubmeshTriangleBuffer.cs | 14 + .../Arrays/SubmeshTriangleBuffer.cs.meta} | 4 +- .../Arrays/ArraysSingleSubmeshGenerator.cs | 315 ----------- .../Arrays/ArraysSubmeshedMeshGenerator.cs | 494 ------------------ .../Submeshed/ISubmeshedMeshGenerator.cs | 70 ++- .../Submeshed/ISubmeshedMeshGenerator.cs.meta | 4 +- ...ator.meta => SkeletonRenderSeparator.meta} | 0 .../Editor.meta | 0 .../Editor/SkeletonRenderPartInspector.cs} | 9 +- .../SkeletonRenderPartInspector.cs.meta | 12 + .../SkeletonRenderSeparatorInspector.cs | 57 ++ .../SkeletonRenderSeparatorInspector.cs.meta | 12 + .../SkeletonRenderPart.cs} | 22 +- .../SkeletonRenderPart.cs.meta | 12 + .../SkeletonRenderSeparator.cs | 103 ++++ .../SkeletonRenderSeparator.cs.meta} | 0 .../Editor/SpineRenderSeparatorInspector.cs | 36 -- .../SpineRenderSeparator.cs | 63 --- .../spine-unity/Modules/SubmeshRenderer.meta | 9 - .../Modules/SubmeshRenderer/Editor.meta | 9 - .../Assets/spine-unity/SkeletonRenderer.cs | 20 +- 32 files changed, 1404 insertions(+), 1092 deletions(-) rename spine-unity/Assets/spine-unity/Mesh Generation/{Submeshed => }/Arrays.meta (100%) create mode 100644 spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysBuffers.cs rename spine-unity/Assets/spine-unity/{Modules/SpineRenderSeparator/Editor/SpineRenderSeparatorInspector.cs.meta => Mesh Generation/Arrays/ArraysBuffers.cs.meta} (76%) rename spine-unity/Assets/spine-unity/Mesh Generation/{Simple => Arrays}/ArraysSimpleMeshGenerator.cs (56%) rename spine-unity/Assets/spine-unity/Mesh Generation/{Simple => Arrays}/ArraysSimpleMeshGenerator.cs.meta (100%) create mode 100644 spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSingleSubmeshGenerator.cs rename spine-unity/Assets/spine-unity/Mesh Generation/{Submeshed => }/Arrays/ArraysSingleSubmeshGenerator.cs.meta (100%) create mode 100644 spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs rename spine-unity/Assets/spine-unity/{Modules/SubmeshRenderer/SubmeshRenderer.cs.meta => Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs.meta} (76%) create mode 100644 spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs rename spine-unity/Assets/spine-unity/Mesh Generation/{Submeshed => }/Arrays/ArraysSubmeshedMeshGenerator.cs.meta (100%) create mode 100644 spine-unity/Assets/spine-unity/Mesh Generation/Arrays/SubmeshTriangleBuffer.cs rename spine-unity/Assets/spine-unity/{Modules/SubmeshRenderer/Editor/SubmeshRendererInspector.cs.meta => Mesh Generation/Arrays/SubmeshTriangleBuffer.cs.meta} (76%) delete mode 100644 spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/Arrays/ArraysSingleSubmeshGenerator.cs delete mode 100644 spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/Arrays/ArraysSubmeshedMeshGenerator.cs rename spine-unity/Assets/spine-unity/Modules/{SpineRenderSeparator.meta => SkeletonRenderSeparator.meta} (100%) rename spine-unity/Assets/spine-unity/Modules/{SpineRenderSeparator => SkeletonRenderSeparator}/Editor.meta (100%) rename spine-unity/Assets/spine-unity/Modules/{SubmeshRenderer/Editor/SubmeshRendererInspector.cs => SkeletonRenderSeparator/Editor/SkeletonRenderPartInspector.cs} (73%) create mode 100644 spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderPartInspector.cs.meta create mode 100644 spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderSeparatorInspector.cs create mode 100644 spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderSeparatorInspector.cs.meta rename spine-unity/Assets/spine-unity/Modules/{SubmeshRenderer/SubmeshRenderer.cs => SkeletonRenderSeparator/SkeletonRenderPart.cs} (59%) create mode 100644 spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderPart.cs.meta create mode 100644 spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderSeparator.cs rename spine-unity/Assets/spine-unity/Modules/{SpineRenderSeparator/SpineRenderSeparator.cs.meta => SkeletonRenderSeparator/SkeletonRenderSeparator.cs.meta} (100%) delete mode 100644 spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator/Editor/SpineRenderSeparatorInspector.cs delete mode 100644 spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator/SpineRenderSeparator.cs delete mode 100644 spine-unity/Assets/spine-unity/Modules/SubmeshRenderer.meta delete mode 100644 spine-unity/Assets/spine-unity/Modules/SubmeshRenderer/Editor.meta diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/Arrays.meta b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays.meta similarity index 100% rename from spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/Arrays.meta rename to spine-unity/Assets/spine-unity/Mesh Generation/Arrays.meta diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysBuffers.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysBuffers.cs new file mode 100644 index 000000000..883f7dbf6 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysBuffers.cs @@ -0,0 +1,149 @@ +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/Modules/SpineRenderSeparator/Editor/SpineRenderSeparatorInspector.cs.meta b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysBuffers.cs.meta similarity index 76% rename from spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator/Editor/SpineRenderSeparatorInspector.cs.meta rename to spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysBuffers.cs.meta index d8ac8aa91..c5548da2a 100644 --- a/spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator/Editor/SpineRenderSeparatorInspector.cs.meta +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysBuffers.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: d8742ee1d54c9954d95c9e6508806ac2 -timeCreated: 1457405832 +guid: 043e864df13214e4989d29c17a863b08 +timeCreated: 1458056200 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Simple/ArraysSimpleMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs similarity index 56% rename from spine-unity/Assets/spine-unity/Mesh Generation/Simple/ArraysSimpleMeshGenerator.cs rename to spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs index 7343f1dff..29df4e9da 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Simple/ArraysSimpleMeshGenerator.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs @@ -32,7 +32,7 @@ using UnityEngine; using System.Collections; -namespace Spine.Unity { +namespace Spine.Unity.MeshGeneration { public class ArraysSimpleMeshGenerator : ISimpleMeshGenerator { #region Settings protected float scale = 1f; @@ -42,6 +42,8 @@ namespace Spine.Unity { } public bool renderMeshes = true; + + public bool premultiplyVertexColors = true; #endregion #region Buffers @@ -112,14 +114,11 @@ namespace Spine.Unity { // Step 3 : Push vertices to arrays // - const float z = 0; + 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; - int vertexIndex = 0; - Color32 color; - float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b; Vector3 meshBoundsMin; Vector3 meshBoundsMax; @@ -134,116 +133,23 @@ namespace Spine.Unity { meshBoundsMin.z = -zFauxHalfThickness; meshBoundsMax.z = zFauxHalfThickness; - int i = 0; - do { - Slot slot = drawOrderItems[i]; - Attachment attachment = slot.attachment; - var regionAttachment = attachment as RegionAttachment; - if (regionAttachment != null) { - regionAttachment.ComputeWorldVertices(slot.bone, tempVertices); + 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; - float x1 = tempVertices[RegionAttachment.X1], y1 = tempVertices[RegionAttachment.Y1]; - float x2 = tempVertices[RegionAttachment.X2], y2 = tempVertices[RegionAttachment.Y2]; - float x3 = tempVertices[RegionAttachment.X3], y3 = tempVertices[RegionAttachment.Y3]; - float x4 = tempVertices[RegionAttachment.X4], y4 = tempVertices[RegionAttachment.Y4]; - vertices[vertexIndex].x = x1 * scale; vertices[vertexIndex].y = y1 * scale; vertices[vertexIndex].z = z; - vertices[vertexIndex + 1].x = x4 * scale; vertices[vertexIndex + 1].y = y4 * scale; vertices[vertexIndex + 1].z = z; - vertices[vertexIndex + 2].x = x2 * scale; vertices[vertexIndex + 2].y = y2 * scale; vertices[vertexIndex + 2].z = z; - vertices[vertexIndex + 3].x = x3 * scale; vertices[vertexIndex + 3].y = y3 * scale; vertices[vertexIndex + 3].z = z; + // Apply scale to vertices + for (int i = 0; i < totalVertexCount; i++) { + var v = vertices[i]; + v.x *= scale; + v.y *= scale; + vertices[i] = v; + } - 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; - colors[vertexIndex] = color; colors[vertexIndex + 1] = color; colors[vertexIndex + 2] = color; colors[vertexIndex + 3] = color; + meshBoundsMax.x *= scale; + meshBoundsMax.y *= scale; + meshBoundsMin.x *= scale; + meshBoundsMax.y *= scale; - 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 { - if (!renderMeshes) continue; - var meshAttachment = attachment as MeshAttachment; - if (meshAttachment != null) { - int meshVertexCount = meshAttachment.vertices.Length; - if (tempVertices.Length < meshVertexCount) - this.tempVertices = tempVertices = new float[meshVertexCount]; - meshAttachment.ComputeWorldVertices(slot, tempVertices); - - 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; - - float[] meshUVs = meshAttachment.uvs; - for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { - float x = tempVertices[ii], y = tempVertices[ii + 1]; - vertices[vertexIndex].x = x * scale; vertices[vertexIndex].y = y * scale; vertices[vertexIndex].z = z; - colors[vertexIndex] = color; - uvs[vertexIndex].x = meshUVs[ii]; uvs[vertexIndex].y = meshUVs[ii + 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; - } - } else { - var skinnedMeshAttachment = attachment as WeightedMeshAttachment; - if (skinnedMeshAttachment != null) { - int meshVertexCount = skinnedMeshAttachment.uvs.Length; - if (tempVertices.Length < meshVertexCount) - this.tempVertices = tempVertices = new float[meshVertexCount]; - skinnedMeshAttachment.ComputeWorldVertices(slot, tempVertices); - - color.a = (byte)(a * slot.a * skinnedMeshAttachment.a); - color.r = (byte)(r * slot.r * skinnedMeshAttachment.r * color.a); - color.g = (byte)(g * slot.g * skinnedMeshAttachment.g * color.a); - color.b = (byte)(b * slot.b * skinnedMeshAttachment.b * color.a); - if (slot.data.blendMode == BlendMode.additive) color.a = 0; - - float[] meshUVs = skinnedMeshAttachment.uvs; - for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { - float x = tempVertices[ii], y = tempVertices[ii + 1]; - vertices[vertexIndex].x = x * scale; vertices[vertexIndex].y = y * scale; vertices[vertexIndex].z = z; - colors[vertexIndex] = color; - uvs[vertexIndex].x = meshUVs[ii]; uvs[vertexIndex].y = meshUVs[ii + 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; - } - } - } - } - } while (++i < drawOrderCount); } diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Simple/ArraysSimpleMeshGenerator.cs.meta b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs.meta similarity index 100% rename from spine-unity/Assets/spine-unity/Mesh Generation/Simple/ArraysSimpleMeshGenerator.cs.meta rename to spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs.meta diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSingleSubmeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSingleSubmeshGenerator.cs new file mode 100644 index 000000000..2a6975e4b --- /dev/null +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSingleSubmeshGenerator.cs @@ -0,0 +1,185 @@ +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/Submeshed/Arrays/ArraysSingleSubmeshGenerator.cs.meta b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSingleSubmeshGenerator.cs.meta similarity index 100% rename from spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/Arrays/ArraysSingleSubmeshGenerator.cs.meta rename to spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSingleSubmeshGenerator.cs.meta diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs new file mode 100644 index 000000000..0c62237bd --- /dev/null +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs @@ -0,0 +1,394 @@ +using UnityEngine; +using System.Collections; +using Spine; + +namespace Spine.Unity.MeshGeneration { + public class ArraysSubmeshSetMeshGenerator : ISubmeshSetMeshGenerator { + public float zSpacing = 0f; + public bool premultiplyVertexColors = true; + + public MeshAndMaterials GenerateMesh (ExposedList instructions, int startSubmesh, int endSubmesh) { + 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; + } + + 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)); + } + } + + 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); + } 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 * (currentInstructionsItems[submeshCount - 1].endSlot); + } else { + meshBoundsMin.z = zSpacing * (currentInstructionsItems[submeshCount - 1].endSlot); + meshBoundsMax.z = 0f; + } + } + + bool structureDoesntMatch = newVertices || newSubmeshBuffers || smartMesh.StructureDoesntMatch(currentAttachments, currentInstructions); + + if (structureDoesntMatch) { + mesh.Clear(); + + if (submeshCount == sharedMaterials.Length) + currentInstructions.FillMaterialArray(this.sharedMaterials); + else + this.sharedMaterials = currentInstructions.GetNewMaterialArray(); + } + + 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; + + smartMesh.Set(this.meshVertices, this.meshUVs, this.meshColors32, currentAttachments, currentInstructions); + mesh.bounds = new Bounds(meshCenter, meshBoundsExtents); + + if (structureDoesntMatch) { + // push new triangles if doesn't match. + mesh.subMeshCount = submeshCount; + for (int i = 0; i < submeshCount; i++) + mesh.SetTriangles(submeshBuffers.Items[i].triangles, i); + } + + 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 { + public readonly Mesh mesh = SpineMesh.NewMesh(); + readonly ExposedList attachmentsUsed = new ExposedList(); + readonly ExposedList instructionsUsed = new ExposedList(); + + public void Set (Vector3[] verts, Vector2[] uvs, Color32[] colors, ExposedList attachments, ExposedList instructions) { + mesh.vertices = verts; + mesh.uv = uvs; + mesh.colors32 = colors; + + attachmentsUsed.Clear(false); + attachmentsUsed.GrowIfNeeded(attachments.Capacity); + attachmentsUsed.Count = attachments.Count; + attachments.CopyTo(attachmentsUsed.Items); + + instructionsUsed.Clear(false); + instructionsUsed.GrowIfNeeded(instructions.Capacity); + instructionsUsed.Count = instructions.Count; + instructions.CopyTo(instructionsUsed.Items); + } + + public bool StructureDoesntMatch (ExposedList attachments, ExposedList instructions) { + // Check count inequality. + if (attachments.Count != this.attachmentsUsed.Count) return true; + if (instructions.Count != this.instructionsUsed.Count) return true; + + // Check each attachment. + var attachmentsPassed = attachments.Items; + var myAttachments = this.attachmentsUsed.Items; + for (int i = 0, n = attachmentsUsed.Count; i < n; i++) + if (attachmentsPassed[i] != myAttachments[i]) return true; + + // Check each submesh for equal arrangement. + var instructionListItems = instructions.Items; + var myInstructions = this.instructionsUsed.Items; + for (int i = 0, n = this.instructionsUsed.Count; i < n; i++) { + var lhs = instructionListItems[i]; + var rhs = myInstructions[i]; + if ( + lhs.material.GetInstanceID() != rhs.material.GetInstanceID() || + lhs.startSlot != rhs.startSlot || + lhs.endSlot != rhs.endSlot || + lhs.triangleCount != rhs.triangleCount || + lhs.vertexCount != rhs.vertexCount || + lhs.firstVertexIndex != rhs.firstVertexIndex + ) return true; + } + + //Debug.Log("structure matched"); + return false; + } + } + #endregion + } + +} diff --git a/spine-unity/Assets/spine-unity/Modules/SubmeshRenderer/SubmeshRenderer.cs.meta b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs.meta similarity index 76% rename from spine-unity/Assets/spine-unity/Modules/SubmeshRenderer/SubmeshRenderer.cs.meta rename to spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs.meta index a53a783d6..88a01687a 100644 --- a/spine-unity/Assets/spine-unity/Modules/SubmeshRenderer/SubmeshRenderer.cs.meta +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 5273e5c60bd84a44db5a4e8f3252eef0 -timeCreated: 1457396525 +guid: 11ba077d7d984814db31d054192be532 +timeCreated: 1458047178 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs new file mode 100644 index 000000000..83a8c9e06 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs @@ -0,0 +1,365 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +using Spine; +using Spine.Unity; + +namespace Spine.Unity.MeshGeneration { + public class ArraysSubmeshedMeshGenerator : ISubmeshedMeshGenerator { + + readonly List separators = new List(); + public List Separators { get { return this.separators; } } + + public bool premultiplyVertexColors = true; + public float zSpacing = 0f; + + // public bool generateNormals; + // public bool generateTangents; + + public SubmeshedMeshInstruction GenerateInstruction (Skeleton skeleton) { + if (skeleton == null) throw new System.ArgumentNullException("skeleton"); + + // Count vertices and submesh triangles. + int runningVertexCount = 0; + + int submeshTriangleCount = 0; + int submeshFirstVertex = 0; + int submeshVertexCount = 0; + int submeshStartSlotIndex = 0; + Material lastMaterial = null; + + var drawOrder = skeleton.drawOrder; + var drawOrderItems = drawOrder.Items; + int drawOrderCount = drawOrder.Count; + int separatorCount = separators.Count; + + var instructionList = this.currentInstructions.submeshInstructions; + instructionList.Clear(false); + + currentInstructions.attachmentList.Clear(false); + + for (int i = 0; i < drawOrderCount; i++) { + var slot = drawOrderItems[i]; + var attachment = slot.attachment; + + object rendererObject; // An AtlasRegion in plain Spine-Unity. eventual source of Material object. + int attachmentVertexCount, attachmentTriangleCount; + + var regionAttachment = attachment as RegionAttachment; + if (regionAttachment != null) { + rendererObject = regionAttachment.RendererObject; + attachmentVertexCount = 4; + attachmentTriangleCount = 6; + } else { + var meshAttachment = attachment as MeshAttachment; + if (meshAttachment != null) { + rendererObject = meshAttachment.RendererObject; + attachmentVertexCount = meshAttachment.vertices.Length >> 1; + attachmentTriangleCount = meshAttachment.triangles.Length; + } else { + var skinnedMeshAttachment = attachment as WeightedMeshAttachment; + if (skinnedMeshAttachment != null) { + rendererObject = skinnedMeshAttachment.RendererObject; + attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1; + attachmentTriangleCount = skinnedMeshAttachment.triangles.Length; + } else + continue; + } + } + + 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) )) { + + instructionList.Add( + new SubmeshInstruction { + skeleton = skeleton, + material = lastMaterial, + triangleCount = submeshTriangleCount, + vertexCount = submeshVertexCount, + startSlot = submeshStartSlotIndex, + endSlot = i, + firstVertexIndex = submeshFirstVertex + } + ); + + // Prepare for next submesh + submeshTriangleCount = 0; + submeshVertexCount = 0; + submeshFirstVertex = runningVertexCount; + submeshStartSlotIndex = i; + } + lastMaterial = attachmentMaterial; + + submeshTriangleCount += attachmentTriangleCount; + submeshVertexCount += attachmentVertexCount; + runningVertexCount += attachmentVertexCount; + + currentInstructions.attachmentList.Add(attachment); + } + + instructionList.Add( + new SubmeshInstruction { + skeleton = skeleton, + material = lastMaterial, + triangleCount = submeshTriangleCount, + vertexCount = submeshVertexCount, + startSlot = submeshStartSlotIndex, + endSlot = drawOrderCount, + firstVertexIndex = submeshFirstVertex + } + ); + + currentInstructions.vertexCount = runningVertexCount; + return currentInstructions; + } + + 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. + 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; + } + } + + Vector3 meshBoundsMin; + Vector3 meshBoundsMax; + + int attachmentCount = meshInstructions.attachmentList.Count; + + // Initial values for manual Mesh Bounds calculation + if (meshInstructions.attachmentList.Count <= 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; + } + } + + 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. + 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 + 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 + 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 + } + } + + this.attachmentVertexBuffer = attVertBuffer; + Vector3 meshBoundsExtents = (meshBoundsMax - meshBoundsMin); + Vector3 meshCenter = meshBoundsMin + meshBoundsExtents * 0.5f; + + smartMesh.Set(this.meshVertices, this.meshUVs, this.meshColors32, meshInstructions); + mesh.bounds = new Bounds(meshCenter, meshBoundsExtents); + + 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. + mesh.subMeshCount = submeshCount; + for (int i = 0; i < submeshCount; i++) + mesh.SetTriangles(submeshBuffers.Items[i].triangles, i); + } + + + 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 { + public readonly Mesh mesh = SpineMesh.NewMesh(); + readonly ExposedList attachmentsUsed = new ExposedList(); + readonly ExposedList instructionsUsed = new ExposedList(); + + public void Set (Vector3[] verts, Vector2[] uvs, Color32[] colors, SubmeshedMeshInstruction instruction) { + mesh.vertices = verts; + mesh.uv = uvs; + mesh.colors32 = colors; + + attachmentsUsed.Clear(false); + attachmentsUsed.GrowIfNeeded(instruction.attachmentList.Capacity); + attachmentsUsed.Count = instruction.attachmentList.Count; + instruction.attachmentList.CopyTo(attachmentsUsed.Items); + + instructionsUsed.Clear(false); + instructionsUsed.GrowIfNeeded(instruction.submeshInstructions.Capacity); + instructionsUsed.Count = instruction.submeshInstructions.Count; + instruction.submeshInstructions.CopyTo(instructionsUsed.Items); + } + + public bool StructureDoesntMatch (SubmeshedMeshInstruction instructions) { + // Check count inequality. + if (instructions.attachmentList.Count != this.attachmentsUsed.Count) return true; + if (instructions.submeshInstructions.Count != this.instructionsUsed.Count) return true; + + // Check each attachment. + var attachmentsPassed = instructions.attachmentList.Items; + var myAttachments = this.attachmentsUsed.Items; + for (int i = 0, n = attachmentsUsed.Count; i < n; i++) + if (attachmentsPassed[i] != myAttachments[i]) return true; + + // Check each submesh for equal arrangement. + var instructionListItems = instructions.submeshInstructions.Items; + var myInstructions = this.instructionsUsed.Items; + for (int i = 0, n = this.instructionsUsed.Count; i < n; i++) { + var lhs = instructionListItems[i]; + var rhs = myInstructions[i]; + if ( + lhs.material.GetInstanceID() != rhs.material.GetInstanceID() || + lhs.startSlot != rhs.startSlot || + lhs.endSlot != rhs.endSlot || + lhs.triangleCount != rhs.triangleCount || + lhs.vertexCount != rhs.vertexCount || + lhs.firstVertexIndex != rhs.firstVertexIndex + ) return true; + } + + //Debug.Log("structure matched"); + return false; + } + } + #endregion + } + +} \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/Arrays/ArraysSubmeshedMeshGenerator.cs.meta b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs.meta similarity index 100% rename from spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/Arrays/ArraysSubmeshedMeshGenerator.cs.meta rename to spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs.meta diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/SubmeshTriangleBuffer.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/SubmeshTriangleBuffer.cs new file mode 100644 index 000000000..a193b0124 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/SubmeshTriangleBuffer.cs @@ -0,0 +1,14 @@ +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/Modules/SubmeshRenderer/Editor/SubmeshRendererInspector.cs.meta b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/SubmeshTriangleBuffer.cs.meta similarity index 76% rename from spine-unity/Assets/spine-unity/Modules/SubmeshRenderer/Editor/SubmeshRendererInspector.cs.meta rename to spine-unity/Assets/spine-unity/Mesh Generation/Arrays/SubmeshTriangleBuffer.cs.meta index 8a47d2273..6ec21ecf0 100644 --- a/spine-unity/Assets/spine-unity/Modules/SubmeshRenderer/Editor/SubmeshRendererInspector.cs.meta +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/SubmeshTriangleBuffer.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 15418e02758268b488e9ab86f805330c -timeCreated: 1457407060 +guid: 4b4bb4dc3775d6548b9405f681601abb +timeCreated: 1458056219 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/Arrays/ArraysSingleSubmeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/Arrays/ArraysSingleSubmeshGenerator.cs deleted file mode 100644 index 2f6e74bbd..000000000 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/Arrays/ArraysSingleSubmeshGenerator.cs +++ /dev/null @@ -1,315 +0,0 @@ -using UnityEngine; -using System.Collections; - -namespace Spine.Unity { - 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; - Color32 color; - 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; - } - } - - int vertexIndex = 0; - var skeleton = instruction.skeleton; - var skeletonDrawOrderItems = skeleton.DrawOrder.Items; - float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b; - - // Push verts in this submesh - for (int slotIndex = instruction.startSlot, endSlot = instruction.endSlot; slotIndex < endSlot; slotIndex++) { - var slot = skeletonDrawOrderItems[slotIndex]; - var attachment = slot.attachment; - float z = slotIndex * zSpacing; - - var regionAttachment = attachment as RegionAttachment; - if (regionAttachment != null) { - attachmentList.Add(attachment); - 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; - - color.a = (byte)(a * slot.a * regionAttachment.a); - if (this.premultiplyVertexColors) { - 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); - } else { - color.r = (byte)(r * slot.r * regionAttachment.r); color.g = (byte)(g * slot.g * regionAttachment.g); color.b = (byte)(b * slot.b * regionAttachment.b); - } - if (slot.data.blendMode == BlendMode.additive) color.a = 0; - 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) { - attachmentList.Add(attachment); - int meshVertexCount = meshAttachment.vertices.Length; - if (attVertBuffer.Length < meshVertexCount) this.attachmentVertexBuffer = attVertBuffer = new float[meshVertexCount]; - meshAttachment.ComputeWorldVertices(slot, attVertBuffer); - - color.a = (byte)(a * slot.a * meshAttachment.a); - if (this.premultiplyVertexColors) { - 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); - } else { - color.r = (byte)(r * slot.r * meshAttachment.r); - color.g = (byte)(g * slot.g * meshAttachment.g); - color.b = (byte)(b * slot.b * meshAttachment.b); - } - if (slot.data.blendMode == BlendMode.additive) color.a = 0; - - 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) { - attachmentList.Add(attachment); - int meshVertexCount = weightedMeshAttachment.uvs.Length; - if (attVertBuffer.Length < meshVertexCount) this.attachmentVertexBuffer = attVertBuffer = new float[meshVertexCount]; - weightedMeshAttachment.ComputeWorldVertices(slot, attVertBuffer); - - color.a = (byte)(a * slot.a * weightedMeshAttachment.a); - if (this.premultiplyVertexColors) { - 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); - } else { - color.r = (byte)(r * slot.r * weightedMeshAttachment.r); - color.g = (byte)(g * slot.g * weightedMeshAttachment.g); - color.b = (byte)(b * slot.b * weightedMeshAttachment.b); - } - if (slot.data.blendMode == BlendMode.additive) color.a = 0; - - 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++; - } - } - } - } - } - - 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 - - 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/Submeshed/Arrays/ArraysSubmeshedMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/Arrays/ArraysSubmeshedMeshGenerator.cs deleted file mode 100644 index 46e19b78b..000000000 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/Arrays/ArraysSubmeshedMeshGenerator.cs +++ /dev/null @@ -1,494 +0,0 @@ -using UnityEngine; -using System.Collections; -using System.Collections.Generic; - -using Spine; -using Spine.Unity; - -public class ArraysSubmeshedMeshGenerator : Spine.Unity.ISubmeshedMeshGenerator { - - readonly List separators = new List(); - public List Separators { get { return this.separators; } } - - public bool generateNormals; - public bool generateTangents; - - public float zSpacing = 0f; - - public SubmeshedMeshInstruction GenerateInstruction (Skeleton skeleton) { - if (skeleton == null) throw new System.ArgumentNullException("skeleton"); - - // Count vertices and submesh triangles. - int runningVertexCount = 0; - - int submeshTriangleCount = 0; - int submeshFirstVertex = 0; - int submeshVertexCount = 0; - int submeshStartSlotIndex = 0; - Material lastMaterial = null; - - var drawOrder = skeleton.drawOrder; - var drawOrderItems = drawOrder.Items; - int drawOrderCount = drawOrder.Count; - int separatorCount = separators.Count; - - var instructionList = this.currentInstructions.submeshInstructions; - instructionList.Clear(false); - - currentInstructions.attachmentList.Clear(false); - - for (int i = 0; i < drawOrderCount; i++) { - var slot = drawOrderItems[i]; - var attachment = slot.attachment; - - object rendererObject; // An AtlasRegion in plain Spine-Unity. eventual source of Material object. - int attachmentVertexCount, attachmentTriangleCount; - - var regionAttachment = attachment as RegionAttachment; - if (regionAttachment != null) { - rendererObject = regionAttachment.RendererObject; - attachmentVertexCount = 4; - attachmentTriangleCount = 6; - } else { - var meshAttachment = attachment as MeshAttachment; - if (meshAttachment != null) { - rendererObject = meshAttachment.RendererObject; - attachmentVertexCount = meshAttachment.vertices.Length >> 1; - attachmentTriangleCount = meshAttachment.triangles.Length; - } else { - var skinnedMeshAttachment = attachment as WeightedMeshAttachment; - if (skinnedMeshAttachment != null) { - rendererObject = skinnedMeshAttachment.RendererObject; - attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1; - attachmentTriangleCount = skinnedMeshAttachment.triangles.Length; - } else - continue; - } - } - - 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) )) { - - instructionList.Add( - new SubmeshInstruction { - skeleton = skeleton, - material = lastMaterial, - triangleCount = submeshTriangleCount, - vertexCount = submeshVertexCount, - startSlot = submeshStartSlotIndex, - endSlot = i, - firstVertexIndex = submeshFirstVertex - } - ); - - // Prepare for next submesh - submeshTriangleCount = 0; - submeshVertexCount = 0; - submeshFirstVertex = runningVertexCount; - submeshStartSlotIndex = i; - } - lastMaterial = attachmentMaterial; - - submeshTriangleCount += attachmentTriangleCount; - submeshVertexCount += attachmentVertexCount; - runningVertexCount += attachmentVertexCount; - - currentInstructions.attachmentList.Add(attachment); - } - - instructionList.Add( - new SubmeshInstruction { - skeleton = skeleton, - material = lastMaterial, - triangleCount = submeshTriangleCount, - vertexCount = submeshVertexCount, - startSlot = submeshStartSlotIndex, - endSlot = drawOrderCount, - firstVertexIndex = submeshFirstVertex - } - ); - - currentInstructions.vertexCount = runningVertexCount; - return currentInstructions; - } - - public SubmeshedMesh GenerateMesh (SubmeshedMeshInstruction meshInstructions) { - var smartMesh = doubleBufferedSmartMesh.GetNextMesh(); - 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; - Color32 color; - - // Ensure correct buffer sizes. - 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; - } - } - - Vector3 meshBoundsMin; - Vector3 meshBoundsMax; - - int attachmentCount = meshInstructions.attachmentList.Count; - - // Initial values for manual Mesh Bounds calculation - if (meshInstructions.attachmentList.Count <= 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; - } - } - - 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. - for (int submeshIndex = 0; submeshIndex < submeshCount; submeshIndex++) { - var currentSubmeshInstruction = instructionList.Items[submeshIndex]; - var skeleton = currentSubmeshInstruction.skeleton; - var skeletonDrawOrderItems = skeleton.DrawOrder.Items; - float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b; - - 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; - - 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; - 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) this.attachmentVertexBuffer = attVertBuffer = new float[meshVertexCount]; - meshAttachment.ComputeWorldVertices(slot, attVertBuffer); - - 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; - - 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) this.attachmentVertexBuffer = attVertBuffer = new float[meshVertexCount]; - weightedMeshAttachment.ComputeWorldVertices(slot, attVertBuffer); - - 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; - - 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++; - } - } - } - } - } - - // 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 - } - } - - - Vector3 meshBoundsExtents = (meshBoundsMax - meshBoundsMin); - Vector3 meshCenter = meshBoundsMin + meshBoundsExtents * 0.5f; - - smartMesh.Set(this.meshVertices, this.meshUVs, this.meshColors32, meshInstructions); - mesh.bounds = new Bounds(meshCenter, meshBoundsExtents); - - 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. - mesh.subMeshCount = submeshCount; - for (int i = 0; i < submeshCount; i++) - mesh.SetTriangles(submeshBuffers.Items[i].triangles, i); - } - - - return new SubmeshedMesh(smartMesh.mesh, sharedMaterials); - } - - #region Internals - readonly DoubleBufferedSmartMesh doubleBufferedSmartMesh = new DoubleBufferedSmartMesh(); - 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 - class SubmeshTriangleBuffer { - public int[] triangles; - public int triangleCount; - - public SubmeshTriangleBuffer (int triangleCount) { - triangles = new int[triangleCount]; - this.triangleCount = triangleCount; - } - } - - class DoubleBufferedSmartMesh { - readonly SmartMesh mesh1 = new SmartMesh(); - readonly SmartMesh mesh2 = new SmartMesh(); - bool usingMesh1; - - public SmartMesh GetNextMesh () { - usingMesh1 = !usingMesh1; - return usingMesh1 ? mesh1 : mesh2; - } - } - - // A SmartMesh is a Mesh (with submeshes) that knows what attachments and instructions were used to generate it. - class SmartMesh { - public readonly Mesh mesh = SpineMesh.NewMesh(); - readonly ExposedList attachmentsUsed = new ExposedList(); - readonly ExposedList instructionsUsed = new ExposedList(); - - public void Set (Vector3[] verts, Vector2[] uvs, Color32[] colors, SubmeshedMeshInstruction instruction) { - mesh.vertices = verts; - mesh.uv = uvs; - mesh.colors32 = colors; - - attachmentsUsed.Clear(false); - attachmentsUsed.GrowIfNeeded(instruction.attachmentList.Capacity); - attachmentsUsed.Count = instruction.attachmentList.Count; - instruction.attachmentList.CopyTo(attachmentsUsed.Items); - - instructionsUsed.Clear(false); - instructionsUsed.GrowIfNeeded(instruction.submeshInstructions.Capacity); - instructionsUsed.Count = instruction.submeshInstructions.Count; - instruction.submeshInstructions.CopyTo(instructionsUsed.Items); - } - - public bool StructureDoesntMatch (SubmeshedMeshInstruction instructions) { - // Check count inequality. - if (instructions.attachmentList.Count != this.attachmentsUsed.Count) return true; - if (instructions.submeshInstructions.Count != this.instructionsUsed.Count) return true; - - // Check each attachment. - var attachmentsPassed = instructions.attachmentList.Items; - var myAttachments = this.attachmentsUsed.Items; - for (int i = 0, n = attachmentsUsed.Count; i < n; i++) - if (attachmentsPassed[i] != myAttachments[i]) return true; - - // Check each submesh for equal arrangement. - var instructionListItems = instructions.submeshInstructions.Items; - var myInstructions = this.instructionsUsed.Items; - for (int i = 0, n = this.instructionsUsed.Count; i < n; i++) { - var lhs = instructionListItems[i]; - var rhs = myInstructions[i]; - if ( - lhs.material.GetInstanceID() != rhs.material.GetInstanceID() || - lhs.startSlot != rhs.startSlot || - lhs.endSlot != rhs.endSlot || - lhs.triangleCount != rhs.triangleCount || - lhs.vertexCount != rhs.vertexCount || - lhs.firstVertexIndex != rhs.firstVertexIndex - ) return true; - } - - //Debug.Log("structure matched"); - return false; - } - } - #endregion -} diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/ISubmeshedMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/ISubmeshedMeshGenerator.cs index 87c0f869e..72d088fe1 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/ISubmeshedMeshGenerator.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/ISubmeshedMeshGenerator.cs @@ -1,33 +1,35 @@ using UnityEngine; using System.Collections.Generic; -namespace Spine.Unity { +namespace Spine.Unity.MeshGeneration { + // ISubmeshedMeshGenerator: + // How to use: + // Step 1: Have a SubmeshedMeshGenerator instance, and a Spine.Skeleton + // Step 2: Call GenerateInstruction. Pass it your Skeleton. Keep the return value (a SubmeshedMeshInstruction, you can use it in other classes too). + // Step 3: Pass the SubmeshedMeshInstruction into GenerateMesh. You'll get a Mesh and Materials. + // Step 4: Put the Mesh in MeshFilter. Put the Materials in MeshRenderer.sharedMaterials. public interface ISubmeshedMeshGenerator { - /// Generates instructions for how to generate the submeshed mesh based on the given state of the - /// skeleton. The returned instructions can be used to generate a whole submeshed mesh or individual submeshes. SubmeshedMeshInstruction GenerateInstruction (Skeleton skeleton); - - /// Returns a SubmeshedMesh (a mesh and a material array coupled in a struct). - /// Call GenerateInstructions to get the SubmeshedMeshInstructions to pass into this. - SubmeshedMesh GenerateMesh (SubmeshedMeshInstruction wholeMeshInstruction); - - /// A list of slots that mark the end of a submesh. The slot after it will be the start of a new submesh. + MeshAndMaterials GenerateMesh (SubmeshedMeshInstruction wholeMeshInstruction); List Separators { get; } } - public interface ISingleSubmeshGenerator { - Mesh GenerateMesh (SubmeshInstruction instruction); + // ISubmeshSetMeshGenerator + // How to use: + // Step 1: Get a list of SubmeshInstruction. You can get this from SkeletonRenderer or an ISubmeshedMeshGenerator's returned SubmeshedMeshInstruction. + // Step 2: Call AddInstruction one by one, or AddInstructions once. + // Step 3: Call GenerateMesh. You'll get a Mesh and Materials. + // Step 4: Put the Mesh in MeshFilter. Put the Materials in MeshRenderer.sharedMaterials. + public interface ISubmeshSetMeshGenerator { + MeshAndMaterials GenerateMesh (ExposedList instructions, int startSubmesh, int endSubmesh); } - /// A Submeshed mesh is a return type so the mesh with - /// multiple submeshes can be coupled with a material array to render its submeshes. - public struct SubmeshedMesh { - public readonly Mesh mesh; - public readonly Material[] materials; - public SubmeshedMesh (Mesh mesh, Material[] materials) { - this.mesh = mesh; - this.materials = materials; - } + // 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. @@ -65,5 +67,33 @@ namespace Spine.Unity { // Vertex index offset. Used by submesh generation if part of a bigger mesh. public int firstVertexIndex; + public bool separatedBySlot; + + /// The number of slots in this SubmeshInstruction's range. Not necessarily the number of attachments. + public int SlotCount { get { return endSlot - startSlot; } } + } + + 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; + } + + public static Material[] GetNewMaterialArray (this ExposedList instructions) { + var materials = new Material[instructions.Count]; + instructions.FillMaterialArray(materials); + return materials; + } + } + + public struct MeshAndMaterials { + public readonly Mesh mesh; + public readonly Material[] materials; + + public MeshAndMaterials (Mesh mesh, Material[] materials) { + 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/Submeshed/ISubmeshedMeshGenerator.cs.meta index b7a7f946d..85782f9f9 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/ISubmeshedMeshGenerator.cs.meta +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Submeshed/ISubmeshedMeshGenerator.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: c518552ea622e98418ce673c5febc468 -timeCreated: 1455406760 +guid: 7492a8ff24ea1884f92307ab1121e451 +timeCreated: 1458046464 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator.meta b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator.meta similarity index 100% rename from spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator.meta rename to spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator.meta diff --git a/spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator/Editor.meta b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor.meta similarity index 100% rename from spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator/Editor.meta rename to spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor.meta diff --git a/spine-unity/Assets/spine-unity/Modules/SubmeshRenderer/Editor/SubmeshRendererInspector.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderPartInspector.cs similarity index 73% rename from spine-unity/Assets/spine-unity/Modules/SubmeshRenderer/Editor/SubmeshRendererInspector.cs rename to spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderPartInspector.cs index 3fbceb67f..c2a192835 100644 --- a/spine-unity/Assets/spine-unity/Modules/SubmeshRenderer/Editor/SubmeshRendererInspector.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderPartInspector.cs @@ -3,14 +3,12 @@ using System.Collections; using UnityEditor; using Spine.Unity; -[CustomEditor(typeof(SubmeshRenderer))] -public class SubmeshRendererInspector : Editor { - +[CustomEditor(typeof(SkeletonRenderPart))] +public class SkeletonRenderPartInspector : Editor { SpineInspectorUtility.SerializedSortingProperties sortingProperties; - SubmeshRenderer component; void OnEnable () { - component = target as SubmeshRenderer; + var component = target as Component; sortingProperties = new SpineInspectorUtility.SerializedSortingProperties(component.GetComponent()); } @@ -18,5 +16,4 @@ public class SubmeshRendererInspector : Editor { DrawDefaultInspector(); SpineInspectorUtility.SortingPropertyFields(sortingProperties, true); } - } diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderPartInspector.cs.meta b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderPartInspector.cs.meta new file mode 100644 index 000000000..a97d66211 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderPartInspector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 30e43037bf4433645ad70266f34c1c8b +timeCreated: 1458051036 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderSeparatorInspector.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderSeparatorInspector.cs new file mode 100644 index 000000000..dfdcfcd86 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderSeparatorInspector.cs @@ -0,0 +1,57 @@ +using UnityEngine; +using System.Collections; +using UnityEditor; +using Spine.Unity; + +[CustomEditor(typeof(SkeletonRenderSeparator))] +public class SkeletonRenderSeparatorInspector : Editor { + + SkeletonRenderSeparator component; + + void OnEnable () { + component = target as SkeletonRenderSeparator; + } + + public override void OnInspectorGUI () { + base.OnInspectorGUI(); + + if (GUILayout.Button("Add Renderer")) { + const int SortingOrderIncrement = 5; + int index = component.renderers.Count; + var smr = SkeletonRenderPart.NewSubmeshRendererGameObject(component.transform, index.ToString()); + component.renderers.Add(smr); + + // increment renderer sorting order. + if (index != 0) { + var prev = component.renderers[index - 1]; + if (prev != null) { + var prevMeshRenderer = prev.GetComponent(); + var currentMeshRenderer = smr.GetComponent(); + if (prevMeshRenderer != null && currentMeshRenderer != null) { + int prevSortingLayer = prevMeshRenderer.sortingLayerID; + int prevSortingOrder = prevMeshRenderer.sortingOrder; + + currentMeshRenderer.sortingLayerID = prevSortingLayer; + currentMeshRenderer.sortingOrder = prevSortingOrder + SortingOrderIncrement; + } + } + } + } + + if (GUILayout.Button("Destroy Renderers")) { + if (EditorUtility.DisplayDialog("Destroy Submesh Renderers", "Do you really want to destroy all the SubmeshRenderer GameObjects in the list?", "Destroy", "Cancel")) { + + for (int i = 0; i < component.renderers.Count; i++) { + Debug.LogFormat("Destroying {0}", component.renderers[i].gameObject.name); + DestroyImmediate(component.renderers[i].gameObject); + } + + component.renderers.Clear(); + } + } + + } + + + +} diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderSeparatorInspector.cs.meta b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderSeparatorInspector.cs.meta new file mode 100644 index 000000000..7e8e65898 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderSeparatorInspector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d2a5062cfe5dd4344831cda4723128af +timeCreated: 1458067064 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/spine-unity/Modules/SubmeshRenderer/SubmeshRenderer.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderPart.cs similarity index 59% rename from spine-unity/Assets/spine-unity/Modules/SubmeshRenderer/SubmeshRenderer.cs rename to spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderPart.cs index 5a6eefe5c..c7063a872 100644 --- a/spine-unity/Assets/spine-unity/Modules/SubmeshRenderer/SubmeshRenderer.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderPart.cs @@ -1,13 +1,12 @@ using UnityEngine; using System.Collections; - -using UnityEngine.Assertions; +using Spine.Unity.MeshGeneration; namespace Spine.Unity { [RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))] - public class SubmeshRenderer : MonoBehaviour { - ISingleSubmeshGenerator meshGenerator; - public ISingleSubmeshGenerator MeshGenerator { + public class SkeletonRenderPart : MonoBehaviour { + ISubmeshSetMeshGenerator meshGenerator; + public ISubmeshSetMeshGenerator MeshGenerator { get { LazyIntialize(); return meshGenerator; @@ -32,7 +31,7 @@ namespace Spine.Unity { void LazyIntialize () { if (meshGenerator != null) return; - meshGenerator = new ArraysSingleSubmeshGenerator(); // swap this out with your custom ISingleSubmeshGenerator code. + meshGenerator = new ArraysSubmeshSetMeshGenerator(); meshFilter = GetComponent(); meshRenderer = GetComponent(); } @@ -41,10 +40,11 @@ namespace Spine.Unity { meshFilter.sharedMesh = null; } - public void RenderSubmesh (SubmeshInstruction instruction) { + public void RenderSubmesh (ExposedList instructions, int startSubmesh, int endSubmesh) { LazyIntialize(); - meshRenderer.sharedMaterial = instruction.material; - meshFilter.sharedMesh = meshGenerator.GenerateMesh(instruction); + MeshAndMaterials m = meshGenerator.GenerateMesh(instructions, startSubmesh, endSubmesh); + meshFilter.sharedMesh = m.mesh; + meshRenderer.sharedMaterials = m.materials; } public void SetPropertyBlock (MaterialPropertyBlock block) { @@ -52,10 +52,10 @@ namespace Spine.Unity { meshRenderer.SetPropertyBlock(block); } - public static SubmeshRenderer NewSubmeshRendererGameObject (Transform parent, string name) { + public static SkeletonRenderPart NewSubmeshRendererGameObject (Transform parent, string name) { var go = new GameObject(name, typeof(MeshFilter), typeof(MeshRenderer)); go.transform.SetParent(parent, false); - var returnComponent = go.AddComponent(); + var returnComponent = go.AddComponent(); return returnComponent; } diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderPart.cs.meta b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderPart.cs.meta new file mode 100644 index 000000000..9359388b9 --- /dev/null +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderPart.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1c0b968d1e7333b499e347acb644f1c1 +timeCreated: 1458045480 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderSeparator.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderSeparator.cs new file mode 100644 index 000000000..790e8ebcf --- /dev/null +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderSeparator.cs @@ -0,0 +1,103 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using Spine.Unity; + +namespace Spine.Unity { + [ExecuteInEditMode] + public class SkeletonRenderSeparator : MonoBehaviour { + [SerializeField] + protected SkeletonRenderer skeletonRenderer; + public SkeletonRenderer SkeletonRenderer { + get { return skeletonRenderer; } + set { + if (skeletonRenderer != null) + skeletonRenderer.GenerateMeshOverride -= SeparateSkeletonRender; + skeletonRenderer = value; + } + } + + MeshRenderer masterMeshRenderer; + + [Header("Settings")] + public bool propagateMaterialPropertyBlock = false; + public bool controlMainMeshRenderer = true; + + [Space(10f)] + public List renderers = new List(); + + void Reset () { + if (skeletonRenderer == null) { + skeletonRenderer = GetComponent(); + } + } + + void OnEnable () { + if (skeletonRenderer == null) return; + if (block == null) block = new MaterialPropertyBlock(); + masterMeshRenderer = skeletonRenderer.GetComponent(); + + if (controlMainMeshRenderer) + masterMeshRenderer.enabled = false; + + skeletonRenderer.GenerateMeshOverride -= SeparateSkeletonRender; + skeletonRenderer.GenerateMeshOverride += SeparateSkeletonRender; + } + + void OnDisable () { + if (skeletonRenderer == null) return; + + if (controlMainMeshRenderer) + masterMeshRenderer.enabled = true; + + skeletonRenderer.GenerateMeshOverride -= SeparateSkeletonRender; + + foreach (var s in renderers) + s.ClearMesh(); + } + + MaterialPropertyBlock block; + + void SeparateSkeletonRender (SkeletonRenderer.SmartMesh.Instruction instruction) { + int rendererCount = renderers.Count; + if (rendererCount <= 0) return; + + int rendererIndex = 0; + + if (propagateMaterialPropertyBlock) + masterMeshRenderer.GetPropertyBlock(block); + + var submeshInstructions = instruction.submeshInstructions; + var submeshInstructionsItems = submeshInstructions.Items; + int lastSubmeshInstruction = submeshInstructions.Count - 1; + + var currentRenderer = renderers[rendererIndex]; + for (int i = 0, start = 0; i <= lastSubmeshInstruction; i++) { + if (submeshInstructionsItems[i].separatedBySlot) { + //Debug.Log(submeshInstructionsItems[i].endSlot); + currentRenderer.RenderSubmesh(instruction.submeshInstructions, start, i + 1); + start = i + 1; + + if (propagateMaterialPropertyBlock) + currentRenderer.SetPropertyBlock(block); + + rendererIndex++; + if (rendererIndex < rendererCount) { + currentRenderer = renderers[rendererIndex]; + } else { + break; + } + } else if (i == lastSubmeshInstruction) { + //Debug.Log(submeshInstructionsItems[i].endSlot); + currentRenderer.RenderSubmesh(instruction.submeshInstructions, start, i + 1); + + if (propagateMaterialPropertyBlock) + currentRenderer.SetPropertyBlock(block); + } + } + } + + + + } +} \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator/SpineRenderSeparator.cs.meta b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderSeparator.cs.meta similarity index 100% rename from spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator/SpineRenderSeparator.cs.meta rename to spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderSeparator.cs.meta diff --git a/spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator/Editor/SpineRenderSeparatorInspector.cs b/spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator/Editor/SpineRenderSeparatorInspector.cs deleted file mode 100644 index 926587636..000000000 --- a/spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator/Editor/SpineRenderSeparatorInspector.cs +++ /dev/null @@ -1,36 +0,0 @@ -using UnityEngine; -using System.Collections; -using UnityEditor; -using Spine.Unity; - -[CustomEditor(typeof(SpineRenderSeparator))] -public class SpineRenderSeparatorInspector : Editor { - - SpineRenderSeparator component; - - void OnEnable () { - component = target as SpineRenderSeparator; - } - - public override void OnInspectorGUI () { - base.OnInspectorGUI(); - if (GUILayout.Button("Destroy Submesh Renderers")) { - if (EditorUtility.DisplayDialog("Destroy Submesh Renderers", "Do you really want to destroy all the SubmeshRenderer GameObjects in the list?", "Destroy", "Cancel")) { - - for (int i = 0; i < component.submeshRenderers.Count; i++) { - Debug.LogFormat("Destroying {0}", component.submeshRenderers[i].gameObject.name); - DestroyImmediate(component.submeshRenderers[i].gameObject); - } - - component.submeshRenderers.Clear(); - } - } - - if (GUILayout.Button("Add SubmeshRenderer")) { - int index = component.submeshRenderers.Count; - var smr = SubmeshRenderer.NewSubmeshRendererGameObject(component.transform, index.ToString()); - component.submeshRenderers.Add(smr); - } - } - -} diff --git a/spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator/SpineRenderSeparator.cs b/spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator/SpineRenderSeparator.cs deleted file mode 100644 index b4dc1e4ca..000000000 --- a/spine-unity/Assets/spine-unity/Modules/SpineRenderSeparator/SpineRenderSeparator.cs +++ /dev/null @@ -1,63 +0,0 @@ -using UnityEngine; -using System.Collections; -using System.Collections.Generic; -using Spine.Unity; - -[ExecuteInEditMode] -public class SpineRenderSeparator : MonoBehaviour { - [SerializeField] - protected SkeletonRenderer skeletonRenderer; - public SkeletonRenderer SkeletonRenderer { - get { return skeletonRenderer; } - set { - if (skeletonRenderer != null) - skeletonRenderer.GenerateMeshOverride -= SeparatelyRenderSubmeshes; - skeletonRenderer = value; - } - } - - MeshRenderer masterMeshRenderer; - - public List submeshRenderers = new List(); - public bool propagateMaterialPropertyBlock = false; - - void OnEnable () { - if (skeletonRenderer == null) return; - if (block == null) block = new MaterialPropertyBlock(); - masterMeshRenderer = skeletonRenderer.GetComponent(); - masterMeshRenderer.enabled = false; - skeletonRenderer.GenerateMeshOverride -= SeparatelyRenderSubmeshes; - skeletonRenderer.GenerateMeshOverride += SeparatelyRenderSubmeshes; - } - - void OnDisable () { - if (skeletonRenderer == null) return; - - masterMeshRenderer.enabled = true; - skeletonRenderer.GenerateMeshOverride -= SeparatelyRenderSubmeshes; - - foreach (var s in submeshRenderers) - s.ClearMesh(); - } - - MaterialPropertyBlock block; - - void SeparatelyRenderSubmeshes (SkeletonRenderer.SmartMesh.Instruction instruction) { - var submeshInstructions = instruction.submeshInstructions; - var submeshInstructionsItems = submeshInstructions.Items; - for (int i = 0; i < instruction.submeshInstructions.Count; i++) { - if (i >= submeshRenderers.Count) return; - var submeshRenderer = submeshRenderers[i]; - submeshRenderer.RenderSubmesh(submeshInstructionsItems[i]); - - if (propagateMaterialPropertyBlock) { - masterMeshRenderer.GetPropertyBlock(block); - submeshRenderer.SetPropertyBlock(block); - } - - } - } - - - -} diff --git a/spine-unity/Assets/spine-unity/Modules/SubmeshRenderer.meta b/spine-unity/Assets/spine-unity/Modules/SubmeshRenderer.meta deleted file mode 100644 index e72d52624..000000000 --- a/spine-unity/Assets/spine-unity/Modules/SubmeshRenderer.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 792af191c395561459cc0cc03a517ae8 -folderAsset: yes -timeCreated: 1457401769 -licenseType: Free -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/spine-unity/Assets/spine-unity/Modules/SubmeshRenderer/Editor.meta b/spine-unity/Assets/spine-unity/Modules/SubmeshRenderer/Editor.meta deleted file mode 100644 index 589b9b4b2..000000000 --- a/spine-unity/Assets/spine-unity/Modules/SubmeshRenderer/Editor.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: 5eec1664658bb4344909619707652674 -folderAsset: yes -timeCreated: 1457405608 -licenseType: Free -DefaultImporter: - userData: - assetBundleName: - assetBundleVariant: diff --git a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs index 346c3e8f9..57480528f 100644 --- a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs +++ b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs @@ -33,6 +33,7 @@ using System.Collections.Generic; using UnityEngine; using Spine; using Spine.Unity; +using Spine.Unity.MeshGeneration; /// Renders a skeleton. [ExecuteInEditMode, RequireComponent(typeof(MeshFilter), typeof(MeshRenderer)), DisallowMultipleComponent] @@ -255,18 +256,18 @@ public class SkeletonRenderer : MonoBehaviour { #endif // Create a new SubmeshInstruction when material changes. (or when forced to separate by a submeshSeparator) - if ((vertexCount > 0 && lastMaterial.GetInstanceID() != material.GetInstanceID()) || - (submeshSeparatorSlotsCount > 0 && submeshSeparatorSlots.Contains(slot))) { - + bool separatedBySlot = (submeshSeparatorSlotsCount > 0 && submeshSeparatorSlots.Contains(slot)); + if ((vertexCount > 0 && lastMaterial.GetInstanceID() != material.GetInstanceID()) || separatedBySlot) { workingSubmeshInstructions.Add( - new Spine.Unity.SubmeshInstruction { + new Spine.Unity.MeshGeneration.SubmeshInstruction { skeleton = this.skeleton, material = lastMaterial, startSlot = submeshStartSlotIndex, endSlot = i, triangleCount = submeshTriangleCount, firstVertexIndex = submeshFirstVertex, - vertexCount = submeshVertexCount + vertexCount = submeshVertexCount, + separatedBySlot = separatedBySlot } ); @@ -283,14 +284,15 @@ public class SkeletonRenderer : MonoBehaviour { } workingSubmeshInstructions.Add( - new Spine.Unity.SubmeshInstruction { + new Spine.Unity.MeshGeneration.SubmeshInstruction { skeleton = this.skeleton, material = lastMaterial, startSlot = submeshStartSlotIndex, endSlot = drawOrderCount, triangleCount = submeshTriangleCount, firstVertexIndex = submeshFirstVertex, - vertexCount = submeshVertexCount + vertexCount = submeshVertexCount, + separatedBySlot = false } ); @@ -663,7 +665,7 @@ public class SkeletonRenderer : MonoBehaviour { return false; } - void SetSubmesh (int submeshIndex, Spine.Unity.SubmeshInstruction submeshInstructions, ExposedList flipStates, bool isLastSubmesh) { + void SetSubmesh (int submeshIndex, Spine.Unity.MeshGeneration.SubmeshInstruction submeshInstructions, ExposedList flipStates, bool isLastSubmesh) { SubmeshTriangleBuffer currentSubmesh = submeshes.Items[submeshIndex]; int[] triangles = currentSubmesh.triangles; @@ -799,7 +801,7 @@ public class SkeletonRenderer : MonoBehaviour { public int vertexCount = -1; public readonly ExposedList attachments = new ExposedList(); public readonly ExposedList attachmentFlips = new ExposedList(); - public readonly ExposedList submeshInstructions = new ExposedList(); + public readonly ExposedList submeshInstructions = new ExposedList(); public void Clear () { this.attachments.Clear(false);