123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585 |
- /******************************************************************************
- * Spine Runtimes Software License
- * Version 2.1
- *
- * Copyright (c) 2013, Esoteric Software
- * All rights reserved.
- *
- * You are granted a perpetual, non-exclusive, non-sublicensable and
- * non-transferable license to install, execute and perform the Spine Runtimes
- * Software (the "Software") solely for internal use. Without the written
- * permission of Esoteric Software (typically granted by licensing Spine), you
- * may not (a) modify, translate, adapt or otherwise create derivative works,
- * improvements of the Software or develop new applications using the Software
- * or (b) remove, delete, alter or obscure any trademarks or any copyright,
- * trademark, patent or other intellectual property or proprietary rights
- * notices on or in the Software, including any copy thereof. Redistributions
- * in binary or source form must include this license and terms.
- *
- * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
- using System;
- using System.IO;
- using System.Collections.Generic;
- using UnityEngine;
- using Spine;
- /// <summary>Renders a skeleton.</summary>
- [ExecuteInEditMode, RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
- public class SkeletonRenderer : MonoBehaviour
- {
- public delegate void SkeletonRendererDelegate(SkeletonRenderer skeletonRenderer);
- public SkeletonRendererDelegate OnReset;
- [System.NonSerialized]
- public bool valid;
- [System.NonSerialized]
- public Skeleton skeleton;
- public SkeletonDataAsset skeletonDataAsset;
- public String initialSkinName;
- public bool calculateNormals, calculateTangents;
- public float zSpacing;
- public bool renderMeshes = true, immutableTriangles;
- public bool frontFacing;
- public bool logErrors = false;
- [SpineSlot]
- public string[] submeshSeparators = new string[0];
- [HideInInspector]
- public List<Slot> submeshSeparatorSlots = new List<Slot>();
- private MeshRenderer meshRenderer;
- private MeshFilter meshFilter;
- private Mesh mesh1, mesh2;
- private bool useMesh1;
- private float[] tempVertices = new float[8];
- private int lastVertexCount;
- private Vector3[] vertices;
- private Color32[] colors;
- private Vector2[] uvs;
- private Material[] sharedMaterials = new Material[0];
- private readonly List<Material> submeshMaterials = new List<Material>();
- private readonly List<Submesh> submeshes = new List<Submesh>();
- private SkeletonUtilitySubmeshRenderer[] submeshRenderers;
- public virtual void Reset()
- {
- if (meshFilter != null)
- meshFilter.sharedMesh = null;
- meshRenderer = GetComponent<MeshRenderer>();
- if (meshRenderer != null) meshRenderer.sharedMaterial = null;
- if (mesh1 != null)
- {
- if (Application.isPlaying)
- Destroy(mesh1);
- else
- DestroyImmediate(mesh1);
- }
- if (mesh2 != null)
- {
- if (Application.isPlaying)
- Destroy(mesh2);
- else
- DestroyImmediate(mesh2);
- }
- mesh1 = null;
- mesh2 = null;
- lastVertexCount = 0;
- vertices = null;
- colors = null;
- uvs = null;
- sharedMaterials = new Material[0];
- submeshMaterials.Clear();
- submeshes.Clear();
- skeleton = null;
- valid = false;
- if (!skeletonDataAsset)
- {
- if (logErrors)
- Debug.LogError("Missing SkeletonData asset.", this);
- return;
- }
- SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(false);
- if (skeletonData == null)
- return;
- valid = true;
- meshFilter = GetComponent<MeshFilter>();
- mesh1 = newMesh();
- mesh2 = newMesh();
- vertices = new Vector3[0];
- skeleton = new Skeleton(skeletonData);
- if (initialSkinName != null && initialSkinName.Length > 0 && initialSkinName != "default")
- skeleton.SetSkin(initialSkinName);
- submeshSeparatorSlots.Clear();
- for (int i = 0; i < submeshSeparators.Length; i++)
- {
- submeshSeparatorSlots.Add(skeleton.FindSlot(submeshSeparators[i]));
- }
- CollectSubmeshRenderers();
- LateUpdate();
- if (OnReset != null)
- OnReset(this);
- }
- public void CollectSubmeshRenderers()
- {
- submeshRenderers = GetComponentsInChildren<SkeletonUtilitySubmeshRenderer>();
- }
- public virtual void Awake()
- {
- Reset();
- }
- public virtual void OnDestroy()
- {
- if (mesh1 != null)
- {
- if (Application.isPlaying)
- Destroy(mesh1);
- else
- DestroyImmediate(mesh1);
- }
- if (mesh2 != null)
- {
- if (Application.isPlaying)
- Destroy(mesh2);
- else
- DestroyImmediate(mesh2);
- }
- mesh1 = null;
- mesh2 = null;
- }
- private Mesh newMesh()
- {
- Mesh mesh = new Mesh();
- mesh.name = "Skeleton Mesh";
- mesh.hideFlags = HideFlags.HideAndDontSave;
- mesh.MarkDynamic();
- return mesh;
- }
- public virtual void LateUpdate()
- {
- if (!valid)
- return;
- // Count vertices and submesh triangles.
- int vertexCount = 0;
- int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0;
- Material lastMaterial = null;
- submeshMaterials.Clear();
- List<Slot> drawOrder = skeleton.DrawOrder;
- int drawOrderCount = drawOrder.Count;
- bool renderMeshes = this.renderMeshes;
- for (int i = 0; i < drawOrderCount; i++)
- {
- Slot slot = drawOrder[i];
- Attachment attachment = slot.attachment;
- object rendererObject;
- int attachmentVertexCount, attachmentTriangleCount;
- if (attachment is RegionAttachment)
- {
- rendererObject = ((RegionAttachment)attachment).RendererObject;
- attachmentVertexCount = 4;
- attachmentTriangleCount = 6;
- }
- else
- {
- if (!renderMeshes)
- continue;
- if (attachment is MeshAttachment)
- {
- MeshAttachment meshAttachment = (MeshAttachment)attachment;
- rendererObject = meshAttachment.RendererObject;
- attachmentVertexCount = meshAttachment.vertices.Length >> 1;
- attachmentTriangleCount = meshAttachment.triangles.Length;
- }
- else if (attachment is SkinnedMeshAttachment)
- {
- SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
- rendererObject = meshAttachment.RendererObject;
- attachmentVertexCount = meshAttachment.uvs.Length >> 1;
- attachmentTriangleCount = meshAttachment.triangles.Length;
- }
- else
- continue;
- }
- // Populate submesh when material changes.
- #if !SPINE_TK2D
- Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject;
- #else
- Material material = (rendererObject.GetType() == typeof(Material)) ? (Material)rendererObject : (Material)((AtlasRegion)rendererObject).page.rendererObject;
- #endif
- if ((lastMaterial != material && lastMaterial != null) || submeshSeparatorSlots.Contains(slot))
- {
- AddSubmesh(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false);
- submeshTriangleCount = 0;
- submeshFirstVertex = vertexCount;
- submeshStartSlotIndex = i;
- }
- lastMaterial = material;
- submeshTriangleCount += attachmentTriangleCount;
- vertexCount += attachmentVertexCount;
- }
- AddSubmesh(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true);
- // Set materials.
- if (submeshMaterials.Count == sharedMaterials.Length)
- submeshMaterials.CopyTo(sharedMaterials);
- else
- sharedMaterials = submeshMaterials.ToArray();
- meshRenderer.sharedMaterials = sharedMaterials;
- // Ensure mesh data is the right size.
- Vector3[] vertices = this.vertices;
- bool newTriangles = vertexCount > vertices.Length;
- if (newTriangles)
- {
- // Not enough vertices, increase size.
- this.vertices = vertices = new Vector3[vertexCount];
- this.colors = new Color32[vertexCount];
- this.uvs = new Vector2[vertexCount];
- mesh1.Clear();
- mesh2.Clear();
- }
- else
- {
- // Too many vertices, zero the extra.
- Vector3 zero = Vector3.zero;
- for (int i = vertexCount, n = lastVertexCount; i < n; i++)
- vertices[i] = zero;
- }
- lastVertexCount = vertexCount;
- // Setup mesh.
- float[] tempVertices = this.tempVertices;
- Vector2[] uvs = this.uvs;
- Color32[] colors = this.colors;
- int vertexIndex = 0;
- Color32 color = new Color32();
- float zSpacing = this.zSpacing;
- float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b;
- for (int i = 0; i < drawOrderCount; i++)
- {
- Slot slot = drawOrder[i];
- Attachment attachment = slot.attachment;
- if (attachment is RegionAttachment)
- {
- RegionAttachment regionAttachment = (RegionAttachment)attachment;
- regionAttachment.ComputeWorldVertices(slot.bone, tempVertices);
- float z = i * zSpacing;
- vertices[vertexIndex] = new Vector3(tempVertices[RegionAttachment.X1], tempVertices[RegionAttachment.Y1], z);
- vertices[vertexIndex + 1] = new Vector3(tempVertices[RegionAttachment.X4], tempVertices[RegionAttachment.Y4], z);
- vertices[vertexIndex + 2] = new Vector3(tempVertices[RegionAttachment.X2], tempVertices[RegionAttachment.Y2], z);
- vertices[vertexIndex + 3] = new Vector3(tempVertices[RegionAttachment.X3], tempVertices[RegionAttachment.Y3], 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.additiveBlending)
- color.a = 0;
- colors[vertexIndex] = color;
- colors[vertexIndex + 1] = color;
- colors[vertexIndex + 2] = color;
- colors[vertexIndex + 3] = color;
- float[] regionUVs = regionAttachment.uvs;
- uvs[vertexIndex] = new Vector2(regionUVs[RegionAttachment.X1], regionUVs[RegionAttachment.Y1]);
- uvs[vertexIndex + 1] = new Vector2(regionUVs[RegionAttachment.X4], regionUVs[RegionAttachment.Y4]);
- uvs[vertexIndex + 2] = new Vector2(regionUVs[RegionAttachment.X2], regionUVs[RegionAttachment.Y2]);
- uvs[vertexIndex + 3] = new Vector2(regionUVs[RegionAttachment.X3], regionUVs[RegionAttachment.Y3]);
- vertexIndex += 4;
- }
- else
- {
- if (!renderMeshes)
- continue;
- if (attachment is MeshAttachment)
- {
- MeshAttachment meshAttachment = (MeshAttachment)attachment;
- 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.additiveBlending)
- color.a = 0;
- float[] meshUVs = meshAttachment.uvs;
- float z = i * zSpacing;
- for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++)
- {
- vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z);
- colors[vertexIndex] = color;
- uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]);
- }
- }
- else if (attachment is SkinnedMeshAttachment)
- {
- SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
- int meshVertexCount = meshAttachment.uvs.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.additiveBlending)
- color.a = 0;
- float[] meshUVs = meshAttachment.uvs;
- float z = i * zSpacing;
- for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++)
- {
- vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z);
- colors[vertexIndex] = color;
- uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]);
- }
- }
- }
- }
- // Double buffer mesh.
- Mesh mesh = useMesh1 ? mesh1 : mesh2;
- meshFilter.sharedMesh = mesh;
- mesh.vertices = vertices;
- mesh.colors32 = colors;
- mesh.uv = uvs;
- int submeshCount = submeshMaterials.Count;
- mesh.subMeshCount = submeshCount;
- for (int i = 0; i < submeshCount; ++i)
- mesh.SetTriangles(submeshes[i].triangles, i);
- mesh.RecalculateBounds();
- if (newTriangles && calculateNormals)
- {
- Vector3[] normals = new Vector3[vertexCount];
- Vector3 normal = new Vector3(0, 0, -1);
- for (int i = 0; i < vertexCount; i++)
- normals[i] = normal;
- (useMesh1 ? mesh2 : mesh1).vertices = vertices; // Set other mesh vertices.
- mesh1.normals = normals;
- mesh2.normals = normals;
- if (calculateTangents)
- {
- Vector4[] tangents = new Vector4[vertexCount];
- Vector3 tangent = new Vector3(0, 0, 1);
- for (int i = 0; i < vertexCount; i++)
- tangents[i] = tangent;
- mesh1.tangents = tangents;
- mesh2.tangents = tangents;
- }
- }
- if (submeshRenderers.Length > 0)
- {
- foreach (var submeshRenderer in submeshRenderers)
- {
- if (submeshRenderer.submeshIndex < sharedMaterials.Length)
- submeshRenderer.SetMesh(meshRenderer, useMesh1 ? mesh1 : mesh2, sharedMaterials[submeshRenderer.submeshIndex]);
- else
- submeshRenderer.GetComponent<Renderer>().enabled = false;
- }
- }
- useMesh1 = !useMesh1;
- }
- /** Stores vertices and triangles for a single material. */
- private void AddSubmesh(Material material, int startSlot, int endSlot, int triangleCount, int firstVertex, bool lastSubmesh)
- {
- int submeshIndex = submeshMaterials.Count;
- submeshMaterials.Add(material);
- if (submeshes.Count <= submeshIndex)
- submeshes.Add(new Submesh());
- else if (immutableTriangles)
- return;
- Submesh submesh = submeshes[submeshIndex];
- int[] triangles = submesh.triangles;
- int trianglesCapacity = triangles.Length;
- if (lastSubmesh && trianglesCapacity > triangleCount)
- {
- // Last submesh may have more triangles than required, so zero triangles to the end.
- for (int i = triangleCount; i < trianglesCapacity; i++)
- triangles[i] = 0;
- submesh.triangleCount = triangleCount;
- }
- else if (trianglesCapacity != triangleCount)
- {
- // Reallocate triangles when not the exact size needed.
- submesh.triangles = triangles = new int[triangleCount];
- submesh.triangleCount = 0;
- }
- if (!renderMeshes && !frontFacing)
- {
- // Use stored triangles if possible.
- if (submesh.firstVertex != firstVertex || submesh.triangleCount < triangleCount)
- {
- submesh.triangleCount = triangleCount;
- submesh.firstVertex = firstVertex;
- int drawOrderIndex = 0;
- for (int i = 0; i < triangleCount; i += 6, firstVertex += 4, drawOrderIndex++)
- {
- triangles[i] = firstVertex;
- triangles[i + 1] = firstVertex + 2;
- triangles[i + 2] = firstVertex + 1;
- triangles[i + 3] = firstVertex + 2;
- triangles[i + 4] = firstVertex + 3;
- triangles[i + 5] = firstVertex + 1;
- }
- }
- return;
- }
- // Store triangles.
- List<Slot> drawOrder = skeleton.DrawOrder;
- for (int i = startSlot, triangleIndex = 0; i < endSlot; i++)
- {
- Slot slot = drawOrder[i];
- Attachment attachment = slot.attachment;
- Bone bone = slot.bone;
- bool flip = frontFacing && ((bone.WorldFlipX != bone.WorldFlipY) != (Mathf.Sign(bone.WorldScaleX) != Mathf.Sign(bone.WorldScaleY)));
- if (attachment is RegionAttachment)
- {
- if (!flip)
- {
- triangles[triangleIndex] = firstVertex;
- triangles[triangleIndex + 1] = firstVertex + 2;
- triangles[triangleIndex + 2] = firstVertex + 1;
- triangles[triangleIndex + 3] = firstVertex + 2;
- triangles[triangleIndex + 4] = firstVertex + 3;
- triangles[triangleIndex + 5] = firstVertex + 1;
- }
- else
- {
- triangles[triangleIndex] = firstVertex + 1;
- triangles[triangleIndex + 1] = firstVertex + 2;
- triangles[triangleIndex + 2] = firstVertex;
- triangles[triangleIndex + 3] = firstVertex + 1;
- triangles[triangleIndex + 4] = firstVertex + 3;
- triangles[triangleIndex + 5] = firstVertex + 2;
- }
- triangleIndex += 6;
- firstVertex += 4;
- continue;
- }
- int[] attachmentTriangles;
- int attachmentVertexCount;
- if (attachment is MeshAttachment)
- {
- MeshAttachment meshAttachment = (MeshAttachment)attachment;
- attachmentVertexCount = meshAttachment.vertices.Length >> 1;
- attachmentTriangles = meshAttachment.triangles;
- }
- else if (attachment is SkinnedMeshAttachment)
- {
- SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
- attachmentVertexCount = meshAttachment.uvs.Length >> 1;
- attachmentTriangles = meshAttachment.triangles;
- }
- else
- continue;
- if (flip)
- {
- for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii += 3, triangleIndex += 3)
- {
- triangles[triangleIndex + 2] = firstVertex + attachmentTriangles[ii];
- triangles[triangleIndex + 1] = firstVertex + attachmentTriangles[ii + 1];
- triangles[triangleIndex] = firstVertex + attachmentTriangles[ii + 2];
- }
- }
- else
- {
- for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++)
- {
- triangles[triangleIndex] = firstVertex + attachmentTriangles[ii];
- }
- }
- firstVertex += attachmentVertexCount;
- }
- }
- #if UNITY_EDITOR
- void OnDrawGizmos()
- {
- // Make selection easier by drawing a clear gizmo over the skeleton.
- if (vertices == null) return;
- Vector3 gizmosCenter = new Vector3();
- Vector3 gizmosSize = new Vector3();
- Vector3 min = new Vector3(float.MaxValue, float.MaxValue, 0f);
- Vector3 max = new Vector3(float.MinValue, float.MinValue, 0f);
- foreach (Vector3 vert in vertices)
- {
- min = Vector3.Min(min, vert);
- max = Vector3.Max(max, vert);
- }
- float width = max.x - min.x;
- float height = max.y - min.y;
- gizmosCenter = new Vector3(min.x + (width / 2f), min.y + (height / 2f), 0f);
- gizmosSize = new Vector3(width, height, 1f);
- Gizmos.color = Color.clear;
- Gizmos.matrix = transform.localToWorldMatrix;
- Gizmos.DrawCube(gizmosCenter, gizmosSize);
- }
- #endif
- }
- class Submesh
- {
- public int[] triangles = new int[0];
- public int triangleCount;
- public int firstVertex = -1;
- }
|