private void UpdateBounds(ref ModelBound bound, Skeleton skeleton) { float[] vertices = new float[8]; var drawOrder = skeleton.DrawOrder; for (int i = 0, n = drawOrder.Count; i < n; i++) { Slot slot = drawOrder.Items[i]; Attachment attachment = slot.Attachment; if (attachment is RegionAttachment) { RegionAttachment region = (RegionAttachment)attachment; region.ComputeWorldVertices(slot.Bone, vertices); bound.Update(vertices, 8); } else if (attachment is MeshAttachment) { MeshAttachment mesh = (MeshAttachment)attachment; int vertexCount = mesh.Vertices.Length; if (vertices.Length < vertexCount) { vertices = new float[vertexCount]; } mesh.ComputeWorldVertices(slot, vertices); bound.Update(vertices, vertexCount); } else if (attachment is SkinnedMeshAttachment) { SkinnedMeshAttachment mesh = (SkinnedMeshAttachment)attachment; int vertexCount = mesh.UVs.Length; if (vertices.Length < vertexCount) { vertices = new float[vertexCount]; } mesh.ComputeWorldVertices(slot, vertices); bound.Update(vertices, vertexCount); } } }
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. Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject; if ((lastMaterial != material && lastMaterial != null) || slot.Data.name[0] == '*') { 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(); } renderer.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) { 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) { 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; } } useMesh1 = !useMesh1; }
public virtual void LateUpdate() { if (!valid) { return; } // Exit early if there is nothing to render if (!meshRenderer.enabled && submeshRenderers.Length == 0) { return; } // Count vertices and submesh triangles. int vertexCount = 0; int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0; Material lastMaterial = null; ExposedList <Slot> drawOrder = skeleton.drawOrder; int drawOrderCount = drawOrder.Count; int submeshSeparatorSlotsCount = submeshSeparatorSlots.Count; bool renderMeshes = this.renderMeshes; // Clear last state of attachments and submeshes MeshState.SingleMeshState workingState = meshState.buffer; var workingAttachments = workingState.attachments; 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. for (int i = 0; i < drawOrderCount; i++) { Slot slot = drawOrder.Items[i]; Bone bone = slot.bone; Attachment attachment = slot.attachment; object rendererObject; // An AtlasRegion in plain Spine-Unity. Spine-TK2D hooks into TK2D's system. eventual source of Material object. int attachmentVertexCount, attachmentTriangleCount; // 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; if (regionAttachment != null) { rendererObject = regionAttachment.RendererObject; attachmentVertexCount = 4; attachmentTriangleCount = 6; } else { if (!renderMeshes) { continue; } MeshAttachment meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { rendererObject = meshAttachment.RendererObject; attachmentVertexCount = meshAttachment.vertices.Length >> 1; attachmentTriangleCount = meshAttachment.triangles.Length; } else { SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment; if (skinnedMeshAttachment != null) { rendererObject = skinnedMeshAttachment.RendererObject; attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1; attachmentTriangleCount = skinnedMeshAttachment.triangles.Length; } else { continue; } } } #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 // Populate submesh when material changes. (or when forced to separate by a submeshSeparator) if ((lastMaterial != null && lastMaterial.GetInstanceID() != material.GetInstanceID()) || (submeshSeparatorSlotsCount > 0 && submeshSeparatorSlots.Contains(slot))) { workingSubmeshArguments.Add( new MeshState.AddSubmeshArguments { material = lastMaterial, startSlot = submeshStartSlotIndex, endSlot = i, triangleCount = submeshTriangleCount, firstVertex = submeshFirstVertex, isLastSubmesh = false } ); submeshTriangleCount = 0; submeshFirstVertex = vertexCount; submeshStartSlotIndex = i; } lastMaterial = material; submeshTriangleCount += attachmentTriangleCount; vertexCount += attachmentVertexCount; } 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) { this.submeshMaterials.Clear(); for (int i = 0, n = workingSubmeshArguments.Count; i < n; i++) { AddSubmesh(workingSubmeshArguments.Items[i], workingFlips); } // 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(); meshState.stateMesh1.requiresUpdate = true; meshState.stateMesh2.requiresUpdate = true; } else { // Too many vertices, zero the extra. Vector3 zero = Vector3.zero; for (int i = vertexCount, n = meshState.vertexCount; i < n; i++) { vertices[i] = zero; } } meshState.vertexCount = vertexCount; // Setup mesh. float zSpacing = this.zSpacing; float[] tempVertices = this.tempVertices; Vector2[] uvs = this.uvs; Color32[] colors = this.colors; int vertexIndex = 0; Color32 color; float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b; Vector3 meshBoundsMin; Vector3 meshBoundsMax; if (vertexCount == 0) { meshBoundsMin = new Vector3(0, 0, 0); meshBoundsMax = new Vector3(0, 0, 0); } else { meshBoundsMin.x = int.MaxValue; meshBoundsMin.y = int.MaxValue; meshBoundsMax.x = int.MinValue; meshBoundsMax.y = int.MinValue; if (zSpacing > 0f) { meshBoundsMin.z = 0f; meshBoundsMax.z = zSpacing * (drawOrderCount - 1); } else { meshBoundsMin.z = zSpacing * (drawOrderCount - 1); meshBoundsMax.z = 0f; } int i = 0; do { Slot slot = drawOrder.Items[i]; Attachment attachment = slot.attachment; RegionAttachment regionAttachment = attachment as RegionAttachment; if (regionAttachment != null) { regionAttachment.ComputeWorldVertices(slot.bone, tempVertices); float z = i * zSpacing; float x1 = tempVertices[RegionAttachment.X1], y1 = tempVertices[RegionAttachment.Y1]; float x2 = tempVertices[RegionAttachment.X2], y2 = tempVertices[RegionAttachment.Y2]; float x3 = tempVertices[RegionAttachment.X3], y3 = tempVertices[RegionAttachment.Y3]; float x4 = tempVertices[RegionAttachment.X4], y4 = tempVertices[RegionAttachment.Y4]; vertices[vertexIndex].x = x1; vertices[vertexIndex].y = y1; vertices[vertexIndex].z = z; vertices[vertexIndex + 1].x = x4; vertices[vertexIndex + 1].y = y4; vertices[vertexIndex + 1].z = z; vertices[vertexIndex + 2].x = x2; vertices[vertexIndex + 2].y = y2; vertices[vertexIndex + 2].z = z; vertices[vertexIndex + 3].x = x3; vertices[vertexIndex + 3].y = y3; vertices[vertexIndex + 3].z = z; color.a = (byte)(a * slot.a * regionAttachment.a); color.r = (byte)(r * slot.r * regionAttachment.r * color.a); color.g = (byte)(g * slot.g * regionAttachment.g * color.a); color.b = (byte)(b * slot.b * regionAttachment.b * color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } colors[vertexIndex] = color; colors[vertexIndex + 1] = color; colors[vertexIndex + 2] = color; colors[vertexIndex + 3] = color; float[] regionUVs = regionAttachment.uvs; uvs[vertexIndex].x = regionUVs[RegionAttachment.X1]; uvs[vertexIndex].y = regionUVs[RegionAttachment.Y1]; uvs[vertexIndex + 1].x = regionUVs[RegionAttachment.X4]; uvs[vertexIndex + 1].y = regionUVs[RegionAttachment.Y4]; uvs[vertexIndex + 2].x = regionUVs[RegionAttachment.X2]; uvs[vertexIndex + 2].y = regionUVs[RegionAttachment.Y2]; uvs[vertexIndex + 3].x = regionUVs[RegionAttachment.X3]; uvs[vertexIndex + 3].y = regionUVs[RegionAttachment.Y3]; // Calculate min/max X if (x1 < meshBoundsMin.x) { meshBoundsMin.x = x1; } else if (x1 > meshBoundsMax.x) { meshBoundsMax.x = x1; } if (x2 < meshBoundsMin.x) { meshBoundsMin.x = x2; } else if (x2 > meshBoundsMax.x) { meshBoundsMax.x = x2; } if (x3 < meshBoundsMin.x) { meshBoundsMin.x = x3; } else if (x3 > meshBoundsMax.x) { meshBoundsMax.x = x3; } if (x4 < meshBoundsMin.x) { meshBoundsMin.x = x4; } else if (x4 > meshBoundsMax.x) { meshBoundsMax.x = x4; } // Calculate min/max Y if (y1 < meshBoundsMin.y) { meshBoundsMin.y = y1; } else if (y1 > meshBoundsMax.y) { meshBoundsMax.y = y1; } if (y2 < meshBoundsMin.y) { meshBoundsMin.y = y2; } else if (y2 > meshBoundsMax.y) { meshBoundsMax.y = y2; } if (y3 < meshBoundsMin.y) { meshBoundsMin.y = y3; } else if (y3 > meshBoundsMax.y) { meshBoundsMax.y = y3; } if (y4 < meshBoundsMin.y) { meshBoundsMin.y = y4; } else if (y4 > meshBoundsMax.y) { meshBoundsMax.y = y4; } vertexIndex += 4; } else { if (!renderMeshes) { continue; } MeshAttachment meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { int meshVertexCount = meshAttachment.vertices.Length; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } meshAttachment.ComputeWorldVertices(slot, tempVertices); color.a = (byte)(a * slot.a * meshAttachment.a); color.r = (byte)(r * slot.r * meshAttachment.r * color.a); color.g = (byte)(g * slot.g * meshAttachment.g * color.a); color.b = (byte)(b * slot.b * meshAttachment.b * color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } float[] meshUVs = meshAttachment.uvs; float z = i * zSpacing; for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { float x = tempVertices[ii], y = tempVertices[ii + 1]; vertices[vertexIndex].x = x; vertices[vertexIndex].y = y; vertices[vertexIndex].z = z; colors[vertexIndex] = color; uvs[vertexIndex].x = meshUVs[ii]; uvs[vertexIndex].y = meshUVs[ii + 1]; if (x < meshBoundsMin.x) { meshBoundsMin.x = x; } else if (x > meshBoundsMax.x) { meshBoundsMax.x = x; } if (y < meshBoundsMin.y) { meshBoundsMin.y = y; } else if (y > meshBoundsMax.y) { meshBoundsMax.y = y; } } } else { SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment; if (skinnedMeshAttachment != null) { int meshVertexCount = skinnedMeshAttachment.uvs.Length; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } skinnedMeshAttachment.ComputeWorldVertices(slot, tempVertices); color.a = (byte)(a * slot.a * skinnedMeshAttachment.a); color.r = (byte)(r * slot.r * skinnedMeshAttachment.r * color.a); color.g = (byte)(g * slot.g * skinnedMeshAttachment.g * color.a); color.b = (byte)(b * slot.b * skinnedMeshAttachment.b * color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } float[] meshUVs = skinnedMeshAttachment.uvs; float z = i * zSpacing; for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { float x = tempVertices[ii], y = tempVertices[ii + 1]; vertices[vertexIndex].x = x; vertices[vertexIndex].y = y; vertices[vertexIndex].z = z; colors[vertexIndex] = color; uvs[vertexIndex].x = meshUVs[ii]; uvs[vertexIndex].y = meshUVs[ii + 1]; if (x < meshBoundsMin.x) { meshBoundsMin.x = x; } else if (x > meshBoundsMax.x) { meshBoundsMax.x = x; } if (y < meshBoundsMin.y) { meshBoundsMin.y = y; } else if (y > meshBoundsMax.y) { meshBoundsMax.y = y; } } } } } } while (++i < drawOrderCount); } // Double buffer mesh. Mesh mesh = useMesh1 ? mesh1 : mesh2; meshFilter.sharedMesh = mesh; mesh.vertices = vertices; mesh.colors32 = colors; mesh.uv = uvs; if (mustUpdateMeshStructure) { int submeshCount = submeshMaterials.Count; mesh.subMeshCount = submeshCount; for (int i = 0; i < submeshCount; ++i) { mesh.SetTriangles(submeshes.Items[i].triangles, i); } // Done updating mesh. storedState.requiresUpdate = false; } Vector3 meshBoundsExtents = meshBoundsMax - meshBoundsMin; Vector3 meshBoundsCenter = meshBoundsMin + meshBoundsExtents * 0.5f; mesh.bounds = new Bounds(meshBoundsCenter, meshBoundsExtents); 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; } } // Update previous state storedState.immutableTriangles = immutableTriangles; storedAttachments.Clear(true); storedAttachments.GrowIfNeeded(workingAttachments.Capacity); storedAttachments.Count = workingAttachments.Count; workingAttachments.CopyTo(storedAttachments.Items); storedFlips.GrowIfNeeded(workingFlips.Capacity); storedFlips.Count = workingFlips.Count; workingFlips.CopyTo(storedFlips.Items); storedState.addSubmeshArguments.GrowIfNeeded(workingSubmeshArguments.Capacity); storedState.addSubmeshArguments.Count = workingSubmeshArguments.Count; workingSubmeshArguments.CopyTo(storedState.addSubmeshArguments.Items); // Submesh Renderers if (submeshRenderers.Length > 0) { for (int i = 0; i < submeshRenderers.Length; i++) { SkeletonUtilitySubmeshRenderer submeshRenderer = submeshRenderers[i]; if (submeshRenderer.submeshIndex < sharedMaterials.Length) { submeshRenderer.SetMesh(meshRenderer, useMesh1 ? mesh1 : mesh2, sharedMaterials[submeshRenderer.submeshIndex]); } else { submeshRenderer.GetComponent <Renderer>().enabled = false; } } } useMesh1 = !useMesh1; }
protected void UpdateSkeletonGeometry() { skeletonGeometry.ClearInstances(); //defaultBlendState = PremultipliedAlpha ? BlendState.AlphaBlend : BlendState.NonPremultiplied; float[] vertices = this.vertices; List <Slot> drawOrder = Skeleton.DrawOrder; float x = Skeleton.X, y = Skeleton.Y; CCColor3B color3b = Color; float skeletonR = color3b.R / 255f; float skeletonG = color3b.G / 255f; float skeletonB = color3b.B / 255f; float skeletonA = Opacity / 255f; for (int i = 0, n = drawOrder.Count; i < n; i++) { Slot slot = drawOrder[i]; Attachment attachment = slot.Attachment; if (attachment is RegionAttachment) { RegionAttachment regionAttachment = (RegionAttachment)attachment; //BlendState blend = slot.Data.AdditiveBlending ? BlendState.Additive : defaultBlendState; var item = skeletonGeometry.CreateGeometryInstance(4, 6); //item.InstanceAttributes.BlendState = blend; //item.InstanceAttributes.AdditionalTransform = AffineWorldTransform; item.GeometryPacket.Indicies = quadTriangles; var itemVertices = item.GeometryPacket.Vertices; AtlasRegion region = (AtlasRegion)regionAttachment.RendererObject; item.GeometryPacket.Texture = (CCTexture2D)region.page.rendererObject; CCColor4B color; float a = skeletonA * slot.A * regionAttachment.A; if (PremultipliedAlpha) { color = new CCColor4B( skeletonR * slot.R * regionAttachment.R * a, skeletonG * slot.G * regionAttachment.G * a, skeletonB * slot.B * regionAttachment.B * a, a); } else { color = new CCColor4B( skeletonR * slot.R * regionAttachment.R, skeletonG * slot.G * regionAttachment.G, skeletonB * slot.B * regionAttachment.B, a); } itemVertices[TL].Colors = color; itemVertices[BL].Colors = color; itemVertices[BR].Colors = color; itemVertices[TR].Colors = color; regionAttachment.ComputeWorldVertices(x, y, slot.Bone, vertices); itemVertices[TL].Vertices.X = vertices[RegionAttachment.X1]; itemVertices[TL].Vertices.Y = vertices[RegionAttachment.Y1]; itemVertices[TL].Vertices.Z = 0; itemVertices[BL].Vertices.X = vertices[RegionAttachment.X2]; itemVertices[BL].Vertices.Y = vertices[RegionAttachment.Y2]; itemVertices[BL].Vertices.Z = 0; itemVertices[BR].Vertices.X = vertices[RegionAttachment.X3]; itemVertices[BR].Vertices.Y = vertices[RegionAttachment.Y3]; itemVertices[BR].Vertices.Z = 0; itemVertices[TR].Vertices.X = vertices[RegionAttachment.X4]; itemVertices[TR].Vertices.Y = vertices[RegionAttachment.Y4]; itemVertices[TR].Vertices.Z = 0; float[] uvs = regionAttachment.UVs; itemVertices[TL].TexCoords.U = uvs[RegionAttachment.X1]; itemVertices[TL].TexCoords.V = uvs[RegionAttachment.Y1]; itemVertices[BL].TexCoords.U = uvs[RegionAttachment.X2]; itemVertices[BL].TexCoords.V = uvs[RegionAttachment.Y2]; itemVertices[BR].TexCoords.U = uvs[RegionAttachment.X3]; itemVertices[BR].TexCoords.V = uvs[RegionAttachment.Y3]; itemVertices[TR].TexCoords.U = uvs[RegionAttachment.X4]; itemVertices[TR].TexCoords.V = uvs[RegionAttachment.Y4]; } else if (attachment is MeshAttachment) { MeshAttachment mesh = (MeshAttachment)attachment; int vertexCount = mesh.Vertices.Length; if (vertices.Length < vertexCount) { vertices = new float[vertexCount]; } mesh.ComputeWorldVertices(x, y, slot, vertices); int[] triangles = mesh.Triangles; var item = skeletonGeometry.CreateGeometryInstance(vertexCount, triangles.Length); //item.InstanceAttributes.AdditionalTransform = AffineWorldTransform; item.GeometryPacket.Indicies = triangles; AtlasRegion region = (AtlasRegion)mesh.RendererObject; item.GeometryPacket.Texture = (CCTexture2D)region.page.rendererObject; CCColor4B color; float a = skeletonA * slot.A * mesh.A; if (PremultipliedAlpha) { color = new CCColor4B( skeletonR * slot.R * mesh.R * a, skeletonG * slot.G * mesh.G * a, skeletonB * slot.B * mesh.B * a, a); } else { color = new CCColor4B( skeletonR * slot.R * mesh.R, skeletonG * slot.G * mesh.G, skeletonB * slot.B * mesh.B, a); } float[] uvs = mesh.UVs; var itemVertices = item.GeometryPacket.Vertices; for (int ii = 0, v = 0; v < vertexCount; ii++, v += 2) { itemVertices[ii].Colors = color; itemVertices[ii].Vertices.X = vertices[v]; itemVertices[ii].Vertices.Y = vertices[v + 1]; itemVertices[ii].Vertices.Z = 0; itemVertices[ii].TexCoords.U = uvs[v]; itemVertices[ii].TexCoords.V = uvs[v + 1]; } } else if (attachment is SkinnedMeshAttachment) { SkinnedMeshAttachment mesh = (SkinnedMeshAttachment)attachment; int vertexCount = mesh.UVs.Length; if (vertices.Length < vertexCount) { vertices = new float[vertexCount]; } mesh.ComputeWorldVertices(x, y, slot, vertices); int[] triangles = mesh.Triangles; var item = skeletonGeometry.CreateGeometryInstance(vertexCount, triangles.Length); item.GeometryPacket.Indicies = triangles; //item.InstanceAttributes.AdditionalTransform = AffineWorldTransform; AtlasRegion region = (AtlasRegion)mesh.RendererObject; item.GeometryPacket.Texture = (CCTexture2D)region.page.rendererObject; CCColor4B color; float a = skeletonA * slot.A * mesh.A; if (PremultipliedAlpha) { color = new CCColor4B( skeletonR * slot.R * mesh.R * a, skeletonG * slot.G * mesh.G * a, skeletonB * slot.B * mesh.B * a, a); } else { color = new CCColor4B( skeletonR * slot.R * mesh.R, skeletonG * slot.G * mesh.G, skeletonB * slot.B * mesh.B, a); } float[] uvs = mesh.UVs; var itemVertices = item.GeometryPacket.Vertices; for (int ii = 0, v = 0; v < vertexCount; ii++, v += 2) { itemVertices[ii].Colors = color; itemVertices[ii].Vertices.X = vertices[v]; itemVertices[ii].Vertices.Y = vertices[v + 1]; itemVertices[ii].Vertices.Z = 0; itemVertices[ii].TexCoords.U = uvs[v]; itemVertices[ii].TexCoords.V = uvs[v + 1]; } } } debugger.Clear(); if (DebugBones || DebugSlots) { if (DebugSlots) { for (int i = 0; i < Skeleton.Slots.Count; ++i) { var slot = Skeleton.Slots[i]; if (slot.Attachment == null) { continue; } var verticesCount = 0; var worldVertices = new float[1000]; // Max number of vertices per mesh. if (slot.Attachment is RegionAttachment) { var attachment = (RegionAttachment)slot.Attachment; attachment.ComputeWorldVertices(Skeleton.X, Skeleton.Y, slot.bone, worldVertices); verticesCount = 8; } else if (slot.Attachment is MeshAttachment) { var mesh = (MeshAttachment)slot.Attachment; mesh.ComputeWorldVertices(Skeleton.X, Skeleton.Y, slot, worldVertices); verticesCount = mesh.Vertices.Length; } else if (slot.Attachment is SkinnedMeshAttachment) { var mesh = (SkinnedMeshAttachment)slot.Attachment; mesh.ComputeWorldVertices(Skeleton.X, Skeleton.Y, slot, worldVertices); verticesCount = mesh.UVs.Length; } else { continue; } CCPoint[] slotVertices = new CCPoint[verticesCount / 2]; for (int ii = 0, si = 0; ii < verticesCount; ii += 2, si++) { slotVertices[si].X = worldVertices[ii] * ScaleX; slotVertices[si].Y = worldVertices[ii + 1] * ScaleY; } debugger.DrawPolygon(slotVertices, verticesCount / 2, CCColor4B.Transparent, 1, DebugSlotColor); } } if (DebugBones) { // Bone lengths. for (int i = 0; i < Skeleton.Bones.Count; i++) { Bone bone = Skeleton.Bones[i]; x = bone.Data.Length * bone.M00 + bone.WorldX; y = bone.Data.Length * bone.M10 + bone.WorldY; debugger.DrawLine(new CCPoint(bone.WorldX, bone.WorldY), new CCPoint(x, y), 1, DebugJointColor); } // Bone origins. for (int i = 0; i < Skeleton.Bones.Count; i++) { Bone bone = Skeleton.Bones[i]; debugger.DrawDot(new CCPoint(bone.WorldX, bone.WorldY), 3, DebugBoneColor); } } } }
public virtual void LateUpdate() { if (!valid) { return; } // Exit early if there is nothing to render if (!meshRenderer.enabled && submeshRenderers.Length == 0) { return; } // Count vertices and submesh triangles. int vertexCount = 0; int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0; Material lastMaterial = null; ExposedList <Slot> drawOrder = skeleton.drawOrder; int drawOrderCount = drawOrder.Count; int submeshSeparatorSlotsCount = submeshSeparatorSlots.Count; bool renderMeshes = this.renderMeshes; // Clear last state of attachments and submeshes ExposedList <int> attachmentsTriangleCountTemp = lastState.attachmentsTriangleCountTemp; attachmentsTriangleCountTemp.GrowIfNeeded(drawOrderCount); attachmentsTriangleCountTemp.Count = drawOrderCount; ExposedList <bool> attachmentsFlipStateTemp = lastState.attachmentsFlipStateTemp; attachmentsFlipStateTemp.GrowIfNeeded(drawOrderCount); attachmentsFlipStateTemp.Count = drawOrderCount; ExposedList <LastState.AddSubmeshArguments> addSubmeshArgumentsTemp = lastState.addSubmeshArgumentsTemp; addSubmeshArgumentsTemp.Clear(false); for (int i = 0; i < drawOrderCount; i++) { Slot slot = drawOrder.Items[i]; Bone bone = slot.bone; Attachment attachment = slot.attachment; object rendererObject; 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); attachmentsFlipStateTemp.Items[i] = flip; attachmentsTriangleCountTemp.Items[i] = -1; RegionAttachment regionAttachment = attachment as RegionAttachment; if (regionAttachment != null) { rendererObject = regionAttachment.RendererObject; attachmentVertexCount = 4; attachmentTriangleCount = 6; } else { if (!renderMeshes) { continue; } MeshAttachment meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { rendererObject = meshAttachment.RendererObject; attachmentVertexCount = meshAttachment.vertices.Length >> 1; attachmentTriangleCount = meshAttachment.triangles.Length; } else { SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment; if (skinnedMeshAttachment != null) { rendererObject = skinnedMeshAttachment.RendererObject; attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1; attachmentTriangleCount = skinnedMeshAttachment.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 != null && lastMaterial.GetInstanceID() != material.GetInstanceID()) || (submeshSeparatorSlotsCount > 0 && submeshSeparatorSlots.Contains(slot))) { addSubmeshArgumentsTemp.Add( new LastState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false) ); submeshTriangleCount = 0; submeshFirstVertex = vertexCount; submeshStartSlotIndex = i; } lastMaterial = material; submeshTriangleCount += attachmentTriangleCount; vertexCount += attachmentVertexCount; attachmentsTriangleCountTemp.Items[i] = attachmentTriangleCount; } addSubmeshArgumentsTemp.Add( new LastState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true) ); bool mustUpdateMeshStructure = CheckIfMustUpdateMeshStructure(attachmentsTriangleCountTemp, attachmentsFlipStateTemp, addSubmeshArgumentsTemp); if (mustUpdateMeshStructure) { submeshMaterials.Clear(); for (int i = 0, n = addSubmeshArgumentsTemp.Count; i < n; i++) { LastState.AddSubmeshArguments arguments = addSubmeshArgumentsTemp.Items[i]; AddSubmesh( arguments.material, arguments.startSlot, arguments.endSlot, arguments.triangleCount, arguments.firstVertex, arguments.lastSubmesh, attachmentsFlipStateTemp ); } // 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 = lastState.vertexCount; i < n; i++) { vertices[i] = zero; } } lastState.vertexCount = vertexCount; // Setup mesh. float zSpacing = this.zSpacing; float[] tempVertices = this.tempVertices; Vector2[] uvs = this.uvs; Color32[] colors = this.colors; int vertexIndex = 0; Color32 color; float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b; Vector3 meshBoundsMin; Vector3 meshBoundsMax; if (vertexCount == 0) { meshBoundsMin = new Vector3(0, 0, 0); meshBoundsMax = new Vector3(0, 0, 0); } else { meshBoundsMin.x = int.MaxValue; meshBoundsMin.y = int.MaxValue; meshBoundsMax.x = int.MinValue; meshBoundsMax.y = int.MinValue; if (zSpacing > 0f) { meshBoundsMin.z = 0f; meshBoundsMax.z = zSpacing * (drawOrderCount - 1); } else { meshBoundsMin.z = zSpacing * (drawOrderCount - 1); meshBoundsMax.z = 0f; } int i = 0; do { Slot slot = drawOrder.Items[i]; Attachment attachment = slot.attachment; RegionAttachment regionAttachment = attachment as RegionAttachment; if (regionAttachment != null) { regionAttachment.ComputeWorldVertices(slot.bone, tempVertices); float z = i * zSpacing; float x1 = tempVertices[RegionAttachment.X1], y1 = tempVertices[RegionAttachment.Y1]; float x2 = tempVertices[RegionAttachment.X2], y2 = tempVertices[RegionAttachment.Y2]; float x3 = tempVertices[RegionAttachment.X3], y3 = tempVertices[RegionAttachment.Y3]; float x4 = tempVertices[RegionAttachment.X4], y4 = tempVertices[RegionAttachment.Y4]; vertices[vertexIndex].x = x1; vertices[vertexIndex].y = y1; vertices[vertexIndex].z = z; vertices[vertexIndex + 1].x = x4; vertices[vertexIndex + 1].y = y4; vertices[vertexIndex + 1].z = z; vertices[vertexIndex + 2].x = x2; vertices[vertexIndex + 2].y = y2; vertices[vertexIndex + 2].z = z; vertices[vertexIndex + 3].x = x3; vertices[vertexIndex + 3].y = y3; vertices[vertexIndex + 3].z = z; color.a = (byte)(a * slot.a * regionAttachment.a); color.r = (byte)(r * slot.r * regionAttachment.r * color.a); color.g = (byte)(g * slot.g * regionAttachment.g * color.a); color.b = (byte)(b * slot.b * regionAttachment.b * color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } colors[vertexIndex] = color; colors[vertexIndex + 1] = color; colors[vertexIndex + 2] = color; colors[vertexIndex + 3] = color; float[] regionUVs = regionAttachment.uvs; uvs[vertexIndex].x = regionUVs[RegionAttachment.X1]; uvs[vertexIndex].y = regionUVs[RegionAttachment.Y1]; uvs[vertexIndex + 1].x = regionUVs[RegionAttachment.X4]; uvs[vertexIndex + 1].y = regionUVs[RegionAttachment.Y4]; uvs[vertexIndex + 2].x = regionUVs[RegionAttachment.X2]; uvs[vertexIndex + 2].y = regionUVs[RegionAttachment.Y2]; uvs[vertexIndex + 3].x = regionUVs[RegionAttachment.X3]; uvs[vertexIndex + 3].y = regionUVs[RegionAttachment.Y3]; // Calculate min/max X if (x1 < meshBoundsMin.x) { meshBoundsMin.x = x1; } else if (x1 > meshBoundsMax.x) { meshBoundsMax.x = x1; } if (x2 < meshBoundsMin.x) { meshBoundsMin.x = x2; } else if (x2 > meshBoundsMax.x) { meshBoundsMax.x = x2; } if (x3 < meshBoundsMin.x) { meshBoundsMin.x = x3; } else if (x3 > meshBoundsMax.x) { meshBoundsMax.x = x3; } if (x4 < meshBoundsMin.x) { meshBoundsMin.x = x4; } else if (x4 > meshBoundsMax.x) { meshBoundsMax.x = x4; } // Calculate min/max Y if (y1 < meshBoundsMin.y) { meshBoundsMin.y = y1; } else if (y1 > meshBoundsMax.y) { meshBoundsMax.y = y1; } if (y2 < meshBoundsMin.y) { meshBoundsMin.y = y2; } else if (y2 > meshBoundsMax.y) { meshBoundsMax.y = y2; } if (y3 < meshBoundsMin.y) { meshBoundsMin.y = y3; } else if (y3 > meshBoundsMax.y) { meshBoundsMax.y = y3; } if (y4 < meshBoundsMin.y) { meshBoundsMin.y = y4; } else if (y4 > meshBoundsMax.y) { meshBoundsMax.y = y4; } vertexIndex += 4; } else { if (!renderMeshes) { continue; } MeshAttachment meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { int meshVertexCount = meshAttachment.vertices.Length; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } meshAttachment.ComputeWorldVertices(slot, tempVertices); color.a = (byte)(a * slot.a * meshAttachment.a); color.r = (byte)(r * slot.r * meshAttachment.r * color.a); color.g = (byte)(g * slot.g * meshAttachment.g * color.a); color.b = (byte)(b * slot.b * meshAttachment.b * color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } float[] meshUVs = meshAttachment.uvs; float z = i * zSpacing; for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { float x = tempVertices[ii], y = tempVertices[ii + 1]; vertices[vertexIndex].x = x; vertices[vertexIndex].y = y; vertices[vertexIndex].z = z; colors[vertexIndex] = color; uvs[vertexIndex].x = meshUVs[ii]; uvs[vertexIndex].y = meshUVs[ii + 1]; if (x < meshBoundsMin.x) { meshBoundsMin.x = x; } else if (x > meshBoundsMax.x) { meshBoundsMax.x = x; } if (y < meshBoundsMin.y) { meshBoundsMin.y = y; } else if (y > meshBoundsMax.y) { meshBoundsMax.y = y; } } } else { SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment; if (skinnedMeshAttachment != null) { int meshVertexCount = skinnedMeshAttachment.uvs.Length; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } skinnedMeshAttachment.ComputeWorldVertices(slot, tempVertices); color.a = (byte)(a * slot.a * skinnedMeshAttachment.a); color.r = (byte)(r * slot.r * skinnedMeshAttachment.r * color.a); color.g = (byte)(g * slot.g * skinnedMeshAttachment.g * color.a); color.b = (byte)(b * slot.b * skinnedMeshAttachment.b * color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } float[] meshUVs = skinnedMeshAttachment.uvs; float z = i * zSpacing; for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { float x = tempVertices[ii], y = tempVertices[ii + 1]; vertices[vertexIndex].x = x; vertices[vertexIndex].y = y; vertices[vertexIndex].z = z; colors[vertexIndex] = color; uvs[vertexIndex].x = meshUVs[ii]; uvs[vertexIndex].y = meshUVs[ii + 1]; if (x < meshBoundsMin.x) { meshBoundsMin.x = x; } else if (x > meshBoundsMax.x) { meshBoundsMax.x = x; } if (y < meshBoundsMin.y) { meshBoundsMin.y = y; } else if (y > meshBoundsMax.y) { meshBoundsMax.y = y; } } } } } } while (++i < drawOrderCount); } // Double buffer mesh. Mesh mesh = useMesh1 ? mesh1 : mesh2; meshFilter.sharedMesh = mesh; mesh.vertices = vertices; mesh.colors32 = colors; mesh.uv = uvs; if (mustUpdateMeshStructure) { int submeshCount = submeshMaterials.Count; mesh.subMeshCount = submeshCount; for (int i = 0; i < submeshCount; ++i) { mesh.SetTriangles(submeshes.Items[i].triangles, i); } } Vector3 meshBoundsExtents = meshBoundsMax - meshBoundsMin; Vector3 meshBoundsCenter = meshBoundsMin + meshBoundsExtents * 0.5f; mesh.bounds = new Bounds(meshBoundsCenter, meshBoundsExtents); 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; } } // Update previous state ExposedList <int> attachmentsTriangleCountCurrentMesh; ExposedList <bool> attachmentsFlipStateCurrentMesh; ExposedList <LastState.AddSubmeshArguments> addSubmeshArgumentsCurrentMesh; if (useMesh1) { attachmentsTriangleCountCurrentMesh = lastState.attachmentsTriangleCountMesh1; addSubmeshArgumentsCurrentMesh = lastState.addSubmeshArgumentsMesh1; attachmentsFlipStateCurrentMesh = lastState.attachmentsFlipStateMesh1; lastState.immutableTrianglesMesh1 = immutableTriangles; } else { attachmentsTriangleCountCurrentMesh = lastState.attachmentsTriangleCountMesh2; addSubmeshArgumentsCurrentMesh = lastState.addSubmeshArgumentsMesh2; attachmentsFlipStateCurrentMesh = lastState.attachmentsFlipStateMesh2; lastState.immutableTrianglesMesh2 = immutableTriangles; } attachmentsTriangleCountCurrentMesh.GrowIfNeeded(attachmentsTriangleCountTemp.Capacity); attachmentsTriangleCountCurrentMesh.Count = attachmentsTriangleCountTemp.Count; attachmentsTriangleCountTemp.CopyTo(attachmentsTriangleCountCurrentMesh.Items, 0); attachmentsFlipStateCurrentMesh.GrowIfNeeded(attachmentsFlipStateTemp.Capacity); attachmentsFlipStateCurrentMesh.Count = attachmentsFlipStateTemp.Count; attachmentsFlipStateTemp.CopyTo(attachmentsFlipStateCurrentMesh.Items, 0); addSubmeshArgumentsCurrentMesh.GrowIfNeeded(addSubmeshArgumentsTemp.Count); addSubmeshArgumentsCurrentMesh.Count = addSubmeshArgumentsTemp.Count; addSubmeshArgumentsTemp.CopyTo(addSubmeshArgumentsCurrentMesh.Items); if (submeshRenderers.Length > 0) { for (int i = 0; i < submeshRenderers.Length; i++) { SkeletonUtilitySubmeshRenderer submeshRenderer = submeshRenderers[i]; if (submeshRenderer.submeshIndex < sharedMaterials.Length) { submeshRenderer.SetMesh(meshRenderer, useMesh1 ? mesh1 : mesh2, sharedMaterials[submeshRenderer.submeshIndex]); } else { submeshRenderer.GetComponent <Renderer>().enabled = false; } } } useMesh1 = !useMesh1; }
/// <summary> /// Helper method that draws debug lines. /// </summary> /// <remarks> /// This method will only work on debug mode and if RenderManager.DebugLines /> /// is set to <c>true</c>. /// </remarks> protected override void DrawDebugLines() { base.DrawDebugLines(); var platform = WaveServices.Platform; Vector2 start = new Vector2(); Vector2 end = new Vector2(); Color color = Color.Red; // Draw bones if ((this.ActualDebugMode & DebugMode.Bones) == DebugMode.Bones) { foreach (var bone in this.SkeletalAnimation.Skeleton.Bones) { if (bone.Parent != null) { start.X = bone.WorldX; start.Y = -bone.WorldY; end.X = (bone.Data.Length * bone.M00) + bone.WorldX; end.Y = -((bone.Data.Length * bone.M10) + bone.WorldY); Vector2.Transform(ref start, ref this.localWorld, out start); Vector2.Transform(ref end, ref this.localWorld, out end); RenderManager.LineBatch2D.DrawLine(ref start, ref end, ref color); } } } // Draw quads if ((this.ActualDebugMode & DebugMode.Quads) == DebugMode.Quads) { color = Color.Yellow; for (int i = 0; i < this.drawOrder.Count; i++) { Slot slot = this.drawOrder[i]; Attachment attachment = slot.Attachment; if (attachment is RegionAttachment) { float[] spineVertices = new float[8]; RegionAttachment mesh = (RegionAttachment)attachment; mesh.ComputeWorldVertices(0, 0, slot.Bone, spineVertices); // Edge1 start.X = spineVertices[RegionAttachment.X1]; start.Y = -spineVertices[RegionAttachment.Y1]; end.X = spineVertices[RegionAttachment.X2]; end.Y = -spineVertices[RegionAttachment.Y2]; Vector2.Transform(ref start, ref this.localWorld, out start); Vector2.Transform(ref end, ref this.localWorld, out end); RenderManager.LineBatch2D.DrawLine(ref start, ref end, ref color); // Edge2 start.X = spineVertices[RegionAttachment.X2]; start.Y = -spineVertices[RegionAttachment.Y2]; end.X = spineVertices[RegionAttachment.X3]; end.Y = -spineVertices[RegionAttachment.Y3]; Vector2.Transform(ref start, ref this.localWorld, out start); Vector2.Transform(ref end, ref this.localWorld, out end); RenderManager.LineBatch2D.DrawLine(ref start, ref end, ref color); // Edge3 start.X = spineVertices[RegionAttachment.X3]; start.Y = -spineVertices[RegionAttachment.Y3]; end.X = spineVertices[RegionAttachment.X4]; end.Y = -spineVertices[RegionAttachment.Y4]; Vector2.Transform(ref start, ref this.localWorld, out start); Vector2.Transform(ref end, ref this.localWorld, out end); RenderManager.LineBatch2D.DrawLine(ref start, ref end, ref color); // Edge4 start.X = spineVertices[RegionAttachment.X4]; start.Y = -spineVertices[RegionAttachment.Y4]; end.X = spineVertices[RegionAttachment.X1]; end.Y = -spineVertices[RegionAttachment.Y1]; Vector2.Transform(ref start, ref this.localWorld, out start); Vector2.Transform(ref end, ref this.localWorld, out end); RenderManager.LineBatch2D.DrawLine(ref start, ref end, ref color); } else if (attachment is MeshAttachment) { MeshAttachment mesh = (MeshAttachment)attachment; int vertexCount = mesh.Vertices.Length; float[] spineVertices = new float[vertexCount]; mesh.ComputeWorldVertices(0, 0, slot, spineVertices); for (int j = 0; j < vertexCount; j += 2) { start.X = spineVertices[j]; start.Y = -spineVertices[j + 1]; if (j < vertexCount - 2) { end.X = spineVertices[j + 2]; end.Y = -spineVertices[j + 3]; } else { end.X = spineVertices[0]; end.Y = -spineVertices[1]; } Vector2.Transform(ref start, ref this.localWorld, out start); Vector2.Transform(ref end, ref this.localWorld, out end); RenderManager.LineBatch2D.DrawLine(ref start, ref end, ref color); } } else if (attachment is SkinnedMeshAttachment) { SkinnedMeshAttachment mesh = (SkinnedMeshAttachment)attachment; int vertexCount = mesh.UVs.Length; float[] spineVertices = new float[vertexCount]; mesh.ComputeWorldVertices(0, 0, slot, spineVertices); for (int j = 0; j < vertexCount; j += 2) { start.X = spineVertices[j]; start.Y = -spineVertices[j + 1]; if (j < vertexCount - 2) { end.X = spineVertices[j + 2]; end.Y = -spineVertices[j + 3]; } else { end.X = spineVertices[0]; end.Y = -spineVertices[1]; } Vector2.Transform(ref start, ref this.localWorld, out start); Vector2.Transform(ref end, ref this.localWorld, out end); RenderManager.LineBatch2D.DrawLine(ref start, ref end, ref color); } } } } }
/// <summary> /// Allows to perform custom drawing. /// </summary> /// <param name="gameTime">The elapsed game time.</param> public override void Draw(TimeSpan gameTime) { this.position.X = this.Transform2D.X; this.position.Y = this.Transform2D.Y; this.scale.X = this.Transform2D.XScale; this.scale.Y = this.Transform2D.YScale; if (this.viewportManager.IsActivated) { this.viewportManager.Translate(ref this.position, ref this.scale); } Quaternion.CreateFromYawPitchRoll(0, 0, this.Transform2D.Rotation, out this.orientation); Matrix.CreateFromQuaternion(ref this.orientation, out this.quaternionMatrix); this.internalScale.X = this.scale.X; this.internalScale.Y = this.scale.Y; Matrix.CreateScale(ref this.internalScale, out this.scaleMatrix); this.internalPosition.X = this.position.X - (this.Transform2D.Origin.X * this.Transform2D.Rectangle.Width); this.internalPosition.Y = this.position.Y - (this.Transform2D.Origin.Y * this.Transform2D.Rectangle.Height); Matrix.CreateTranslation(ref this.internalPosition, out this.translationMatrix); Matrix.Multiply(ref this.scaleMatrix, ref this.quaternionMatrix, out this.localWorld); Matrix.Multiply(ref this.localWorld, ref this.translationMatrix, out this.localWorld); float opacity = this.RenderManager.DebugLines ? this.DebugAlpha : this.Transform2D.Opacity; int numVertices = 0; int numPrimitives = 0; // Process Mesh for (int i = 0; i < this.drawOrder.Count; i++) { Slot slot = this.drawOrder[i]; Attachment attachment = slot.Attachment; float alpha = this.SkeletalAnimation.Skeleton.A * slot.A * opacity; byte r = (byte)(this.SkeletalAnimation.Skeleton.R * slot.R * 255 * alpha); byte g = (byte)(this.SkeletalAnimation.Skeleton.G * slot.G * 255 * alpha); byte b = (byte)(this.SkeletalAnimation.Skeleton.B * slot.B * 255 * alpha); byte a = (byte)(alpha * 255); Color color = new Color(r, g, b, a); if (attachment is RegionAttachment) { RegionAttachment regionAttachment = attachment as RegionAttachment; float[] spineVertices = new float[8]; float[] uvs = regionAttachment.UVs; AtlasRegion region = (AtlasRegion)regionAttachment.RendererObject; this.material.Texture = (Texture2D)region.page.rendererObject; regionAttachment.ComputeWorldVertices(0, 0, slot.Bone, spineVertices); this.vertices = new VertexPositionColorTexture[4]; // Vertex TL this.tempVertice.Position.X = spineVertices[RegionAttachment.X1]; this.tempVertice.Position.Y = -spineVertices[RegionAttachment.Y1]; this.tempVertice.Position.Z = 0; this.tempVertice.Color = color; this.tempVertice.TexCoord.X = uvs[RegionAttachment.X1]; this.tempVertice.TexCoord.Y = uvs[RegionAttachment.Y1]; this.vertices[0] = this.tempVertice; // Vertex TR this.tempVertice.Position.X = spineVertices[RegionAttachment.X4]; this.tempVertice.Position.Y = -spineVertices[RegionAttachment.Y4]; this.tempVertice.Position.Z = 0; this.tempVertice.Color = color; this.tempVertice.TexCoord.X = uvs[RegionAttachment.X4]; this.tempVertice.TexCoord.Y = uvs[RegionAttachment.Y4]; this.vertices[1] = this.tempVertice; // Vertex BR this.tempVertice.Position.X = spineVertices[RegionAttachment.X3]; this.tempVertice.Position.Y = -spineVertices[RegionAttachment.Y3]; this.tempVertice.Position.Z = 0; this.tempVertice.Color = color; this.tempVertice.TexCoord.X = uvs[RegionAttachment.X3]; this.tempVertice.TexCoord.Y = uvs[RegionAttachment.Y3]; this.vertices[2] = this.tempVertice; // Vertex BL this.tempVertice.Position.X = spineVertices[RegionAttachment.X2]; this.tempVertice.Position.Y = -spineVertices[RegionAttachment.Y2]; this.tempVertice.Position.Z = 0; this.tempVertice.Color = color; this.tempVertice.TexCoord.X = uvs[RegionAttachment.X2]; this.tempVertice.TexCoord.Y = uvs[RegionAttachment.Y2]; this.vertices[3] = this.tempVertice; numVertices = 4; numPrimitives = 2; this.indices = quadIndices; } else if (attachment is MeshAttachment) { MeshAttachment mesh = (MeshAttachment)attachment; numVertices = mesh.Vertices.Length; numPrimitives = numVertices / 2; indices = CopyIndices(mesh.Triangles); float[] spineVertices = new float[numVertices]; mesh.ComputeWorldVertices(0, 0, slot, spineVertices); AtlasRegion region = (AtlasRegion)mesh.RendererObject; this.material.Texture = (Texture2D)region.page.rendererObject; this.vertices = new VertexPositionColorTexture[numVertices / 2]; float[] uvs = mesh.UVs; for (int v = 0, j = 0; v < numVertices; v += 2, j++) { this.tempVertice.Color = color; this.tempVertice.Position.X = spineVertices[v]; this.tempVertice.Position.Y = -spineVertices[v + 1]; this.tempVertice.Position.Z = 0; this.tempVertice.TexCoord.X = uvs[v]; this.tempVertice.TexCoord.Y = uvs[v + 1]; this.vertices[j] = this.tempVertice; } } else if (attachment is SkinnedMeshAttachment) { SkinnedMeshAttachment mesh = (SkinnedMeshAttachment)attachment; numVertices = mesh.UVs.Length; numPrimitives = numVertices / 2; indices = CopyIndices(mesh.Triangles); float[] spineVertices = new float[numVertices]; mesh.ComputeWorldVertices(0, 0, slot, spineVertices); AtlasRegion region = (AtlasRegion)mesh.RendererObject; this.material.Texture = (Texture2D)region.page.rendererObject; this.vertices = new VertexPositionColorTexture[numVertices / 2]; float[] uvs = mesh.UVs; for (int v = 0, j = 0; v < numVertices; v += 2, j++) { this.tempVertice.Color = color; this.tempVertice.Position.X = spineVertices[v]; this.tempVertice.Position.Y = -spineVertices[v + 1]; this.tempVertice.Position.Z = 0; this.tempVertice.TexCoord.X = uvs[v]; this.tempVertice.TexCoord.Y = uvs[v + 1]; this.vertices[j] = this.tempVertice; } } if (attachment != null) { bool reset = false; if (this.spineMeshes[i] != null) { if (this.spineMeshes[i].VertexBuffer.VertexCount != vertices.Length || this.spineMeshes[i].IndexBuffer.Data.Length != indices.Length) { Mesh toDispose = this.spineMeshes[i]; this.GraphicsDevice.DestroyIndexBuffer(toDispose.IndexBuffer); this.GraphicsDevice.DestroyVertexBuffer(toDispose.VertexBuffer); reset = true; } } if (this.spineMeshes[i] == null || reset) { Mesh newMesh = new Mesh( 0, numVertices, 0, numPrimitives, new DynamicVertexBuffer(VertexPositionColorTexture.VertexFormat), new DynamicIndexBuffer(indices), PrimitiveType.TriangleList); this.spineMeshes[i] = newMesh; } Mesh mesh = this.spineMeshes[i]; mesh.IndexBuffer.SetData(this.indices); this.GraphicsDevice.BindIndexBuffer(mesh.IndexBuffer); mesh.VertexBuffer.SetData(this.vertices); this.GraphicsDevice.BindVertexBuffer(mesh.VertexBuffer); mesh.ZOrder = this.Transform2D.DrawOrder; this.RenderManager.DrawMesh(mesh, this.material, ref this.localWorld, false); } } }
public virtual void LateUpdate() { if (!valid) { return; } // Exit early if there is nothing to render if (!meshRenderer.enabled && submeshRenderers.Length == 0) { return; } // Count vertices and submesh triangles. int vertexCount = 0; int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0; Material lastMaterial = null; ExposedList <Slot> drawOrder = skeleton.drawOrder; int drawOrderCount = drawOrder.Count; int submeshSeparatorSlotsCount = submeshSeparatorSlots.Count; bool renderMeshes = this.renderMeshes; // Clear last state of attachments and submeshes ExposedList <int> attachmentsTriangleCountTemp = lastState.attachmentsTriangleCountTemp; attachmentsTriangleCountTemp.GrowIfNeeded(drawOrderCount); attachmentsTriangleCountTemp.Count = drawOrderCount; ExposedList <bool> attachmentsFlipStateTemp = lastState.attachmentsFlipStateTemp; attachmentsFlipStateTemp.GrowIfNeeded(drawOrderCount); attachmentsFlipStateTemp.Count = drawOrderCount; ExposedList <LastState.AddSubmeshArguments> addSubmeshArgumentsTemp = lastState.addSubmeshArgumentsTemp; addSubmeshArgumentsTemp.Clear(false); bool noRender = false; for (int i = 0; i < drawOrderCount; i++) { Slot slot = drawOrder.Items[i]; Bone bone = slot.bone; Attachment attachment = slot.attachment; object rendererObject; 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); attachmentsFlipStateTemp.Items[i] = flip; attachmentsTriangleCountTemp.Items[i] = -1; RegionAttachment regionAttachment = attachment as RegionAttachment; if (regionAttachment != null) { rendererObject = regionAttachment.RendererObject; attachmentVertexCount = 4; attachmentTriangleCount = 6; } else { if (!renderMeshes) { continue; } MeshAttachment meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { rendererObject = meshAttachment.RendererObject; attachmentVertexCount = meshAttachment.vertices.Length >> 1; attachmentTriangleCount = meshAttachment.triangles.Length; } else { SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment; if (skinnedMeshAttachment != null) { rendererObject = skinnedMeshAttachment.RendererObject; attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1; attachmentTriangleCount = skinnedMeshAttachment.triangles.Length; } else { continue; } } } // Populate submesh when material changes. // tsteil - added support for mask material Material material = null; if (useMaskMaterial) { if (maskProvider != null) { if (maskMaterial == null) { var prefabMat = (Material)((AtlasRegion)rendererObject).page.rendererObjectMask; material = new Material(prefabMat); material.hideFlags = HideFlags.HideAndDontSave; maskMaterial = material; SetMaskId(); } else { material = maskMaterial; } } else { material = (Material)((AtlasRegion)rendererObject).page.rendererObjectMask; } } else { #if !SPINE_TK2D material = (Material)((AtlasRegion)rendererObject).page.rendererObject; #else material = (rendererObject.GetType() == typeof(Material)) ? (Material)rendererObject : (Material)((AtlasRegion)rendererObject).page.rendererObject; #endif } if ((lastMaterial != null && lastMaterial.GetInstanceID() != material.GetInstanceID()) || (submeshSeparatorSlotsCount > 0 && submeshSeparatorSlots.Contains(slot))) { addSubmeshArgumentsTemp.Add( new LastState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false) ); submeshTriangleCount = 0; submeshFirstVertex = vertexCount; submeshStartSlotIndex = i; } lastMaterial = material; submeshTriangleCount += attachmentTriangleCount; vertexCount += attachmentVertexCount; attachmentsTriangleCountTemp.Items[i] = attachmentTriangleCount; } // tsteil - we need to keep track if we're rendering or not if (lastMaterial == null) { noRender = true; } addSubmeshArgumentsTemp.Add( new LastState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true) ); bool mustUpdateMeshStructure = CheckIfMustUpdateMeshStructure(attachmentsTriangleCountTemp, attachmentsFlipStateTemp, addSubmeshArgumentsTemp); var submeshMatCount = 0; if (mustUpdateMeshStructure) { submeshMaterials.Clear(); for (int i = 0, n = addSubmeshArgumentsTemp.Count; i < n; i++) { LastState.AddSubmeshArguments arguments = addSubmeshArgumentsTemp.Items[i]; AddSubmesh( arguments.material, arguments.startSlot, arguments.endSlot, arguments.triangleCount, arguments.firstVertex, arguments.lastSubmesh, attachmentsFlipStateTemp ); } // Set materials. submeshMatCount = submeshMaterials.Count; if (submeshMatCount == 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]; if (setupUv2) { this.uvs2 = new Vector2[vertexCount]; } mesh1.Clear(); mesh2.Clear(); } else { // Too many vertices, zero the extra. Vector3 zero = Vector3.zero; for (int i = vertexCount, n = lastState.vertexCount; i < n; i++) { vertices[i] = zero; } } lastState.vertexCount = vertexCount; // Setup mesh. float zSpacing = this.zSpacing; float[] tempVertices = this.tempVertices; Vector2[] uvs = this.uvs; Vector2[] uvs2 = this.uvs2; Color32[] colors = this.colors; int vertexIndex = 0; Color32 color; float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b; Vector3 meshBoundsMin; meshBoundsMin.x = float.MaxValue; meshBoundsMin.y = float.MaxValue; meshBoundsMin.z = zSpacing > 0f ? 0f : zSpacing * (drawOrderCount - 1); Vector3 meshBoundsMax; meshBoundsMax.x = float.MinValue; meshBoundsMax.y = float.MinValue; meshBoundsMax.z = zSpacing < 0f ? 0f : zSpacing * (drawOrderCount - 1); for (int i = 0; i < drawOrderCount; i++) { Slot slot = drawOrder.Items[i]; Attachment attachment = slot.attachment; RegionAttachment regionAttachment = attachment as RegionAttachment; if (regionAttachment != null) { regionAttachment.ComputeWorldVertices(slot.bone, tempVertices); float z = i * zSpacing; vertices[vertexIndex].x = tempVertices[RegionAttachment.X1]; vertices[vertexIndex].y = tempVertices[RegionAttachment.Y1]; vertices[vertexIndex].z = z; vertices[vertexIndex + 1].x = tempVertices[RegionAttachment.X4]; vertices[vertexIndex + 1].y = tempVertices[RegionAttachment.Y4]; vertices[vertexIndex + 1].z = z; vertices[vertexIndex + 2].x = tempVertices[RegionAttachment.X2]; vertices[vertexIndex + 2].y = tempVertices[RegionAttachment.Y2]; vertices[vertexIndex + 2].z = z; vertices[vertexIndex + 3].x = tempVertices[RegionAttachment.X3]; vertices[vertexIndex + 3].y = tempVertices[RegionAttachment.Y3]; vertices[vertexIndex + 3].z = z; // Eugene - added if (overrideVertexColor) { color = vertexColor; colors[vertexIndex] = color; colors[vertexIndex + 1] = color; colors[vertexIndex + 2] = color; colors[vertexIndex + 3] = color; } else { color.a = (byte)(a * slot.a * regionAttachment.a); color.r = (byte)(r * slot.r * regionAttachment.r * color.a); color.g = (byte)(g * slot.g * regionAttachment.g * color.a); color.b = (byte)(b * slot.b * regionAttachment.b * color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } colors[vertexIndex] = color; colors[vertexIndex + 1] = color; colors[vertexIndex + 2] = color; colors[vertexIndex + 3] = color; } float[] regionUVs = regionAttachment.uvs; uvs[vertexIndex].x = regionUVs[RegionAttachment.X1]; uvs[vertexIndex].y = regionUVs[RegionAttachment.Y1]; uvs[vertexIndex + 1].x = regionUVs[RegionAttachment.X4]; uvs[vertexIndex + 1].y = regionUVs[RegionAttachment.Y4]; uvs[vertexIndex + 2].x = regionUVs[RegionAttachment.X2]; uvs[vertexIndex + 2].y = regionUVs[RegionAttachment.Y2]; uvs[vertexIndex + 3].x = regionUVs[RegionAttachment.X3]; uvs[vertexIndex + 3].y = regionUVs[RegionAttachment.Y3]; // Calculate min/max X if (tempVertices[RegionAttachment.X1] < meshBoundsMin.x) { meshBoundsMin.x = tempVertices[RegionAttachment.X1]; } else if (tempVertices[RegionAttachment.X1] > meshBoundsMax.x) { meshBoundsMax.x = tempVertices[RegionAttachment.X1]; } if (tempVertices[RegionAttachment.X2] < meshBoundsMin.x) { meshBoundsMin.x = tempVertices[RegionAttachment.X2]; } else if (tempVertices[RegionAttachment.X2] > meshBoundsMax.x) { meshBoundsMax.x = tempVertices[RegionAttachment.X2]; } if (tempVertices[RegionAttachment.X3] < meshBoundsMin.x) { meshBoundsMin.x = tempVertices[RegionAttachment.X3]; } else if (tempVertices[RegionAttachment.X3] > meshBoundsMax.x) { meshBoundsMax.x = tempVertices[RegionAttachment.X3]; } if (tempVertices[RegionAttachment.X4] < meshBoundsMin.x) { meshBoundsMin.x = tempVertices[RegionAttachment.X4]; } else if (tempVertices[RegionAttachment.X4] > meshBoundsMax.x) { meshBoundsMax.x = tempVertices[RegionAttachment.X4]; } // Calculate min/max Y if (tempVertices[RegionAttachment.Y1] < meshBoundsMin.y) { meshBoundsMin.y = tempVertices[RegionAttachment.Y1]; } else if (tempVertices[RegionAttachment.Y1] > meshBoundsMax.y) { meshBoundsMax.y = tempVertices[RegionAttachment.Y1]; } if (tempVertices[RegionAttachment.Y2] < meshBoundsMin.y) { meshBoundsMin.y = tempVertices[RegionAttachment.Y2]; } else if (tempVertices[RegionAttachment.Y2] > meshBoundsMax.y) { meshBoundsMax.y = tempVertices[RegionAttachment.Y2]; } if (tempVertices[RegionAttachment.Y3] < meshBoundsMin.y) { meshBoundsMin.y = tempVertices[RegionAttachment.Y3]; } else if (tempVertices[RegionAttachment.Y3] > meshBoundsMax.y) { meshBoundsMax.y = tempVertices[RegionAttachment.Y3]; } if (tempVertices[RegionAttachment.Y4] < meshBoundsMin.y) { meshBoundsMin.y = tempVertices[RegionAttachment.Y4]; } else if (tempVertices[RegionAttachment.Y4] > meshBoundsMax.y) { meshBoundsMax.y = tempVertices[RegionAttachment.Y4]; } vertexIndex += 4; } else { if (!renderMeshes) { continue; } MeshAttachment meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { int meshVertexCount = meshAttachment.vertices.Length; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } meshAttachment.ComputeWorldVertices(slot, tempVertices); // Eugene - added if (overrideVertexColor) { color = vertexColor; } else { color.a = (byte)(a * slot.a * meshAttachment.a); color.r = (byte)(r * slot.r * meshAttachment.r * color.a); color.g = (byte)(g * slot.g * meshAttachment.g * color.a); color.b = (byte)(b * slot.b * meshAttachment.b * color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } } float[] meshUVs = meshAttachment.uvs; float z = i * zSpacing; for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { vertices[vertexIndex].x = tempVertices[ii]; vertices[vertexIndex].y = tempVertices[ii + 1]; vertices[vertexIndex].z = z; colors[vertexIndex] = color; uvs[vertexIndex].x = meshUVs[ii]; uvs[vertexIndex].y = meshUVs[ii + 1]; if (tempVertices[ii] < meshBoundsMin.x) { meshBoundsMin.x = tempVertices[ii]; } else if (tempVertices[ii] > meshBoundsMax.x) { meshBoundsMax.x = tempVertices[ii]; } if (tempVertices[ii + 1] < meshBoundsMin.y) { meshBoundsMin.y = tempVertices[ii + 1]; } else if (tempVertices[ii + 1] > meshBoundsMax.y) { meshBoundsMax.y = tempVertices[ii + 1]; } } } else { SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment; if (skinnedMeshAttachment != null) { int meshVertexCount = skinnedMeshAttachment.uvs.Length; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } skinnedMeshAttachment.ComputeWorldVertices(slot, tempVertices); // Eugene - added if (overrideVertexColor) { color = vertexColor; } else { color.a = (byte)(a * slot.a * skinnedMeshAttachment.a); color.r = (byte)(r * slot.r * skinnedMeshAttachment.r * color.a); color.g = (byte)(g * slot.g * skinnedMeshAttachment.g * color.a); color.b = (byte)(b * slot.b * skinnedMeshAttachment.b * color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } } float[] meshUVs = skinnedMeshAttachment.uvs; float z = i * zSpacing; for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { vertices[vertexIndex].x = tempVertices[ii]; vertices[vertexIndex].y = tempVertices[ii + 1]; vertices[vertexIndex].z = z; colors[vertexIndex] = color; uvs[vertexIndex].x = meshUVs[ii]; uvs[vertexIndex].y = meshUVs[ii + 1]; if (tempVertices[ii] < meshBoundsMin.x) { meshBoundsMin.x = tempVertices[ii]; } else if (tempVertices[ii] > meshBoundsMax.x) { meshBoundsMax.x = tempVertices[ii]; } if (tempVertices[ii + 1] < meshBoundsMin.y) { meshBoundsMin.y = tempVertices[ii + 1]; } else if (tempVertices[ii + 1] > meshBoundsMax.y) { meshBoundsMax.y = tempVertices[ii + 1]; } } } } } } // Double buffer mesh. Mesh mesh = useMesh1 ? mesh1 : mesh2; meshFilter.sharedMesh = mesh; mesh.vertices = vertices; mesh.colors32 = colors; mesh.uv = uvs; // tsteil - added UV2 stuff if (setupUv2) { float minX = 1f; float minY = 1f; float maxX = 0f; float maxY = 0f; float sizeX = 0f; float sizeY = 0f; // go through our vertices and find the min and max so we can normalize the UVs against it for (int i = 0; i < vertexCount; ++i) { var x = vertices[i].x; var y = vertices[i].y; if (x < minX) { minX = x; } else if (x > maxX) { maxX = x; } if (y < minY) { minY = y; } else if (y > maxY) { maxY = y; } } sizeX = maxX - minX; sizeY = maxY - minY; // now set the uvs2 for (int i = 0; i < vertexCount; ++i) { uvs2[i].x = (vertices[i].x - minX) / sizeX; uvs2[i].y = (vertices[i].y - minY) / sizeY; } mesh.uv2 = uvs2; } if (mustUpdateMeshStructure) { int submeshCount = submeshMatCount; mesh.subMeshCount = submeshCount; for (int i = 0; i < submeshCount; ++i) { mesh.SetTriangles(submeshes.Items[i].triangles, i); } } // tsteil: if we're not rendering, we dont need to calculate the bounds (this fixes the crazy AABB math errors) if (noRender == false) { Vector3 meshBoundsExtents = meshBoundsMax - meshBoundsMin; Vector3 meshBoundsCenter = meshBoundsMin + meshBoundsExtents * 0.5f; mesh.bounds = new Bounds(meshBoundsCenter, meshBoundsExtents); } 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; } } // Update previous state ExposedList <int> attachmentsTriangleCountCurrentMesh; ExposedList <bool> attachmentsFlipStateCurrentMesh; ExposedList <LastState.AddSubmeshArguments> addSubmeshArgumentsCurrentMesh; if (useMesh1) { attachmentsTriangleCountCurrentMesh = lastState.attachmentsTriangleCountMesh1; addSubmeshArgumentsCurrentMesh = lastState.addSubmeshArgumentsMesh1; attachmentsFlipStateCurrentMesh = lastState.attachmentsFlipStateMesh1; lastState.immutableTrianglesMesh1 = immutableTriangles; } else { attachmentsTriangleCountCurrentMesh = lastState.attachmentsTriangleCountMesh2; addSubmeshArgumentsCurrentMesh = lastState.addSubmeshArgumentsMesh2; attachmentsFlipStateCurrentMesh = lastState.attachmentsFlipStateMesh2; lastState.immutableTrianglesMesh2 = immutableTriangles; } attachmentsTriangleCountCurrentMesh.GrowIfNeeded(attachmentsTriangleCountTemp.Capacity); attachmentsTriangleCountCurrentMesh.Count = attachmentsTriangleCountTemp.Count; attachmentsTriangleCountTemp.CopyTo(attachmentsTriangleCountCurrentMesh.Items, 0); attachmentsFlipStateCurrentMesh.GrowIfNeeded(attachmentsFlipStateTemp.Capacity); attachmentsFlipStateCurrentMesh.Count = attachmentsFlipStateTemp.Count; attachmentsFlipStateTemp.CopyTo(attachmentsFlipStateCurrentMesh.Items, 0); addSubmeshArgumentsCurrentMesh.GrowIfNeeded(addSubmeshArgumentsTemp.Count); addSubmeshArgumentsCurrentMesh.Count = addSubmeshArgumentsTemp.Count; addSubmeshArgumentsTemp.CopyTo(addSubmeshArgumentsCurrentMesh.Items); if (submeshRenderers.Length > 0) { for (int i = 0; i < submeshRenderers.Length; i++) { SkeletonUtilitySubmeshRenderer submeshRenderer = submeshRenderers[i]; if (submeshRenderer.submeshIndex < sharedMaterials.Length) { submeshRenderer.SetMesh(meshRenderer, useMesh1 ? mesh1 : mesh2, sharedMaterials[submeshRenderer.submeshIndex]); } else { submeshRenderer.GetComponent <Renderer>().enabled = false; } } } useMesh1 = !useMesh1; }
protected override void Draw() { defaultBlendState = PremultipliedAlpha ? BlendState.AlphaBlend : BlendState.NonPremultiplied; float[] vertices = this.vertices; List <Slot> drawOrder = Skeleton.DrawOrder; float x = Skeleton.X, y = Skeleton.Y; CCColor3B color3b = Color; float skeletonR = color3b.R / 255f; float skeletonG = color3b.G / 255f; float skeletonB = color3b.B / 255f; float skeletonA = Opacity / 255f; batcher.BlendState = defaultBlendState; batcher.Begin(); for (int i = 0, n = drawOrder.Count; i < n; i++) { Slot slot = drawOrder[i]; Attachment attachment = slot.Attachment; if (attachment is RegionAttachment) { RegionAttachment regionAttachment = (RegionAttachment)attachment; BlendState blend = slot.Data.AdditiveBlending ? BlendState.Additive : defaultBlendState; //batcher.BlendState = blend; if (CCDrawManager.GraphicsDevice.BlendState != blend) { batcher.End(); batcher.BlendState = blend; batcher.Begin(); } MeshItem item = batcher.NextItem(4, 6); item.triangles = quadTriangles; VertexPositionColorTexture[] itemVertices = item.vertices; AtlasRegion region = (AtlasRegion)regionAttachment.RendererObject; item.texture = (Texture2D)region.page.rendererObject; Color color; float a = skeletonA * slot.A * regionAttachment.A; if (PremultipliedAlpha) { color = new Color( skeletonR * slot.R * regionAttachment.R * a, skeletonG * slot.G * regionAttachment.G * a, skeletonB * slot.B * regionAttachment.B * a, a); } else { color = new Color( skeletonR * slot.R * regionAttachment.R, skeletonG * slot.G * regionAttachment.G, skeletonB * slot.B * regionAttachment.B, a); } itemVertices[TL].Color = color; itemVertices[BL].Color = color; itemVertices[BR].Color = color; itemVertices[TR].Color = color; regionAttachment.ComputeWorldVertices(x, y, slot.Bone, vertices); itemVertices[TL].Position.X = vertices[RegionAttachment.X1]; itemVertices[TL].Position.Y = vertices[RegionAttachment.Y1]; itemVertices[TL].Position.Z = 0; itemVertices[BL].Position.X = vertices[RegionAttachment.X2]; itemVertices[BL].Position.Y = vertices[RegionAttachment.Y2]; itemVertices[BL].Position.Z = 0; itemVertices[BR].Position.X = vertices[RegionAttachment.X3]; itemVertices[BR].Position.Y = vertices[RegionAttachment.Y3]; itemVertices[BR].Position.Z = 0; itemVertices[TR].Position.X = vertices[RegionAttachment.X4]; itemVertices[TR].Position.Y = vertices[RegionAttachment.Y4]; itemVertices[TR].Position.Z = 0; float[] uvs = regionAttachment.UVs; itemVertices[TL].TextureCoordinate.X = uvs[RegionAttachment.X1]; itemVertices[TL].TextureCoordinate.Y = uvs[RegionAttachment.Y1]; itemVertices[BL].TextureCoordinate.X = uvs[RegionAttachment.X2]; itemVertices[BL].TextureCoordinate.Y = uvs[RegionAttachment.Y2]; itemVertices[BR].TextureCoordinate.X = uvs[RegionAttachment.X3]; itemVertices[BR].TextureCoordinate.Y = uvs[RegionAttachment.Y3]; itemVertices[TR].TextureCoordinate.X = uvs[RegionAttachment.X4]; itemVertices[TR].TextureCoordinate.Y = uvs[RegionAttachment.Y4]; } else if (attachment is MeshAttachment) { MeshAttachment mesh = (MeshAttachment)attachment; int vertexCount = mesh.Vertices.Length; if (vertices.Length < vertexCount) { vertices = new float[vertexCount]; } mesh.ComputeWorldVertices(x, y, slot, vertices); int[] triangles = mesh.Triangles; MeshItem item = batcher.NextItem(vertexCount, triangles.Length); item.triangles = triangles; AtlasRegion region = (AtlasRegion)mesh.RendererObject; item.texture = (Texture2D)region.page.rendererObject; Color color; float a = skeletonA * slot.A * mesh.A; if (PremultipliedAlpha) { color = new Color( skeletonR * slot.R * mesh.R * a, skeletonG * slot.G * mesh.G * a, skeletonB * slot.B * mesh.B * a, a); } else { color = new Color( skeletonR * slot.R * mesh.R, skeletonG * slot.G * mesh.G, skeletonB * slot.B * mesh.B, a); } float[] uvs = mesh.UVs; VertexPositionColorTexture[] itemVertices = item.vertices; for (int ii = 0, v = 0; v < vertexCount; ii++, v += 2) { itemVertices[ii].Color = color; itemVertices[ii].Position.X = vertices[v]; itemVertices[ii].Position.Y = vertices[v + 1]; itemVertices[ii].Position.Z = 0; itemVertices[ii].TextureCoordinate.X = uvs[v]; itemVertices[ii].TextureCoordinate.Y = uvs[v + 1]; } } else if (attachment is SkinnedMeshAttachment) { SkinnedMeshAttachment mesh = (SkinnedMeshAttachment)attachment; int vertexCount = mesh.UVs.Length; if (vertices.Length < vertexCount) { vertices = new float[vertexCount]; } mesh.ComputeWorldVertices(x, y, slot, vertices); int[] triangles = mesh.Triangles; MeshItem item = batcher.NextItem(vertexCount, triangles.Length); item.triangles = triangles; AtlasRegion region = (AtlasRegion)mesh.RendererObject; item.texture = (Texture2D)region.page.rendererObject; Color color; float a = skeletonA * slot.A * mesh.A; if (PremultipliedAlpha) { color = new Color( skeletonR * slot.R * mesh.R * a, skeletonG * slot.G * mesh.G * a, skeletonB * slot.B * mesh.B * a, a); } else { color = new Color( skeletonR * slot.R * mesh.R, skeletonG * slot.G * mesh.G, skeletonB * slot.B * mesh.B, a); } float[] uvs = mesh.UVs; VertexPositionColorTexture[] itemVertices = item.vertices; for (int ii = 0, v = 0; v < vertexCount; ii++, v += 2) { itemVertices[ii].Color = color; itemVertices[ii].Position.X = vertices[v]; itemVertices[ii].Position.Y = vertices[v + 1]; itemVertices[ii].Position.Z = 0; itemVertices[ii].TextureCoordinate.X = uvs[v]; itemVertices[ii].TextureCoordinate.Y = uvs[v + 1]; } } } batcher.End(); if (DebugBones || DebugSlots) { if (DebugSlots) { for (int i = 0; i < Skeleton.Slots.Count; ++i) { var slot = Skeleton.Slots[i]; if (slot.Attachment == null) { continue; } var verticesCount = 0; var worldVertices = new float[1000]; // Max number of vertices per mesh. if (slot.Attachment is RegionAttachment) { var attachment = (RegionAttachment)slot.Attachment; attachment.ComputeWorldVertices(Skeleton.X, Skeleton.Y, slot.bone, worldVertices); verticesCount = 8; } else if (slot.Attachment is MeshAttachment) { var mesh = (MeshAttachment)slot.Attachment; mesh.ComputeWorldVertices(Skeleton.X, Skeleton.Y, slot, worldVertices); verticesCount = mesh.Vertices.Length; } else if (slot.Attachment is SkinnedMeshAttachment) { var mesh = (SkinnedMeshAttachment)slot.Attachment; mesh.ComputeWorldVertices(Skeleton.X, Skeleton.Y, slot, worldVertices); verticesCount = mesh.UVs.Length; } else { continue; } CCPoint[] slotVertices = new CCPoint[verticesCount / 2]; for (int ii = 0, si = 0; ii < verticesCount; ii += 2, si++) { slotVertices[si].X = worldVertices[ii] * ScaleX; slotVertices[si].Y = worldVertices[ii + 1] * ScaleY; } CCDrawingPrimitives.Begin(); CCDrawingPrimitives.DrawPoly(slotVertices, verticesCount / 2, true, DebugSlotColor); CCDrawingPrimitives.End(); } } if (DebugBones) { // Bone lengths. for (int i = 0; i < Skeleton.Bones.Count; i++) { Bone bone = Skeleton.Bones[i]; x = bone.Data.Length * bone.M00 + bone.WorldX; y = bone.Data.Length * bone.M10 + bone.WorldY; CCDrawingPrimitives.Begin(); CCDrawingPrimitives.DrawLine(new CCPoint(bone.WorldX, bone.WorldY), new CCPoint(x, y), DebugJointColor); CCDrawingPrimitives.End(); } // Bone origins. for (int i = 0; i < Skeleton.Bones.Count; i++) { Bone bone = Skeleton.Bones[i]; CCDrawingPrimitives.Begin(); CCDrawingPrimitives.DrawPoint(new CCPoint(bone.WorldX, bone.WorldY), 4, DebugBoneColor); CCDrawingPrimitives.End(); } } } }
private void InternalDraw(Skeleton pSkeleton, Texture2D[] pTextureArray, float pDepth, float scale, Color pColor) { if (!isBegin) { throw new Exception("Beginn muss vor Draw aufgerufen werden!"); } float[] vertices = this.mSkeletonVertecies; List <Slot> drawOrder = pSkeleton.DrawOrder; float x = pSkeleton.X, y = pSkeleton.Y; int textId = this.mBatch.AddTextures(pTextureArray); for (int i = 0, n = drawOrder.Count; i < n; i++) { Slot slot = drawOrder[i]; Attachment attachment = slot.Attachment; if (attachment is RegionAttachment) { RegionAttachment regionAttachment = (RegionAttachment)attachment; MeshData item = this.mBatch.NextItem(4, 6); item.triangles = quadIndecies; AtlasRegion region = (AtlasRegion)regionAttachment.RendererObject; regionAttachment.ComputeWorldVertices(x, y, slot.Bone, vertices); item.vertices[TL].Position.X = vertices[RegionAttachment.X1]; item.vertices[TL].Position.Y = vertices[RegionAttachment.Y1]; item.vertices[TL].Position.Z = pDepth; // -orderDepth * (n - (i + 1)); item.vertices[BL].Position.X = vertices[RegionAttachment.X2]; item.vertices[BL].Position.Y = vertices[RegionAttachment.Y2]; item.vertices[BL].Position.Z = pDepth;// -orderDepth * (n - (i + 1)); item.vertices[BR].Position.X = vertices[RegionAttachment.X3]; item.vertices[BR].Position.Y = vertices[RegionAttachment.Y3]; item.vertices[BR].Position.Z = pDepth;// -orderDepth * (n - (i + 1)); item.vertices[TR].Position.X = vertices[RegionAttachment.X4]; item.vertices[TR].Position.Y = vertices[RegionAttachment.Y4]; item.vertices[TR].Position.Z = pDepth;// -orderDepth * (n - (i + 1)); float[] uvs = regionAttachment.UVs; item.vertices[TL].TextureCoordinate.X = uvs[RegionAttachment.X1]; item.vertices[TL].TextureCoordinate.Y = uvs[RegionAttachment.Y1]; item.vertices[BL].TextureCoordinate.X = uvs[RegionAttachment.X2]; item.vertices[BL].TextureCoordinate.Y = uvs[RegionAttachment.Y2]; item.vertices[BR].TextureCoordinate.X = uvs[RegionAttachment.X3]; item.vertices[BR].TextureCoordinate.Y = uvs[RegionAttachment.Y3]; item.vertices[TR].TextureCoordinate.X = uvs[RegionAttachment.X4]; item.vertices[TR].TextureCoordinate.Y = uvs[RegionAttachment.Y4]; item.vertices[TL].Color = pColor; item.vertices[BL].Color = pColor; item.vertices[BR].Color = pColor; item.vertices[TR].Color = pColor; item.TextureID = textId; } else if (attachment is MeshAttachment) { MeshAttachment mesh = (MeshAttachment)attachment; int vertexCount = mesh.Vertices.Length; if (vertices.Length < vertexCount) { vertices = new float[vertexCount]; } mesh.ComputeWorldVertices(x, y, slot, vertices); int[] triangles = mesh.triangles; MeshData item = mBatch.NextItem(vertexCount, triangles.Length); item.triangles = triangles; item.TextureID = textId; AtlasRegion region = (AtlasRegion)mesh.RendererObject; float[] uvs = mesh.UVs; VertexPositionColorTexture[] itemVertices = item.vertices; for (int ii = 0, v = 0; v < vertexCount; ii++, v += 2) { itemVertices[ii].Position.X = vertices[v]; itemVertices[ii].Position.Y = vertices[v + 1]; itemVertices[ii].Position.Z = pDepth; itemVertices[ii].TextureCoordinate.X = uvs[v]; itemVertices[ii].TextureCoordinate.Y = uvs[v + 1]; itemVertices[ii].Color = pColor; } } else if (attachment is SkinnedMeshAttachment) { SkinnedMeshAttachment mesh = (SkinnedMeshAttachment)attachment; int vertexCount = mesh.UVs.Length; if (vertices.Length < vertexCount) { vertices = new float[vertexCount]; } mesh.ComputeWorldVertices(x, y, slot, vertices); int[] triangles = mesh.Triangles; MeshData item = mBatch.NextItem(vertexCount, triangles.Length); item.triangles = triangles; item.TextureID = textId; float[] uvs = mesh.UVs; VertexPositionColorTexture[] itemVertices = item.vertices; for (int ii = 0, v = 0; v < vertexCount; ii++, v += 2) { itemVertices[ii].Position.X = vertices[v]; itemVertices[ii].Position.Y = vertices[v + 1]; itemVertices[ii].Position.Z = 0; itemVertices[ii].TextureCoordinate.X = uvs[v]; itemVertices[ii].TextureCoordinate.Y = uvs[v + 1]; itemVertices[ii].Color = pColor; } } } }