|
@@ -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]
|
|
|
|
- public string[] submeshSeparators = new string[0];
|
|
|
|
|
|
+ // Submesh Separation
|
|
|
|
+ [SpineSlot] public string[] submeshSeparators = new string[0];
|
|
|
|
+ [HideInInspector] public List<Slot> submeshSeparatorSlots = new List<Slot>();
|
|
|
|
+ #endregion
|
|
|
|
|
|
- [HideInInspector]
|
|
|
|
- public List<Slot> submeshSeparatorSlots = new List<Slot>();
|
|
|
|
|
|
+ [System.NonSerialized] public bool valid;
|
|
|
|
+ [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,35 +188,59 @@ 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;
|
|
|
|
+ var drawOrderItems = drawOrder.Items;
|
|
int drawOrderCount = drawOrder.Count;
|
|
int drawOrderCount = drawOrder.Count;
|
|
int submeshSeparatorSlotsCount = submeshSeparatorSlots.Count;
|
|
int submeshSeparatorSlotsCount = submeshSeparatorSlots.Count;
|
|
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;
|
|
|
|
- stateTemp.attachments.Clear(true);
|
|
|
|
- stateTemp.UpdateDrawOrderCount(drawOrderCount);
|
|
|
|
|
|
+ MeshState.SingleMeshState workingState = meshState.buffer;
|
|
|
|
+ var workingAttachments = workingState.attachments;
|
|
|
|
+ workingAttachments.Clear(true);
|
|
|
|
+ workingState.UpdateAttachmentCount(drawOrderCount);
|
|
|
|
+ var workingAttachmentsItems = workingAttachments.Items; // Make sure to not add to or remove from ExposedList inside the loop below
|
|
|
|
+
|
|
|
|
+ var workingFlips = workingState.attachmentsFlipState;
|
|
|
|
+ var workingFlipsItems = workingState.attachmentsFlipState.Items; // Make sure to not add to or remove from ExposedList inside the loop below
|
|
|
|
+
|
|
|
|
+ var workingSubmeshArguments = workingState.addSubmeshArguments; // Items array should not be cached. There is dynamic writing to this object.
|
|
|
|
+ workingSubmeshArguments.Clear(false);
|
|
|
|
+
|
|
|
|
+ MeshState.SingleMeshState storedState = useMesh1 ? meshState.stateMesh1 : meshState.stateMesh2;
|
|
|
|
+ var storedAttachments = storedState.attachments;
|
|
|
|
+ var storedAttachmentsItems = storedAttachments.Items; // Make sure to not add to or remove from ExposedList inside the loop below
|
|
|
|
+
|
|
|
|
+ var storedFlips = storedState.attachmentsFlipState;
|
|
|
|
+ var storedFlipsItems = storedFlips.Items; // Make sure to not add to or remove from ExposedList inside the loop below
|
|
|
|
+
|
|
|
|
+ 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 = drawOrderItems[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;
|
|
|
|
- RegionAttachment regionAttachment = attachment as RegionAttachment;
|
|
|
|
|
|
+
|
|
|
|
+ // 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
|
|
|
|
+
|
|
|
|
+ workingFlipsItems[i] = flip;
|
|
|
|
+ workingAttachmentsItems[i] = attachment;
|
|
|
|
+
|
|
|
|
+ mustUpdateMeshStructure = mustUpdateMeshStructure || // Always prefer short circuited or. || and not |=.
|
|
|
|
+ (attachment != storedAttachmentsItems[i]) || // Attachment order changed. // This relies on the drawOrder.Count != storedAttachments.Count check above as a bounds check.
|
|
|
|
+ (flip != storedFlipsItems[i]); // Flip states changed.
|
|
|
|
+
|
|
|
|
+ var regionAttachment = attachment as RegionAttachment;
|
|
if (regionAttachment != null) {
|
|
if (regionAttachment != null) {
|
|
rendererObject = regionAttachment.RendererObject;
|
|
rendererObject = regionAttachment.RendererObject;
|
|
attachmentVertexCount = 4;
|
|
attachmentVertexCount = 4;
|
|
@@ -221,13 +248,13 @@ public class SkeletonRenderer : MonoBehaviour {
|
|
} else {
|
|
} else {
|
|
if (!renderMeshes)
|
|
if (!renderMeshes)
|
|
continue;
|
|
continue;
|
|
- MeshAttachment meshAttachment = attachment as MeshAttachment;
|
|
|
|
|
|
+ var meshAttachment = attachment as MeshAttachment;
|
|
if (meshAttachment != null) {
|
|
if (meshAttachment != null) {
|
|
rendererObject = meshAttachment.RendererObject;
|
|
rendererObject = meshAttachment.RendererObject;
|
|
attachmentVertexCount = meshAttachment.vertices.Length >> 1;
|
|
attachmentVertexCount = meshAttachment.vertices.Length >> 1;
|
|
attachmentTriangleCount = meshAttachment.triangles.Length;
|
|
attachmentTriangleCount = meshAttachment.triangles.Length;
|
|
} else {
|
|
} else {
|
|
- SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment;
|
|
|
|
|
|
+ var skinnedMeshAttachment = attachment as SkinnedMeshAttachment;
|
|
if (skinnedMeshAttachment != null) {
|
|
if (skinnedMeshAttachment != null) {
|
|
rendererObject = skinnedMeshAttachment.RendererObject;
|
|
rendererObject = skinnedMeshAttachment.RendererObject;
|
|
attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1;
|
|
attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1;
|
|
@@ -237,17 +264,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 +294,43 @@ 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();
|
|
|
|
- for (int i = 0, n = stateTemp.addSubmeshArguments.Count; i < n; i++) {
|
|
|
|
- MeshState.AddSubmeshArguments arguments = stateTemp.addSubmeshArguments.Items[i];
|
|
|
|
- AddSubmesh(
|
|
|
|
- arguments.material,
|
|
|
|
- arguments.startSlot,
|
|
|
|
- arguments.endSlot,
|
|
|
|
- arguments.triangleCount,
|
|
|
|
- arguments.firstVertex,
|
|
|
|
- arguments.lastSubmesh,
|
|
|
|
- stateTemp.attachmentsFlipState
|
|
|
|
- );
|
|
|
|
|
|
+ this.submeshMaterials.Clear();
|
|
|
|
+
|
|
|
|
+ var workingSubmeshArgumentsItems = workingSubmeshArguments.Items;
|
|
|
|
+ for (int i = 0, n = workingSubmeshArguments.Count; i < n; i++) {
|
|
|
|
+ AddSubmesh(workingSubmeshArgumentsItems[i], workingFlips);
|
|
}
|
|
}
|
|
|
|
|
|
// Set materials.
|
|
// Set materials.
|
|
@@ -286,6 +342,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;
|
|
@@ -294,8 +351,12 @@ public class SkeletonRenderer : MonoBehaviour {
|
|
this.vertices = vertices = new Vector3[vertexCount];
|
|
this.vertices = vertices = new Vector3[vertexCount];
|
|
this.colors = new Color32[vertexCount];
|
|
this.colors = new Color32[vertexCount];
|
|
this.uvs = new Vector2[vertexCount];
|
|
this.uvs = new Vector2[vertexCount];
|
|
|
|
+
|
|
mesh1.Clear();
|
|
mesh1.Clear();
|
|
mesh2.Clear();
|
|
mesh2.Clear();
|
|
|
|
+ meshState.stateMesh1.requiresUpdate = true;
|
|
|
|
+ meshState.stateMesh2.requiresUpdate = true;
|
|
|
|
+
|
|
} else {
|
|
} else {
|
|
// Too many vertices, zero the extra.
|
|
// Too many vertices, zero the extra.
|
|
Vector3 zero = Vector3.zero;
|
|
Vector3 zero = Vector3.zero;
|
|
@@ -332,7 +393,7 @@ public class SkeletonRenderer : MonoBehaviour {
|
|
}
|
|
}
|
|
int i = 0;
|
|
int i = 0;
|
|
do {
|
|
do {
|
|
- Slot slot = drawOrder.Items[i];
|
|
|
|
|
|
+ Slot slot = drawOrderItems[i];
|
|
Attachment attachment = slot.attachment;
|
|
Attachment attachment = slot.attachment;
|
|
RegionAttachment regionAttachment = attachment as RegionAttachment;
|
|
RegionAttachment regionAttachment = attachment as RegionAttachment;
|
|
if (regionAttachment != null) {
|
|
if (regionAttachment != null) {
|
|
@@ -502,6 +563,9 @@ public class SkeletonRenderer : MonoBehaviour {
|
|
mesh.subMeshCount = submeshCount;
|
|
mesh.subMeshCount = submeshCount;
|
|
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.
|
|
|
|
+ storedState.requiresUpdate = false;
|
|
}
|
|
}
|
|
|
|
|
|
Vector3 meshBoundsExtents = meshBoundsMax - meshBoundsMin;
|
|
Vector3 meshBoundsExtents = meshBoundsMax - meshBoundsMin;
|
|
@@ -526,24 +590,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;
|
|
|
|
- currentMeshState.immutableTriangles = immutableTriangles;
|
|
|
|
|
|
+ storedState.immutableTriangles = immutableTriangles;
|
|
|
|
+
|
|
|
|
+ storedAttachments.Clear(true);
|
|
|
|
+ storedAttachments.GrowIfNeeded(workingAttachments.Capacity);
|
|
|
|
+ storedAttachments.Count = workingAttachments.Count;
|
|
|
|
+ workingAttachments.CopyTo(storedAttachments.Items);
|
|
|
|
|
|
- currentMeshState.attachments.Clear(true);
|
|
|
|
- currentMeshState.attachments.GrowIfNeeded(stateTemp.attachments.Capacity);
|
|
|
|
- currentMeshState.attachments.Count = stateTemp.attachments.Count;
|
|
|
|
- stateTemp.attachments.CopyTo(currentMeshState.attachments.Items);
|
|
|
|
|
|
+ storedFlips.GrowIfNeeded(workingFlips.Capacity);
|
|
|
|
+ storedFlips.Count = workingFlips.Count;
|
|
|
|
+ workingFlips.CopyTo(storedFlips.Items);
|
|
|
|
|
|
- currentMeshState.attachmentsFlipState.GrowIfNeeded(stateTemp.attachmentsFlipState.Capacity);
|
|
|
|
- currentMeshState.attachmentsFlipState.Count = stateTemp.attachmentsFlipState.Count;
|
|
|
|
- stateTemp.attachmentsFlipState.CopyTo(currentMeshState.attachmentsFlipState.Items);
|
|
|
|
|
|
+ storedState.addSubmeshArguments.GrowIfNeeded(workingSubmeshArguments.Capacity);
|
|
|
|
+ storedState.addSubmeshArguments.Count = workingSubmeshArguments.Count;
|
|
|
|
+ workingSubmeshArguments.CopyTo(storedState.addSubmeshArguments.Items);
|
|
|
|
|
|
- currentMeshState.addSubmeshArguments.GrowIfNeeded(stateTemp.addSubmeshArguments.Capacity);
|
|
|
|
- currentMeshState.addSubmeshArguments.Count = stateTemp.addSubmeshArguments.Count;
|
|
|
|
- stateTemp.addSubmeshArguments.CopyTo(currentMeshState.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];
|
|
@@ -558,87 +623,65 @@ public class SkeletonRenderer : MonoBehaviour {
|
|
useMesh1 = !useMesh1;
|
|
useMesh1 = !useMesh1;
|
|
}
|
|
}
|
|
|
|
|
|
- private bool CheckIfMustUpdateMeshStructure (ExposedList<Attachment> attachmentsTemp, ExposedList<bool> attachmentsFlipStateTemp, ExposedList<MeshState.AddSubmeshArguments> addSubmeshArgumentsTemp) {
|
|
|
|
-#if UNITY_EDITOR
|
|
|
|
|
|
+ private bool CheckIfMustUpdateMeshStructure (ExposedList<MeshState.AddSubmeshArguments> workingAddSubmeshArguments) {
|
|
|
|
+ #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
|
|
- bool mustUpdateMeshStructure =
|
|
|
|
- immutableTriangles != (useMesh1 ? meshState.stateMesh1.immutableTriangles : meshState.stateMesh2.immutableTriangles);
|
|
|
|
-
|
|
|
|
- if (mustUpdateMeshStructure)
|
|
|
|
- return true;
|
|
|
|
-
|
|
|
|
- // Check if any attachments were enabled/disabled
|
|
|
|
- // or submesh structures has changed
|
|
|
|
MeshState.SingleMeshState currentMeshState = useMesh1 ? meshState.stateMesh1 : meshState.stateMesh2;
|
|
MeshState.SingleMeshState currentMeshState = useMesh1 ? meshState.stateMesh1 : meshState.stateMesh2;
|
|
- ExposedList<Attachment> attachmentsCurrentMesh = currentMeshState.attachments;
|
|
|
|
- ExposedList<MeshState.AddSubmeshArguments> addSubmeshArgumentsCurrentMesh = currentMeshState.addSubmeshArguments;
|
|
|
|
- ExposedList<bool> attachmentsFlipStateCurrentMesh = currentMeshState.attachmentsFlipState;
|
|
|
|
-
|
|
|
|
- // 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;
|
|
|
|
|
|
+ // Check if submesh structures has changed
|
|
|
|
+ ExposedList<MeshState.AddSubmeshArguments> addSubmeshArgumentsCurrentMesh = currentMeshState.addSubmeshArguments;
|
|
|
|
+ int submeshCount = workingAddSubmeshArguments.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 (Material material, int startSlot, int endSlot, int triangleCount, int firstVertex, bool lastSubmesh, ExposedList<bool> flipStates) {
|
|
|
|
|
|
+ private void AddSubmesh (MeshState.AddSubmeshArguments submeshArguments, ExposedList<bool> flipStates) { //submeshArguments is a struct, so it's ok.
|
|
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());
|
|
else if (immutableTriangles)
|
|
else if (immutableTriangles)
|
|
return;
|
|
return;
|
|
|
|
|
|
- Submesh submesh = submeshes.Items[submeshIndex];
|
|
|
|
|
|
+ Submesh currentSubmesh = submeshes.Items[submeshIndex];
|
|
|
|
+ int[] triangles = currentSubmesh.triangles;
|
|
|
|
+
|
|
|
|
+ int triangleCount = submeshArguments.triangleCount;
|
|
|
|
+ int firstVertex = submeshArguments.firstVertex;
|
|
|
|
|
|
- int[] triangles = submesh.triangles;
|
|
|
|
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;
|
|
- submesh.triangleCount = triangleCount;
|
|
|
|
|
|
+ }
|
|
|
|
+ currentSubmesh.triangleCount = triangleCount;
|
|
|
|
+
|
|
} else if (trianglesCapacity != triangleCount) {
|
|
} else if (trianglesCapacity != triangleCount) {
|
|
// Reallocate triangles when not the exact size needed.
|
|
// Reallocate triangles when not the exact size needed.
|
|
- submesh.triangles = triangles = new int[triangleCount];
|
|
|
|
- submesh.triangleCount = 0;
|
|
|
|
|
|
+ currentSubmesh.triangles = triangles = new int[triangleCount];
|
|
|
|
+ currentSubmesh.triangleCount = 0;
|
|
}
|
|
}
|
|
|
|
|
|
- if (!renderMeshes && !frontFacing) {
|
|
|
|
|
|
+ if (!this.renderMeshes && !this.frontFacing) {
|
|
// Use stored triangles if possible.
|
|
// 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++) {
|
|
|
|
|
|
+ if (currentSubmesh.firstVertex != firstVertex || currentSubmesh.triangleCount < triangleCount) { //|| currentSubmesh.triangleCount == 0
|
|
|
|
+ currentSubmesh.triangleCount = triangleCount;
|
|
|
|
+ currentSubmesh.firstVertex = firstVertex;
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < triangleCount; i += 6, firstVertex += 4) {
|
|
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;
|
|
@@ -646,18 +689,23 @@ public class SkeletonRenderer : MonoBehaviour {
|
|
triangles[i + 4] = firstVertex + 3;
|
|
triangles[i + 4] = firstVertex + 3;
|
|
triangles[i + 5] = firstVertex + 1;
|
|
triangles[i + 5] = firstVertex + 1;
|
|
}
|
|
}
|
|
|
|
+
|
|
}
|
|
}
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- // Store triangles.
|
|
|
|
- ExposedList<Slot> drawOrder = skeleton.DrawOrder;
|
|
|
|
- for (int i = startSlot, triangleIndex = 0; i < endSlot; i++) {
|
|
|
|
- Slot slot = drawOrder.Items[i];
|
|
|
|
- Attachment attachment = slot.attachment;
|
|
|
|
|
|
+ // Iterate through all slots and store their triangles.
|
|
|
|
|
|
- bool flip = flipStates.Items[i];
|
|
|
|
|
|
+ var drawOrderItems = skeleton.DrawOrder.Items; // Make sure to not modify ExposedList inside the loop below
|
|
|
|
+ var flipStatesItems = flipStates.Items; // Make sure to not modify ExposedList inside the loop below
|
|
|
|
|
|
|
|
+ int triangleIndex = 0; // Modified by loop
|
|
|
|
+ for (int i = submeshArguments.startSlot, n = submeshArguments.endSlot; i < n; i++) {
|
|
|
|
+ Attachment attachment = drawOrderItems[i].attachment;
|
|
|
|
+
|
|
|
|
+ bool flip = flipStatesItems[i];
|
|
|
|
+
|
|
|
|
+ // Add RegionAttachment triangles
|
|
if (attachment is RegionAttachment) {
|
|
if (attachment is RegionAttachment) {
|
|
if (!flip) {
|
|
if (!flip) {
|
|
triangles[triangleIndex] = firstVertex;
|
|
triangles[triangleIndex] = firstVertex;
|
|
@@ -679,16 +727,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;
|
|
|
|
|
|
+ var 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;
|
|
|
|
|
|
+ var 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;
|
|
@@ -710,7 +760,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>();
|
|
@@ -724,26 +774,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 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) {
|
|
|
|
- attachmentsFlipState.GrowIfNeeded(drawOrderCount);
|
|
|
|
- attachmentsFlipState.Count = drawOrderCount;
|
|
|
|
|
|
+ public void UpdateAttachmentCount (int attachmentCount) {
|
|
|
|
+ attachmentsFlipState.GrowIfNeeded(attachmentCount);
|
|
|
|
+ attachmentsFlipState.Count = attachmentCount;
|
|
|
|
|
|
- attachments.GrowIfNeeded(drawOrderCount);
|
|
|
|
- attachments.Count = drawOrderCount;
|
|
|
|
|
|
+ attachments.GrowIfNeeded(attachmentCount);
|
|
|
|
+ attachments.Count = attachmentCount;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -753,22 +804,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 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 isLastSubmesh;
|
|
|
|
|
|
public bool Equals (ref AddSubmeshArguments other) {
|
|
public bool Equals (ref AddSubmeshArguments other) {
|
|
return
|
|
return
|
|
- !ReferenceEquals(material, null) &&
|
|
|
|
- !ReferenceEquals(other.material, null) &&
|
|
|
|
- material.GetInstanceID() == other.material.GetInstanceID() &&
|
|
|
|
|
|
+ //!ReferenceEquals(material, null) &&
|
|
|
|
+ //!ReferenceEquals(other.material, null) &&
|
|
|
|
+ //material.GetInstanceID() == other.material.GetInstanceID() &&
|
|
startSlot == other.startSlot &&
|
|
startSlot == other.startSlot &&
|
|
endSlot == other.endSlot &&
|
|
endSlot == other.endSlot &&
|
|
triangleCount == other.triangleCount &&
|
|
triangleCount == other.triangleCount &&
|