[Unity] Fix material array incorrect persistence

This fixes a separate flickering bug.
Reported in the forum here: http://esotericsoftware.com/forum/Weird-flicker-between-some-of-the-animations-5577
The solution was to compare `this.sharedMaterials` against the immediately-determined material array.

Also included:
Moved attachment and flip array checks outside of extra loops in CheckIfMustUpdateMeshStructure to prevent O(2n) behavior.
Renamed some identifiers. "temp" is replaced with "working". The analogy is human brain's "working memory".
Added some cached references within the method's stack (where their members are frequently accessed).
Added comments for easy update, in preparation for incoming changes in Spine v3.
This commit is contained in:
John 2015-12-23 03:31:56 +08:00
parent 6778a039c6
commit 205e0dc5ad

View File

@ -39,39 +39,46 @@ using Spine;
public class SkeletonRenderer : MonoBehaviour { public class SkeletonRenderer : MonoBehaviour {
public delegate void SkeletonRendererDelegate (SkeletonRenderer skeletonRenderer); public delegate void SkeletonRendererDelegate (SkeletonRenderer skeletonRenderer);
public SkeletonRendererDelegate OnReset; public SkeletonRendererDelegate OnReset;
[System.NonSerialized]
public bool valid;
[System.NonSerialized]
public Skeleton skeleton;
public SkeletonDataAsset skeletonDataAsset; public SkeletonDataAsset skeletonDataAsset;
public String initialSkinName; public String initialSkinName;
#region Advanced
public bool calculateNormals, calculateTangents; public bool calculateNormals, calculateTangents;
public float zSpacing; public float zSpacing;
public bool renderMeshes = true, immutableTriangles; public bool renderMeshes = true, immutableTriangles;
public bool frontFacing; public bool frontFacing;
public bool logErrors = false; public bool logErrors = false;
[SpineSlot] // Submesh Separation
public string[] submeshSeparators = new string[0]; [SpineSlot] public string[] submeshSeparators = new string[0];
[HideInInspector] public List<Slot> submeshSeparatorSlots = new List<Slot>();
#endregion
[HideInInspector] [System.NonSerialized] public bool valid;
public List<Slot> submeshSeparatorSlots = new List<Slot>(); [System.NonSerialized] public Skeleton skeleton;
private MeshRenderer meshRenderer; private MeshRenderer meshRenderer;
private MeshFilter meshFilter; private MeshFilter meshFilter;
private Mesh mesh1, mesh2; private Mesh mesh1, mesh2;
private bool useMesh1; private bool useMesh1;
private float[] tempVertices = new float[8]; private float[] tempVertices = new float[8];
private Vector3[] vertices; private Vector3[] vertices;
private Color32[] colors; private Color32[] colors;
private Vector2[] uvs; private Vector2[] uvs;
private Material[] sharedMaterials = new Material[0]; private Material[] sharedMaterials = new Material[0];
private MeshState meshState = new MeshState();
private readonly ExposedList<Material> submeshMaterials = new ExposedList<Material>(); private readonly ExposedList<Material> submeshMaterials = new ExposedList<Material>();
private readonly ExposedList<Submesh> submeshes = new ExposedList<Submesh>(); private readonly ExposedList<Submesh> submeshes = new ExposedList<Submesh>();
private SkeletonUtilitySubmeshRenderer[] submeshRenderers; private SkeletonUtilitySubmeshRenderer[] submeshRenderers;
private MeshState meshState = new MeshState();
public virtual void Awake () {
Reset();
}
public virtual void Reset () { public virtual void Reset () {
if (meshFilter != null) if (meshFilter != null)
@ -144,10 +151,6 @@ public class SkeletonRenderer : MonoBehaviour {
submeshRenderers = GetComponentsInChildren<SkeletonUtilitySubmeshRenderer>(); submeshRenderers = GetComponentsInChildren<SkeletonUtilitySubmeshRenderer>();
} }
public virtual void Awake () {
Reset();
}
public virtual void OnDestroy () { public virtual void OnDestroy () {
if (mesh1 != null) { if (mesh1 != null) {
if (Application.isPlaying) if (Application.isPlaying)
@ -167,7 +170,7 @@ public class SkeletonRenderer : MonoBehaviour {
mesh2 = null; mesh2 = null;
} }
private Mesh newMesh () { private static Mesh newMesh () {
Mesh mesh = new Mesh(); Mesh mesh = new Mesh();
mesh.name = "Skeleton Mesh"; mesh.name = "Skeleton Mesh";
mesh.hideFlags = HideFlags.HideAndDontSave; mesh.hideFlags = HideFlags.HideAndDontSave;
@ -185,6 +188,7 @@ public class SkeletonRenderer : MonoBehaviour {
// Count vertices and submesh triangles. // Count vertices and submesh triangles.
int vertexCount = 0; int vertexCount = 0;
int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0; int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0;
Material lastMaterial = null; Material lastMaterial = null;
ExposedList<Slot> drawOrder = skeleton.drawOrder; ExposedList<Slot> drawOrder = skeleton.drawOrder;
@ -193,26 +197,41 @@ public class SkeletonRenderer : MonoBehaviour {
bool renderMeshes = this.renderMeshes; bool renderMeshes = this.renderMeshes;
// Clear last state of attachments and submeshes // Clear last state of attachments and submeshes
MeshState.SingleMeshState stateTemp = meshState.stateTemp; MeshState.SingleMeshState workingState = meshState.buffer;
stateTemp.attachments.Clear(true); var workingAttachments = workingState.attachments;
stateTemp.UpdateDrawOrderCount(drawOrderCount); var workingFlips = workingState.attachmentsFlipState;
var workingSubmeshArguments = workingState.addSubmeshArguments;
workingAttachments.Clear(true);
workingState.UpdateAttachmentCount(drawOrderCount);
workingSubmeshArguments.Clear(false);
MeshState.SingleMeshState storedState = useMesh1 ? meshState.stateMesh1 : meshState.stateMesh2;
var storedAttachments = storedState.attachments;
var storedFlips = storedState.attachmentsFlipState;
bool mustUpdateMeshStructure = storedState.requiresUpdate || // Force update if the mesh was cleared. (prevents flickering due to incorrect state)
drawOrder.Count != storedAttachments.Count || // Number of slots changed (when does this happen?)
immutableTriangles != storedState.immutableTriangles; // Immutable Triangles flag changed.
stateTemp.addSubmeshArguments.Clear(false);
for (int i = 0; i < drawOrderCount; i++) { for (int i = 0; i < drawOrderCount; i++) {
Slot slot = drawOrder.Items[i]; Slot slot = drawOrder.Items[i];
Bone bone = slot.bone; Bone bone = slot.bone;
Attachment attachment = slot.attachment; Attachment attachment = slot.attachment;
object rendererObject; object rendererObject; // An AtlasRegion in plain Spine-Unity. Spine-TK2D hooks into TK2D's system. eventual source of Material object.
int attachmentVertexCount, attachmentTriangleCount; int attachmentVertexCount, attachmentTriangleCount;
bool worldScaleXIsPositive = bone.worldScaleX >= 0f;
bool worldScaleYIsPositive = bone.worldScaleY >= 0f;
bool worldScaleIsSameSigns = (worldScaleXIsPositive && worldScaleYIsPositive) ||
(!worldScaleXIsPositive && !worldScaleYIsPositive);
bool flip = frontFacing && ((bone.worldFlipX != bone.worldFlipY) == worldScaleIsSameSigns);
stateTemp.attachmentsFlipState.Items[i] = flip;
stateTemp.attachments.Items[i] = attachment; // Handle flipping for normals (for lighting).
bool worldScaleIsSameSigns = ((bone.worldScaleY >= 0f) == (bone.worldScaleX >= 0f));
bool flip = frontFacing && ((bone.worldFlipX != bone.worldFlipY) == worldScaleIsSameSigns); // TODO: bone flipX and flipY will be removed in Spine 3.0
workingFlips.Items[i] = flip;
workingAttachments.Items[i] = attachment;
mustUpdateMeshStructure = mustUpdateMeshStructure || // Always prefer short circuited or. || and not |=.
(attachment != storedAttachments.Items[i]) || // Attachment order changed. // This relies on the drawOrder.Count != storedAttachments.Count check above as a bounds check.
(flip != storedFlips.Items[i]); // Flip states changed.
RegionAttachment regionAttachment = attachment as RegionAttachment; RegionAttachment regionAttachment = attachment as RegionAttachment;
if (regionAttachment != null) { if (regionAttachment != null) {
rendererObject = regionAttachment.RendererObject; rendererObject = regionAttachment.RendererObject;
@ -237,17 +256,27 @@ public class SkeletonRenderer : MonoBehaviour {
} }
} }
// Populate submesh when material changes. #if !SPINE_TK2D
#if !SPINE_TK2D
Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject; Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject;
#else #else
Material material = (rendererObject.GetType() == typeof(Material)) ? (Material)rendererObject : (Material)((AtlasRegion)rendererObject).page.rendererObject; Material material = (rendererObject.GetType() == typeof(Material)) ? (Material)rendererObject : (Material)((AtlasRegion)rendererObject).page.rendererObject;
#endif #endif
// Populate submesh when material changes. (or when forced to separate by a submeshSeparator)
if ((lastMaterial != null && lastMaterial.GetInstanceID() != material.GetInstanceID()) || if ((lastMaterial != null && lastMaterial.GetInstanceID() != material.GetInstanceID()) ||
(submeshSeparatorSlotsCount > 0 && submeshSeparatorSlots.Contains(slot))) { (submeshSeparatorSlotsCount > 0 && submeshSeparatorSlots.Contains(slot))) {
stateTemp.addSubmeshArguments.Add(
new MeshState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false) workingSubmeshArguments.Add(
); new MeshState.AddSubmeshArguments {
material = lastMaterial,
startSlot = submeshStartSlotIndex,
endSlot = i,
triangleCount = submeshTriangleCount,
firstVertex = submeshFirstVertex,
isLastSubmesh = false
}
);
submeshTriangleCount = 0; submeshTriangleCount = 0;
submeshFirstVertex = vertexCount; submeshFirstVertex = vertexCount;
submeshStartSlotIndex = i; submeshStartSlotIndex = i;
@ -257,24 +286,41 @@ public class SkeletonRenderer : MonoBehaviour {
submeshTriangleCount += attachmentTriangleCount; submeshTriangleCount += attachmentTriangleCount;
vertexCount += attachmentVertexCount; vertexCount += attachmentVertexCount;
} }
stateTemp.addSubmeshArguments.Add(
new MeshState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true)
);
bool mustUpdateMeshStructure = CheckIfMustUpdateMeshStructure(stateTemp.attachments, stateTemp.attachmentsFlipState, stateTemp.addSubmeshArguments);
workingSubmeshArguments.Add(
new MeshState.AddSubmeshArguments {
material = lastMaterial,
startSlot = submeshStartSlotIndex,
endSlot = drawOrderCount,
triangleCount = submeshTriangleCount,
firstVertex = submeshFirstVertex,
isLastSubmesh = true
}
);
mustUpdateMeshStructure = mustUpdateMeshStructure ||
this.sharedMaterials.Length != workingSubmeshArguments.Count || // Material array changed in size
CheckIfMustUpdateMeshStructure(workingSubmeshArguments); // Submesh Argument Array changed.
// CheckIfMustUpdateMaterialArray (workingMaterials, sharedMaterials)
if (!mustUpdateMeshStructure) {
// Narrow phase material array check.
var workingMaterials = workingSubmeshArguments.Items;
for (int i = 0, n = sharedMaterials.Length; i < n; i++) {
if (this.sharedMaterials[i] != workingMaterials[i].material) { // Bounds check is implied above.
mustUpdateMeshStructure = true;
break;
}
}
}
// NOT ELSE
if (mustUpdateMeshStructure) { if (mustUpdateMeshStructure) {
submeshMaterials.Clear(); this.submeshMaterials.Clear();
for (int i = 0, n = stateTemp.addSubmeshArguments.Count; i < n; i++) { for (int i = 0, n = workingSubmeshArguments.Count; i < n; i++) {
MeshState.AddSubmeshArguments arguments = stateTemp.addSubmeshArguments.Items[i]; AddSubmesh(workingSubmeshArguments.Items[i], workingFlips);
AddSubmesh(
arguments.material,
arguments.startSlot,
arguments.endSlot,
arguments.triangleCount,
arguments.firstVertex,
arguments.lastSubmesh,
stateTemp.attachmentsFlipState
);
} }
// Set materials. // Set materials.
@ -286,6 +332,7 @@ public class SkeletonRenderer : MonoBehaviour {
meshRenderer.sharedMaterials = sharedMaterials; meshRenderer.sharedMaterials = sharedMaterials;
} }
// Ensure mesh data is the right size. // Ensure mesh data is the right size.
Vector3[] vertices = this.vertices; Vector3[] vertices = this.vertices;
bool newTriangles = vertexCount > vertices.Length; bool newTriangles = vertexCount > vertices.Length;
@ -297,8 +344,8 @@ public class SkeletonRenderer : MonoBehaviour {
mesh1.Clear(); mesh1.Clear();
mesh2.Clear(); mesh2.Clear();
meshState.stateMesh1.forceUpdate = true; meshState.stateMesh1.requiresUpdate = true;
meshState.stateMesh2.forceUpdate = true; meshState.stateMesh2.requiresUpdate = true;
} else { } else {
// Too many vertices, zero the extra. // Too many vertices, zero the extra.
@ -507,12 +554,8 @@ public class SkeletonRenderer : MonoBehaviour {
for (int i = 0; i < submeshCount; ++i) for (int i = 0; i < submeshCount; ++i)
mesh.SetTriangles(submeshes.Items[i].triangles, i); mesh.SetTriangles(submeshes.Items[i].triangles, i);
// Done updating mesh. Clear the force update state. // Done updating mesh.
if (useMesh1) { storedState.requiresUpdate = false;
meshState.stateMesh1.forceUpdate = false;
} else {
meshState.stateMesh2.forceUpdate = false;
}
} }
Vector3 meshBoundsExtents = meshBoundsMax - meshBoundsMin; Vector3 meshBoundsExtents = meshBoundsMax - meshBoundsMin;
@ -537,24 +580,25 @@ public class SkeletonRenderer : MonoBehaviour {
mesh2.tangents = tangents; mesh2.tangents = tangents;
} }
} }
// Update previous state // Update previous state
MeshState.SingleMeshState currentMeshState = useMesh1 ? meshState.stateMesh1 : meshState.stateMesh2; storedState.immutableTriangles = immutableTriangles;
currentMeshState.immutableTriangles = immutableTriangles;
currentMeshState.attachments.Clear(true); storedAttachments.Clear(true);
currentMeshState.attachments.GrowIfNeeded(stateTemp.attachments.Capacity); storedAttachments.GrowIfNeeded(workingAttachments.Capacity);
currentMeshState.attachments.Count = stateTemp.attachments.Count; storedAttachments.Count = workingAttachments.Count;
stateTemp.attachments.CopyTo(currentMeshState.attachments.Items); workingAttachments.CopyTo(storedAttachments.Items);
currentMeshState.attachmentsFlipState.GrowIfNeeded(stateTemp.attachmentsFlipState.Capacity); storedFlips.GrowIfNeeded(workingFlips.Capacity);
currentMeshState.attachmentsFlipState.Count = stateTemp.attachmentsFlipState.Count; storedFlips.Count = workingFlips.Count;
stateTemp.attachmentsFlipState.CopyTo(currentMeshState.attachmentsFlipState.Items); workingFlips.CopyTo(storedFlips.Items);
currentMeshState.addSubmeshArguments.GrowIfNeeded(stateTemp.addSubmeshArguments.Capacity); storedState.addSubmeshArguments.GrowIfNeeded(workingSubmeshArguments.Capacity);
currentMeshState.addSubmeshArguments.Count = stateTemp.addSubmeshArguments.Count; storedState.addSubmeshArguments.Count = workingSubmeshArguments.Count;
stateTemp.addSubmeshArguments.CopyTo(currentMeshState.addSubmeshArguments.Items); workingSubmeshArguments.CopyTo(storedState.addSubmeshArguments.Items);
// Submesh Renderers
if (submeshRenderers.Length > 0) { if (submeshRenderers.Length > 0) {
for (int i = 0; i < submeshRenderers.Length; i++) { for (int i = 0; i < submeshRenderers.Length; i++) {
SkeletonUtilitySubmeshRenderer submeshRenderer = submeshRenderers[i]; SkeletonUtilitySubmeshRenderer submeshRenderer = submeshRenderers[i];
@ -569,60 +613,32 @@ public class SkeletonRenderer : MonoBehaviour {
useMesh1 = !useMesh1; useMesh1 = !useMesh1;
} }
private bool CheckIfMustUpdateMeshStructure (ExposedList<Attachment> attachmentsTemp, ExposedList<bool> attachmentsFlipStateTemp, ExposedList<MeshState.AddSubmeshArguments> addSubmeshArgumentsTemp) { private bool CheckIfMustUpdateMeshStructure (ExposedList<MeshState.AddSubmeshArguments> workingAddSubmeshArguments) {
#if UNITY_EDITOR #if UNITY_EDITOR
if (!Application.isPlaying) if (!Application.isPlaying)
return true; return true;
#endif #endif
// Check if any mesh settings were changed // Check if any mesh settings were changed
MeshState.SingleMeshState currentMeshState = useMesh1 ? meshState.stateMesh1 : meshState.stateMesh2; MeshState.SingleMeshState currentMeshState = useMesh1 ? meshState.stateMesh1 : meshState.stateMesh2;
bool mustUpdateMeshStructure = // Check if submesh structures has changed
(immutableTriangles != currentMeshState.immutableTriangles) || currentMeshState.forceUpdate;
if (mustUpdateMeshStructure)
return true;
// Check if any attachments were enabled/disabled
// or submesh structures has changed
ExposedList<Attachment> attachmentsCurrentMesh = currentMeshState.attachments;
ExposedList<MeshState.AddSubmeshArguments> addSubmeshArgumentsCurrentMesh = currentMeshState.addSubmeshArguments; ExposedList<MeshState.AddSubmeshArguments> addSubmeshArgumentsCurrentMesh = currentMeshState.addSubmeshArguments;
ExposedList<bool> attachmentsFlipStateCurrentMesh = currentMeshState.attachmentsFlipState; int submeshCount = workingAddSubmeshArguments.Count;
// Check attachments
int attachmentCount = attachmentsTemp.Count;
if (attachmentsCurrentMesh.Count != attachmentCount)
return true;
for (int i = 0; i < attachmentCount; i++) {
if (attachmentsCurrentMesh.Items[i] != attachmentsTemp.Items[i])
return true;
}
// Check flip state
for (int i = 0; i < attachmentCount; i++) {
if (attachmentsFlipStateCurrentMesh.Items[i] != attachmentsFlipStateTemp.Items[i])
return true;
}
// Check submeshes
int submeshCount = addSubmeshArgumentsTemp.Count;
if (addSubmeshArgumentsCurrentMesh.Count != submeshCount) if (addSubmeshArgumentsCurrentMesh.Count != submeshCount)
return true; return true;
for (int i = 0; i < submeshCount; i++) { for (int i = 0; i < submeshCount; i++) {
if (!addSubmeshArgumentsCurrentMesh.Items[i].Equals(ref addSubmeshArgumentsTemp.Items[i])) if (!addSubmeshArgumentsCurrentMesh.Items[i].Equals(ref workingAddSubmeshArguments.Items[i]))
return true; return true;
} }
return false; return false;
} }
/** Stores vertices and triangles for a single material. */ private void AddSubmesh (MeshState.AddSubmeshArguments submeshArguments, ExposedList<bool> flipStates) {
private void AddSubmesh (Material material, int startSlot, int endSlot, int triangleCount, int firstVertex, bool lastSubmesh, ExposedList<bool> flipStates) {
int submeshIndex = submeshMaterials.Count; int submeshIndex = submeshMaterials.Count;
submeshMaterials.Add(material); submeshMaterials.Add(submeshArguments.material);
if (submeshes.Count <= submeshIndex) if (submeshes.Count <= submeshIndex)
submeshes.Add(new Submesh()); submeshes.Add(new Submesh());
@ -630,10 +646,13 @@ public class SkeletonRenderer : MonoBehaviour {
return; return;
Submesh submesh = submeshes.Items[submeshIndex]; Submesh submesh = submeshes.Items[submeshIndex];
int[] triangles = submesh.triangles; int[] triangles = submesh.triangles;
int triangleCount = submeshArguments.triangleCount;
int firstVertex = submeshArguments.firstVertex;
int trianglesCapacity = triangles.Length; int trianglesCapacity = triangles.Length;
if (lastSubmesh && trianglesCapacity > triangleCount) { if (submeshArguments.isLastSubmesh && trianglesCapacity > triangleCount) {
// Last submesh may have more triangles than required, so zero triangles to the end. // Last submesh may have more triangles than required, so zero triangles to the end.
for (int i = triangleCount; i < trianglesCapacity; i++) for (int i = triangleCount; i < trianglesCapacity; i++)
triangles[i] = 0; triangles[i] = 0;
@ -649,8 +668,8 @@ public class SkeletonRenderer : MonoBehaviour {
if (submesh.firstVertex != firstVertex || submesh.triangleCount < triangleCount) { if (submesh.firstVertex != firstVertex || submesh.triangleCount < triangleCount) {
submesh.triangleCount = triangleCount; submesh.triangleCount = triangleCount;
submesh.firstVertex = firstVertex; submesh.firstVertex = firstVertex;
int drawOrderIndex = 0; //int drawOrderIndex = 0;
for (int i = 0; i < triangleCount; i += 6, firstVertex += 4, drawOrderIndex++) { for (int i = 0; i < triangleCount; i += 6, firstVertex += 4/*, drawOrderIndex++*/) {
triangles[i] = firstVertex; triangles[i] = firstVertex;
triangles[i + 1] = firstVertex + 2; triangles[i + 1] = firstVertex + 2;
triangles[i + 2] = firstVertex + 1; triangles[i + 2] = firstVertex + 1;
@ -662,14 +681,16 @@ public class SkeletonRenderer : MonoBehaviour {
return; return;
} }
// Store triangles. // Iterate through all slots and store their triangles.
ExposedList<Slot> drawOrder = skeleton.DrawOrder; ExposedList<Slot> drawOrder = skeleton.DrawOrder;
for (int i = startSlot, triangleIndex = 0; i < endSlot; i++) { int triangleIndex = 0; // Modified by loop
for (int i = submeshArguments.startSlot, n = submeshArguments.endSlot; i < n; i++) {
Slot slot = drawOrder.Items[i]; Slot slot = drawOrder.Items[i];
Attachment attachment = slot.attachment; Attachment attachment = slot.attachment;
bool flip = flipStates.Items[i]; bool flip = flipStates.Items[i];
// Add RegionAttachment triangles
if (attachment is RegionAttachment) { if (attachment is RegionAttachment) {
if (!flip) { if (!flip) {
triangles[triangleIndex] = firstVertex; triangles[triangleIndex] = firstVertex;
@ -691,16 +712,18 @@ public class SkeletonRenderer : MonoBehaviour {
firstVertex += 4; firstVertex += 4;
continue; continue;
} }
// Add (Skinned)MeshAttachment triangles
int[] attachmentTriangles; int[] attachmentTriangles;
int attachmentVertexCount; int attachmentVertexCount;
MeshAttachment meshAttachment = attachment as MeshAttachment; MeshAttachment meshAttachment = attachment as MeshAttachment;
if (meshAttachment != null) { if (meshAttachment != null) {
attachmentVertexCount = meshAttachment.vertices.Length >> 1; attachmentVertexCount = meshAttachment.vertices.Length >> 1; // length/2
attachmentTriangles = meshAttachment.triangles; attachmentTriangles = meshAttachment.triangles;
} else { } else {
SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment; SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment;
if (skinnedMeshAttachment != null) { if (skinnedMeshAttachment != null) {
attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1; attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1; // length/2
attachmentTriangles = skinnedMeshAttachment.triangles; attachmentTriangles = skinnedMeshAttachment.triangles;
} else } else
continue; continue;
@ -722,7 +745,7 @@ public class SkeletonRenderer : MonoBehaviour {
} }
} }
#if UNITY_EDITOR #if UNITY_EDITOR
void OnDrawGizmos () { void OnDrawGizmos () {
// Make selection easier by drawing a clear gizmo over the skeleton. // Make selection easier by drawing a clear gizmo over the skeleton.
meshFilter = GetComponent<MeshFilter>(); meshFilter = GetComponent<MeshFilter>();
@ -736,27 +759,27 @@ public class SkeletonRenderer : MonoBehaviour {
Gizmos.matrix = transform.localToWorldMatrix; Gizmos.matrix = transform.localToWorldMatrix;
Gizmos.DrawCube(meshBounds.center, meshBounds.size); Gizmos.DrawCube(meshBounds.center, meshBounds.size);
} }
#endif #endif
private class MeshState { private class MeshState {
public int vertexCount; public int vertexCount;
public readonly SingleMeshState stateTemp = new SingleMeshState(); public readonly SingleMeshState buffer = new SingleMeshState();
public readonly SingleMeshState stateMesh1 = new SingleMeshState(); public readonly SingleMeshState stateMesh1 = new SingleMeshState();
public readonly SingleMeshState stateMesh2 = new SingleMeshState(); public readonly SingleMeshState stateMesh2 = new SingleMeshState();
public class SingleMeshState { public class SingleMeshState {
public bool immutableTriangles; public bool immutableTriangles;
public bool forceUpdate; public bool requiresUpdate;
public readonly ExposedList<Attachment> attachments = new ExposedList<Attachment>(); public readonly ExposedList<Attachment> attachments = new ExposedList<Attachment>();
public readonly ExposedList<bool> attachmentsFlipState = new ExposedList<bool>(); public readonly ExposedList<bool> attachmentsFlipState = new ExposedList<bool>();
public readonly ExposedList<AddSubmeshArguments> addSubmeshArguments = new ExposedList<AddSubmeshArguments>(); public readonly ExposedList<AddSubmeshArguments> addSubmeshArguments = new ExposedList<AddSubmeshArguments>();
public void UpdateDrawOrderCount(int drawOrderCount) { public void UpdateAttachmentCount (int attachmentCount) {
attachmentsFlipState.GrowIfNeeded(drawOrderCount); attachmentsFlipState.GrowIfNeeded(attachmentCount);
attachmentsFlipState.Count = drawOrderCount; attachmentsFlipState.Count = attachmentCount;
attachments.GrowIfNeeded(drawOrderCount); attachments.GrowIfNeeded(attachmentCount);
attachments.Count = drawOrderCount; attachments.Count = attachmentCount;
} }
} }
@ -766,22 +789,13 @@ public class SkeletonRenderer : MonoBehaviour {
public int endSlot; public int endSlot;
public int triangleCount; public int triangleCount;
public int firstVertex; public int firstVertex;
public bool lastSubmesh; public bool isLastSubmesh;
public AddSubmeshArguments (Material material, int startSlot, int endSlot, int triangleCount, int firstVertex, bool lastSubmesh) {
this.material = material;
this.startSlot = startSlot;
this.endSlot = endSlot;
this.triangleCount = triangleCount;
this.firstVertex = firstVertex;
this.lastSubmesh = lastSubmesh;
}
public bool Equals (ref AddSubmeshArguments other) { public bool Equals (ref AddSubmeshArguments other) {
return return
!ReferenceEquals(material, null) && //!ReferenceEquals(material, null) &&
!ReferenceEquals(other.material, null) && //!ReferenceEquals(other.material, null) &&
material.GetInstanceID() == other.material.GetInstanceID() && //material.GetInstanceID() == other.material.GetInstanceID() &&
startSlot == other.startSlot && startSlot == other.startSlot &&
endSlot == other.endSlot && endSlot == other.endSlot &&
triangleCount == other.triangleCount && triangleCount == other.triangleCount &&