Created
June 17, 2016 04:30
-
-
Save pharan/a7deef685d6bb2e5e9a3c4593ee9d709 to your computer and use it in GitHub Desktop.
A version of Spine-Unity ArraysMeshGenerator.cs that can disallow degenerate triangles and extra verts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/****************************************************************************** | |
* Spine Runtimes Software License | |
* Version 2.3 | |
* | |
* Copyright (c) 2013-2015, Esoteric Software | |
* All rights reserved. | |
* | |
* You are granted a perpetual, non-exclusive, non-sublicensable and | |
* non-transferable license to use, install, execute and perform the Spine | |
* Runtimes Software (the "Software") and derivative works solely for personal | |
* or internal use. Without the written permission of Esoteric Software (see | |
* Section 2 of the Spine Software License Agreement), you may not (a) modify, | |
* translate, adapt or otherwise create derivative works, improvements of the | |
* Software or develop new applications using the Software or (b) remove, | |
* delete, alter or obscure any trademarks or any copyright, trademark, patent | |
* or other intellectual property or proprietary rights notices on or in the | |
* Software, including any copy thereof. Redistributions in binary or source | |
* form must include this license and terms. | |
* | |
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR | |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | |
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*****************************************************************************/ | |
#define SPINE_OPTIONAL_NORMALS | |
//#define ALLOW_DEGENERATE | |
using UnityEngine; | |
namespace Spine.Unity.MeshGeneration { | |
public class ArraysMeshGenerator { | |
#region Settings | |
protected bool premultiplyVertexColors = true; | |
public bool PremultiplyVertexColors { get { return this.premultiplyVertexColors; } set { this.premultiplyVertexColors = value; } } | |
#endregion | |
protected float[] attachmentVertexBuffer = new float[8]; | |
protected Vector3[] meshVertices; | |
protected Color32[] meshColors32; | |
protected Vector2[] meshUVs; | |
protected bool generateNormals = false; | |
public bool GenerateNormals { | |
get { return generateNormals; } | |
set { generateNormals = value; } | |
} | |
Vector3[] meshNormals; | |
public void TryAddNormalsTo (Mesh mesh, int targetVertexCount) { | |
#if SPINE_OPTIONAL_NORMALS | |
if (generateNormals) { | |
bool verticesWasResized = this.meshNormals == null || targetVertexCount > meshNormals.Length; | |
if (verticesWasResized) { | |
this.meshNormals = new Vector3[targetVertexCount]; | |
Vector3 normal = new Vector3(0, 0, -1); | |
Vector3[] normals = this.meshNormals; | |
for (int i = 0; i < targetVertexCount; i++) | |
normals[i] = normal; | |
} | |
mesh.normals = this.meshNormals; | |
} | |
#endif | |
} | |
public static bool EnsureSize (int targetVertexCount, ref Vector3[] vertices, ref Vector2[] uvs, ref Color32[] colors) { | |
Vector3[] verts = vertices; | |
#if ALLOW_DEGENERATE | |
bool verticesWasResized = verts == null || targetVertexCount > verts.Length; | |
#else | |
bool verticesWasResized = verts == null || targetVertexCount != verts.Length; | |
#endif | |
if (verticesWasResized) { | |
// Not enough space, increase size. | |
vertices = new Vector3[targetVertexCount]; | |
colors = new Color32[targetVertexCount]; | |
uvs = new Vector2[targetVertexCount]; | |
} else { | |
// Too many vertices, zero the extra. | |
Vector3 zero = Vector3.zero; | |
for (int i = targetVertexCount, n = verts.Length; i < n; i++) | |
verts[i] = zero; | |
} | |
return verticesWasResized; | |
} | |
public static bool EnsureTriangleBuffersSize (ExposedList<SubmeshTriangleBuffer> submeshBuffers, int targetSubmeshCount, SubmeshInstruction[] instructionItems) { | |
bool submeshBuffersWasResized = submeshBuffers.Count < targetSubmeshCount; | |
if (submeshBuffersWasResized) { | |
submeshBuffers.GrowIfNeeded(targetSubmeshCount - submeshBuffers.Count); | |
for (int i = submeshBuffers.Count; submeshBuffers.Count < targetSubmeshCount; i++) | |
submeshBuffers.Add(new SubmeshTriangleBuffer(instructionItems[i].triangleCount)); | |
} | |
return submeshBuffersWasResized; | |
} | |
/// <summary> | |
/// Fills vertex arrays. | |
/// </summary> | |
/// <param name="skeleton">Spine.Skeleton source of the drawOrder array</param> | |
/// <param name="startSlot">Slot index of the first slot.</param> | |
/// <param name="endSlot">The index bounding the slot list. endSlot - 1 is the last slot to be added.</param> | |
/// <param name="zSpacing">Spacing along the z-axis between attachments.</param> | |
/// <param name="pmaColors">If set to <c>true</c>, vertex colors will be premultiplied. This will also enable additive.</param> | |
/// <param name="verts">Vertex positions array. </param> | |
/// <param name="uvs">Vertex UV array.</param> | |
/// <param name="colors">Vertex color array (Color32).</param> | |
/// <param name="vertexIndex">A reference to the running vertex index. This is used when more than one submesh is to be added.</param> | |
/// <param name="tempVertBuffer">A temporary vertex position buffer for attachment position values.</param> | |
/// <param name="boundsMin">Reference to the running calculated minimum bounds.</param> | |
/// <param name="boundsMax">Reference to the running calculated maximum bounds.</param> | |
public static void FillVerts (Skeleton skeleton, int startSlot, int endSlot, float zSpacing, bool pmaColors, Vector3[] verts, Vector2[] uvs, Color32[] colors, ref int vertexIndex, ref float[] tempVertBuffer, ref Vector3 boundsMin, ref Vector3 boundsMax) { | |
Color32 color; | |
var skeletonDrawOrderItems = skeleton.DrawOrder.Items; | |
float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b; | |
int vi = vertexIndex; | |
var tempVerts = tempVertBuffer; | |
Vector3 bmin = boundsMin; | |
Vector3 bmax = boundsMax; | |
// drawOrder[endSlot] is excluded | |
for (int slotIndex = startSlot; slotIndex < endSlot; slotIndex++) { | |
var slot = skeletonDrawOrderItems[slotIndex]; | |
var attachment = slot.attachment; | |
float z = slotIndex * zSpacing; | |
var regionAttachment = attachment as RegionAttachment; | |
if (regionAttachment != null) { | |
regionAttachment.ComputeWorldVertices(slot.bone, tempVerts); | |
float x1 = tempVerts[RegionAttachment.X1], y1 = tempVerts[RegionAttachment.Y1]; | |
float x2 = tempVerts[RegionAttachment.X2], y2 = tempVerts[RegionAttachment.Y2]; | |
float x3 = tempVerts[RegionAttachment.X3], y3 = tempVerts[RegionAttachment.Y3]; | |
float x4 = tempVerts[RegionAttachment.X4], y4 = tempVerts[RegionAttachment.Y4]; | |
verts[vi].x = x1; verts[vi].y = y1; verts[vi].z = z; | |
verts[vi + 1].x = x4; verts[vi + 1].y = y4; verts[vi + 1].z = z; | |
verts[vi + 2].x = x2; verts[vi + 2].y = y2; verts[vi + 2].z = z; | |
verts[vi + 3].x = x3; verts[vi + 3].y = y3; verts[vi + 3].z = z; | |
if (pmaColors) { | |
color.a = (byte)(a * slot.a * regionAttachment.a); | |
color.r = (byte)(r * slot.r * regionAttachment.r * color.a); | |
color.g = (byte)(g * slot.g * regionAttachment.g * color.a); | |
color.b = (byte)(b * slot.b * regionAttachment.b * color.a); | |
if (slot.data.blendMode == BlendMode.additive) color.a = 0; | |
} else { | |
color.a = (byte)(a * slot.a * regionAttachment.a); | |
color.r = (byte)(r * slot.r * regionAttachment.r * 255); | |
color.g = (byte)(g * slot.g * regionAttachment.g * 255); | |
color.b = (byte)(b * slot.b * regionAttachment.b * 255); | |
} | |
colors[vi] = color; colors[vi + 1] = color; colors[vi + 2] = color; colors[vi + 3] = color; | |
float[] regionUVs = regionAttachment.uvs; | |
uvs[vi].x = regionUVs[RegionAttachment.X1]; uvs[vi].y = regionUVs[RegionAttachment.Y1]; | |
uvs[vi + 1].x = regionUVs[RegionAttachment.X4]; uvs[vi + 1].y = regionUVs[RegionAttachment.Y4]; | |
uvs[vi + 2].x = regionUVs[RegionAttachment.X2]; uvs[vi + 2].y = regionUVs[RegionAttachment.Y2]; | |
uvs[vi + 3].x = regionUVs[RegionAttachment.X3]; uvs[vi + 3].y = regionUVs[RegionAttachment.Y3]; | |
// Calculate min/max X | |
if (x1 < bmin.x) bmin.x = x1; | |
else if (x1 > bmax.x) bmax.x = x1; | |
if (x2 < bmin.x) bmin.x = x2; | |
else if (x2 > bmax.x) bmax.x = x2; | |
if (x3 < bmin.x) bmin.x = x3; | |
else if (x3 > bmax.x) bmax.x = x3; | |
if (x4 < bmin.x) bmin.x = x4; | |
else if (x4 > bmax.x) bmax.x = x4; | |
// Calculate min/max Y | |
if (y1 < bmin.y) bmin.y = y1; | |
else if (y1 > bmax.y) bmax.y = y1; | |
if (y2 < bmin.y) bmin.y = y2; | |
else if (y2 > bmax.y) bmax.y = y2; | |
if (y3 < bmin.y) bmin.y = y3; | |
else if (y3 > bmax.y) bmax.y = y3; | |
if (y4 < bmin.y) bmin.y = y4; | |
else if (y4 > bmax.y) bmax.y = y4; | |
vi += 4; | |
} else { | |
var meshAttachment = attachment as MeshAttachment; | |
if (meshAttachment != null) { | |
int meshVertexCount = meshAttachment.vertices.Length; | |
if (tempVerts.Length < meshVertexCount) tempVerts = new float[meshVertexCount]; | |
meshAttachment.ComputeWorldVertices(slot, tempVerts); | |
if (pmaColors) { | |
color.a = (byte)(a * slot.a * meshAttachment.a); | |
color.r = (byte)(r * slot.r * meshAttachment.r * color.a); | |
color.g = (byte)(g * slot.g * meshAttachment.g * color.a); | |
color.b = (byte)(b * slot.b * meshAttachment.b * color.a); | |
if (slot.data.blendMode == BlendMode.additive) color.a = 0; | |
} else { | |
color.a = (byte)(a * slot.a * meshAttachment.a); | |
color.r = (byte)(r * slot.r * meshAttachment.r * 255); | |
color.g = (byte)(g * slot.g * meshAttachment.g * 255); | |
color.b = (byte)(b * slot.b * meshAttachment.b * 255); | |
} | |
float[] attachmentUVs = meshAttachment.uvs; | |
for (int iii = 0; iii < meshVertexCount; iii += 2) { | |
float x = tempVerts[iii], y = tempVerts[iii + 1]; | |
verts[vi].x = x; verts[vi].y = y; verts[vi].z = z; | |
colors[vi] = color; uvs[vi].x = attachmentUVs[iii]; uvs[vi].y = attachmentUVs[iii + 1]; | |
if (x < bmin.x) bmin.x = x; | |
else if (x > bmax.x) bmax.x = x; | |
if (y < bmin.y) bmin.y = y; | |
else if (y > bmax.y) bmax.y = y; | |
vi++; | |
} | |
} else { | |
var weightedMeshAttachment = attachment as WeightedMeshAttachment; | |
if (weightedMeshAttachment != null) { | |
int meshVertexCount = weightedMeshAttachment.uvs.Length; | |
if (tempVerts.Length < meshVertexCount) tempVerts = new float[meshVertexCount]; | |
weightedMeshAttachment.ComputeWorldVertices(slot, tempVerts); | |
if (pmaColors) { | |
color.a = (byte)(a * slot.a * weightedMeshAttachment.a); | |
color.r = (byte)(r * slot.r * weightedMeshAttachment.r * color.a); | |
color.g = (byte)(g * slot.g * weightedMeshAttachment.g * color.a); | |
color.b = (byte)(b * slot.b * weightedMeshAttachment.b * color.a); | |
if (slot.data.blendMode == BlendMode.additive) color.a = 0; | |
} else { | |
color.a = (byte)(a * slot.a * weightedMeshAttachment.a); | |
color.r = (byte)(r * slot.r * weightedMeshAttachment.r * 255); | |
color.g = (byte)(g * slot.g * weightedMeshAttachment.g * 255); | |
color.b = (byte)(b * slot.b * weightedMeshAttachment.b * 255); | |
} | |
float[] attachmentUVs = weightedMeshAttachment.uvs; | |
for (int iii = 0; iii < meshVertexCount; iii += 2) { | |
float x = tempVerts[iii], y = tempVerts[iii + 1]; | |
verts[vi].x = x; verts[vi].y = y; verts[vi].z = z; | |
colors[vi] = color; | |
uvs[vi].x = attachmentUVs[iii]; uvs[vi].y = attachmentUVs[iii + 1]; | |
if (x < bmin.x) bmin.x = x; | |
else if (x > bmax.x) bmax.x = x; | |
if (y < bmin.y) bmin.y = y; | |
else if (y > bmax.y) bmax.y = y; | |
vi++; | |
} | |
} | |
} | |
} | |
} | |
// ref return values | |
vertexIndex = vi; | |
tempVertBuffer = tempVerts; | |
boundsMin = bmin; | |
boundsMax = bmax; | |
} | |
/// <summary> | |
/// Fills a submesh triangle buffer array. | |
/// </summary> | |
/// <param name="skeleton">Spine.Skeleton source of draw order slots.</param> | |
/// <param name="triangleCount">The target triangle count.</param> | |
/// <param name="firstVertex">First vertex of this submesh.</param> | |
/// <param name="startSlot">Start slot.</param> | |
/// <param name="endSlot">End slot.</param> | |
/// <param name="triangleBuffer">The triangle buffer array to be filled. This reference will be replaced in case the triangle values don't fit.</param> | |
/// <param name="isLastSubmesh">If set to <c>true</c>, the triangle buffer is allowed to be larger than needed.</param> | |
public static void FillTriangles (Skeleton skeleton, int triangleCount, int firstVertex, int startSlot, int endSlot, ref int[] triangleBuffer, bool isLastSubmesh) { | |
int trianglesCapacity = triangleBuffer.Length; | |
var tris = triangleBuffer; | |
#if ALLOW_DEGENERATE | |
// Ensure triangleBuffer size. | |
if (isLastSubmesh) { | |
if (trianglesCapacity > triangleCount) { | |
for (int i = triangleCount; i < trianglesCapacity; i++) | |
tris[i] = 0; | |
} else if (trianglesCapacity < triangleCount) { | |
triangleBuffer = tris = new int[triangleCount]; | |
} | |
} else if (trianglesCapacity != triangleCount) { | |
triangleBuffer = tris = new int[triangleCount]; | |
} | |
#else | |
if (trianglesCapacity != triangleCount) { | |
triangleBuffer = tris = new int[triangleCount]; | |
} | |
#endif | |
// Iterate through submesh slots and store the triangles. | |
int triangleIndex = 0; | |
int afv = firstVertex; // attachment first vertex | |
var skeletonDrawOrderItems = skeleton.drawOrder.Items; | |
for (int i = startSlot, n = endSlot; i < n; i++) { | |
var attachment = skeletonDrawOrderItems[i].attachment; | |
if (attachment is RegionAttachment) { | |
tris[triangleIndex] = afv; tris[triangleIndex + 1] = afv + 2; tris[triangleIndex + 2] = afv + 1; | |
tris[triangleIndex + 3] = afv + 2; tris[triangleIndex + 4] = afv + 3; tris[triangleIndex + 5] = afv + 1; | |
triangleIndex += 6; | |
afv += 4; | |
} else { | |
int[] attachmentTriangles; | |
int attachmentVertexCount; | |
var meshAttachment = attachment as MeshAttachment; | |
if (meshAttachment != null) { | |
attachmentVertexCount = meshAttachment.vertices.Length >> 1; // length/2 | |
attachmentTriangles = meshAttachment.triangles; | |
} else { | |
var weightedMeshAttachment = attachment as WeightedMeshAttachment; | |
if (weightedMeshAttachment != null) { | |
attachmentVertexCount = weightedMeshAttachment.uvs.Length >> 1; // length/2 | |
attachmentTriangles = weightedMeshAttachment.triangles; | |
} else | |
continue; | |
} | |
for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++) | |
tris[triangleIndex] = afv + attachmentTriangles[ii]; | |
afv += attachmentVertexCount; | |
} | |
} // Done adding current submesh triangles | |
} | |
public static Bounds ToBounds (Vector3 boundsMin, Vector3 boundsMax) { | |
Vector3 size = (boundsMax - boundsMin); | |
Vector3 center = boundsMin + size * 0.5f; | |
return new Bounds(center, size); | |
} | |
#region SubmeshTriangleBuffer | |
public class SubmeshTriangleBuffer { | |
public int[] triangles; | |
//public int triangleCount; | |
public SubmeshTriangleBuffer (int triangleCount) { | |
triangles = new int[triangleCount]; | |
} | |
} | |
#endregion | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment