/// <summary> Sets the scale. Call regionAttachment.UpdateOffset to apply the change.</summary> public static void SetScale(this RegionAttachment regionAttachment, Vector2 scale) { regionAttachment.scaleX = scale.x; regionAttachment.scaleY = scale.y; }
/// <summary> Sets the position offset. Call regionAttachment.UpdateOffset to apply the change.</summary> public static void SetPositionOffset(this RegionAttachment regionAttachment, Vector2 offset) { regionAttachment.x = offset.x; regionAttachment.y = offset.y; }
public RegionAttachment NewRegionAttachment(Skin skin, string name, string path) { RegionAttachment attachment = new RegionAttachment(name); Texture2D tex = sprite.texture; int instanceId = tex.GetInstanceID(); AtlasRegion atlasRegion; //check cache first if (atlasTable.ContainsKey(instanceId)) { atlasRegion = atlasTable[instanceId]; } else { //Setup new material Material mat = new Material(shader); if (sprite.packed) { mat.name = "Unity Packed Sprite Material"; } else { mat.name = sprite.name + " Sprite Material"; } mat.mainTexture = tex; //create faux-region to play nice with SkeletonRenderer atlasRegion = new AtlasRegion(); AtlasPage page = new AtlasPage(); page.rendererObject = mat; atlasRegion.page = page; //cache it atlasTable[instanceId] = atlasRegion; } Rect texRect = sprite.textureRect; //normalize rect to UV space of packed atlas texRect.x = Mathf.InverseLerp(0, tex.width, texRect.x); texRect.y = Mathf.InverseLerp(0, tex.height, texRect.y); texRect.width = Mathf.InverseLerp(0, tex.width, texRect.width); texRect.height = Mathf.InverseLerp(0, tex.height, texRect.height); Bounds bounds = sprite.bounds; Vector3 size = bounds.size; //TODO: make sure this rotation thing actually works bool rotated = false; if (sprite.packed) { rotated = sprite.packingRotation == SpritePackingRotation.Any; } //do some math and assign UVs and sizes attachment.SetUVs(texRect.xMin, texRect.yMax, texRect.xMax, texRect.yMin, rotated); attachment.RendererObject = atlasRegion; attachment.SetColor(Color.white); attachment.ScaleX = 1; attachment.ScaleY = 1; attachment.RegionOffsetX = sprite.rect.width * (0.5f - Mathf.InverseLerp(bounds.min.x, bounds.max.x, 0)) / sprite.pixelsPerUnit; attachment.RegionOffsetY = sprite.rect.height * (0.5f - Mathf.InverseLerp(bounds.min.y, bounds.max.y, 0)) / sprite.pixelsPerUnit; attachment.Width = size.x; attachment.Height = size.y; attachment.RegionWidth = size.x; attachment.RegionHeight = size.y; attachment.RegionOriginalWidth = size.x; attachment.RegionOriginalHeight = size.y; attachment.UpdateOffset(); return(attachment); }
public virtual void Update() { // Clear fields if missing information to render. if (skeletonDataAsset == null || skeletonDataAsset.GetSkeletonData(false) == null) { Clear(); return; } // Initialize fields. if (skeleton == null || skeleton.Data != skeletonDataAsset.GetSkeletonData(false)) { Initialize(); } UpdateSkeleton(); // Count quads. int quadCount = 0; List <Slot> drawOrder = skeleton.DrawOrder; for (int i = 0, n = drawOrder.Count; i < n; i++) { Slot slot = drawOrder[i]; Attachment attachment = slot.Attachment; if (attachment is RegionAttachment) { quadCount++; } } // Ensure mesh data is the right size. Vector3[] vertices = this.vertices; int vertexCount = quadCount * 4; bool newTriangles = vertexCount > vertices.Length; if (newTriangles) { // Not enough vertices, increase size. this.vertices = vertices = new Vector3[vertexCount]; colors = new Color32[vertexCount]; uvs = new Vector2[vertexCount]; triangles = new int[quadCount * 6]; mesh.Clear(); for (int i = 0, n = quadCount; i < n; i++) { int index = i * 6; int vertex = i * 4; triangles[index] = vertex; triangles[index + 1] = vertex + 2; triangles[index + 2] = vertex + 1; triangles[index + 3] = vertex + 2; triangles[index + 4] = vertex + 3; triangles[index + 5] = vertex + 1; } } else { // Too many vertices, zero the extra. Vector3 zero = new Vector3(0, 0, 0); for (int i = vertexCount, n = lastVertexCount; i < n; i++) { vertices[i] = zero; } } lastVertexCount = vertexCount; // Setup mesh. float[] vertexPositions = this.vertexPositions; int vertexIndex = 0; Color32 color = new Color32(); for (int i = 0, n = drawOrder.Count; i < n; i++) { Slot slot = drawOrder[i]; RegionAttachment regionAttachment = slot.Attachment as RegionAttachment; if (regionAttachment == null) { continue; } regionAttachment.ComputeVertices(skeleton.X, skeleton.Y, slot.Bone, vertexPositions); vertices[vertexIndex] = new Vector3(vertexPositions[RegionAttachment.X1], vertexPositions[RegionAttachment.Y1], 0); vertices[vertexIndex + 1] = new Vector3(vertexPositions[RegionAttachment.X4], vertexPositions[RegionAttachment.Y4], 0); vertices[vertexIndex + 2] = new Vector3(vertexPositions[RegionAttachment.X2], vertexPositions[RegionAttachment.Y2], 0); vertices[vertexIndex + 3] = new Vector3(vertexPositions[RegionAttachment.X3], vertexPositions[RegionAttachment.Y3], 0); color.a = (byte)(skeleton.A * slot.A * 255); color.r = (byte)(skeleton.R * slot.R * color.a); color.g = (byte)(skeleton.G * slot.G * color.a); color.b = (byte)(skeleton.B * slot.B * color.a); 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], 1 - regionUVs[RegionAttachment.Y1]); uvs[vertexIndex + 1] = new Vector2(regionUVs[RegionAttachment.X4], 1 - regionUVs[RegionAttachment.Y4]); uvs[vertexIndex + 2] = new Vector2(regionUVs[RegionAttachment.X2], 1 - regionUVs[RegionAttachment.Y2]); uvs[vertexIndex + 3] = new Vector2(regionUVs[RegionAttachment.X3], 1 - regionUVs[RegionAttachment.Y3]); vertexIndex += 4; } mesh.vertices = vertices; mesh.colors32 = colors; mesh.uv = uvs; if (newTriangles) { mesh.triangles = triangles; } }
public virtual void LateUpdate() { if (!valid || (!meshRenderer.enabled && this.generateMeshOverride == null)) { return; } ExposedList <Slot> drawOrder = skeleton.drawOrder; Slot[] items = drawOrder.Items; int count = drawOrder.Count; bool flag = renderMeshes; SmartMesh.Instruction instruction = currentInstructions; ExposedList <Attachment> attachments = instruction.attachments; attachments.Clear(clearArray: false); attachments.GrowIfNeeded(count); attachments.Count = count; Attachment[] items2 = instruction.attachments.Items; ExposedList <SubmeshInstruction> submeshInstructions = instruction.submeshInstructions; submeshInstructions.Clear(clearArray: false); bool flag2 = customSlotMaterials.Count > 0; int num = 0; int num2 = 0; int num3 = 0; int firstVertexIndex = 0; int startSlot = 0; Material material = null; for (int i = 0; i < count; i++) { Slot slot = items[i]; Attachment attachment = items2[i] = slot.attachment; RegionAttachment regionAttachment = attachment as RegionAttachment; object rendererObject; int num4; int num5; if (regionAttachment != null) { rendererObject = regionAttachment.RendererObject; num4 = 4; num5 = 6; } else { if (!flag) { continue; } MeshAttachment meshAttachment = attachment as MeshAttachment; if (meshAttachment == null) { continue; } rendererObject = meshAttachment.RendererObject; num4 = meshAttachment.worldVerticesLength >> 1; num5 = meshAttachment.triangles.Length; } Material value; if (flag2) { if (!customSlotMaterials.TryGetValue(slot, out value)) { value = (Material)((AtlasRegion)rendererObject).page.rendererObject; } } else { value = (Material)((AtlasRegion)rendererObject).page.rendererObject; } bool flag3 = separatorSlots.Count > 0 && separatorSlots.Contains(slot); if (num > 0 && (material.GetInstanceID() != value.GetInstanceID() || flag3)) { submeshInstructions.Add(new SubmeshInstruction { skeleton = skeleton, material = material, startSlot = startSlot, endSlot = i, triangleCount = num3, firstVertexIndex = firstVertexIndex, vertexCount = num2, forceSeparate = flag3 }); num3 = 0; num2 = 0; firstVertexIndex = num; startSlot = i; } material = value; num3 += num5; num += num4; num2 += num4; } if (num2 != 0) { submeshInstructions.Add(new SubmeshInstruction { skeleton = skeleton, material = material, startSlot = startSlot, endSlot = count, triangleCount = num3, firstVertexIndex = firstVertexIndex, vertexCount = num2, forceSeparate = false }); } instruction.vertexCount = num; instruction.immutableTriangles = immutableTriangles; if (customMaterialOverride.Count > 0) { SubmeshInstruction[] items3 = submeshInstructions.Items; for (int j = 0; j < submeshInstructions.Count; j++) { Material material2 = items3[j].material; Material value2; if (customMaterialOverride.TryGetValue(material2, out value2)) { items3[j].material = value2; } } } if (this.generateMeshOverride != null) { this.generateMeshOverride(instruction); if (disableRenderingOnOverride) { return; } } if (ArraysMeshGenerator.EnsureSize(num, ref vertices, ref uvs, ref colors) && calculateNormals) { Vector3[] array = normals = new Vector3[num]; Vector3 vector = new Vector3(0f, 0f, -1f); for (int k = 0; k < num; k++) { array[k] = vector; } } Vector3 boundsMin = default(Vector3); Vector3 boundsMax = default(Vector3); if (num <= 0) { boundsMin = new Vector3(0f, 0f, 0f); boundsMax = new Vector3(0f, 0f, 0f); } else { boundsMin.x = 2.14748365E+09f; boundsMin.y = 2.14748365E+09f; boundsMax.x = -2.14748365E+09f; boundsMax.y = -2.14748365E+09f; if (zSpacing > 0f) { boundsMin.z = 0f; boundsMax.z = zSpacing * (float)(count - 1); } else { boundsMin.z = zSpacing * (float)(count - 1); boundsMax.z = 0f; } } int vertexIndex = 0; ArraysMeshGenerator.FillVerts(skeleton, 0, count, zSpacing, pmaVertexColors, vertices, uvs, colors, ref vertexIndex, ref tempVertices, ref boundsMin, ref boundsMax, flag); SmartMesh next = doubleBufferedMesh.GetNext(); Mesh mesh = next.mesh; mesh.vertices = vertices; mesh.colors32 = colors; mesh.uv = uvs; mesh.bounds = ArraysMeshGenerator.ToBounds(boundsMin, boundsMax); SmartMesh.Instruction instructionUsed = next.instructionUsed; if (calculateNormals && instructionUsed.vertexCount < num) { mesh.normals = normals; } bool flag4 = CheckIfMustUpdateMeshStructure(instruction, instructionUsed); int count2 = submeshInstructions.Count; if (flag4) { ExposedList <Material> exposedList = submeshMaterials; exposedList.Clear(clearArray: false); int count3 = submeshes.Count; if (submeshes.Capacity < count2) { submeshes.Capacity = count2; } for (int l = count3; l < count2; l++) { submeshes.Items[l] = new ArraysMeshGenerator.SubmeshTriangleBuffer(submeshInstructions.Items[l].triangleCount); } submeshes.Count = count2; bool flag5 = !instruction.immutableTriangles; int m = 0; int num6 = count2 - 1; for (; m < count2; m++) { SubmeshInstruction submeshInstruction = submeshInstructions.Items[m]; if (flag5 || m >= count3) { ArraysMeshGenerator.SubmeshTriangleBuffer submeshTriangleBuffer = submeshes.Items[m]; int triangleCount = submeshInstruction.triangleCount; if (flag) { ArraysMeshGenerator.FillTriangles(ref submeshTriangleBuffer.triangles, skeleton, triangleCount, submeshInstruction.firstVertexIndex, submeshInstruction.startSlot, submeshInstruction.endSlot, m == num6); submeshTriangleBuffer.triangleCount = triangleCount; } else { ArraysMeshGenerator.FillTrianglesQuads(ref submeshTriangleBuffer.triangles, ref submeshTriangleBuffer.triangleCount, ref submeshTriangleBuffer.firstVertex, submeshInstruction.firstVertexIndex, triangleCount, m == num6); } } exposedList.Add(submeshInstruction.material); } mesh.subMeshCount = count2; for (int n = 0; n < count2; n++) { mesh.SetTriangles(submeshes.Items[n].triangles, n); } } if (calculateTangents) { ArraysMeshGenerator.SolveTangents2DEnsureSize(ref tangents, ref tempTanBuffer, vertices.Length); for (int num7 = 0; num7 < count2; num7++) { ArraysMeshGenerator.SubmeshTriangleBuffer submeshTriangleBuffer2 = submeshes.Items[num7]; ArraysMeshGenerator.SolveTangents2DTriangles(tempTanBuffer, submeshTriangleBuffer2.triangles, submeshTriangleBuffer2.triangleCount, vertices, uvs, num); } ArraysMeshGenerator.SolveTangents2DBuffer(tangents, tempTanBuffer, num); mesh.tangents = tangents; } Material[] array2 = sharedMaterials; bool flag6 = flag4 || array2.Length != count2; if (!flag6) { SubmeshInstruction[] items4 = submeshInstructions.Items; int num8 = 0; for (int num9 = array2.Length; num8 < num9; num8++) { if (array2[num8].GetInstanceID() != items4[num8].material.GetInstanceID()) { flag6 = true; break; } } } if (flag6) { if (submeshMaterials.Count == sharedMaterials.Length) { submeshMaterials.CopyTo(sharedMaterials); } else { sharedMaterials = submeshMaterials.ToArray(); } meshRenderer.sharedMaterials = sharedMaterials; } meshFilter.sharedMesh = mesh; next.instructionUsed.Set(instruction); }
public virtual void Draw() { if (!valid) { return; } // Count vertices and submesh triangles. int vertexCount = 0; int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0; Material lastMaterial = null; submeshMaterials.Clear(); List <Slot> drawOrder = skeleton.DrawOrder; int drawOrderCount = drawOrder.Count; bool renderMeshes = this.renderMeshes; for (int i = 0; i < drawOrderCount; i++) { Slot slot = drawOrder[i]; Attachment attachment = slot.attachment; object rendererObject; int attachmentVertexCount, attachmentTriangleCount; if (attachment is RegionAttachment) { rendererObject = ((RegionAttachment)attachment).RendererObject; attachmentVertexCount = 4; attachmentTriangleCount = 6; } else { if (!renderMeshes) { continue; } if (attachment is MeshAttachment) { MeshAttachment meshAttachment = (MeshAttachment)attachment; rendererObject = meshAttachment.RendererObject; attachmentVertexCount = meshAttachment.vertices.Length >> 1; attachmentTriangleCount = meshAttachment.triangles.Length; } else if (attachment is SkinnedMeshAttachment) { SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment; rendererObject = meshAttachment.RendererObject; attachmentVertexCount = meshAttachment.uvs.Length >> 1; attachmentTriangleCount = meshAttachment.triangles.Length; } else { continue; } } // Populate submesh when material changes. #if !SPINE_TK2D Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject; #else Material material = (rendererObject.GetType() == typeof(Material)) ? (Material)rendererObject : (Material)((AtlasRegion)rendererObject).page.rendererObject; #endif if ((lastMaterial != material && lastMaterial != null) || submeshSeparatorSlots.Contains(slot)) { AddSubmesh(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false); submeshTriangleCount = 0; submeshFirstVertex = vertexCount; submeshStartSlotIndex = i; } lastMaterial = material; //new Material(material); submeshTriangleCount += attachmentTriangleCount; vertexCount += attachmentVertexCount; } AddSubmesh(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true); // Set materials. if (submeshMaterials.Count == mMats.Length) { submeshMaterials.CopyTo(mMats); } else { mMats = submeshMaterials.ToArray(); } mRenderer.materials = mMats; // 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.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] = new Vector2(regionUVs[RegionAttachment.X1], regionUVs[RegionAttachment.Y1]); uvs[vertexIndex + 1] = new Vector2(regionUVs[RegionAttachment.X4], regionUVs[RegionAttachment.Y4]); uvs[vertexIndex + 2] = new Vector2(regionUVs[RegionAttachment.X2], regionUVs[RegionAttachment.Y2]); uvs[vertexIndex + 3] = new Vector2(regionUVs[RegionAttachment.X3], regionUVs[RegionAttachment.Y3]); vertexIndex += 4; } else { if (!renderMeshes) { continue; } if (attachment is MeshAttachment) { MeshAttachment meshAttachment = (MeshAttachment)attachment; int meshVertexCount = meshAttachment.vertices.Length; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } meshAttachment.ComputeWorldVertices(slot, tempVertices); color.a = (byte)(a * slot.a * meshAttachment.a); color.r = (byte)(r * slot.r * meshAttachment.r * color.a); color.g = (byte)(g * slot.g * meshAttachment.g * color.a); color.b = (byte)(b * slot.b * meshAttachment.b * color.a); if (slot.data.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] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z); colors[vertexIndex] = color; uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]); } } else if (attachment is SkinnedMeshAttachment) { SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment; int meshVertexCount = meshAttachment.uvs.Length; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } meshAttachment.ComputeWorldVertices(slot, tempVertices); color.a = (byte)(a * slot.a * meshAttachment.a); color.r = (byte)(r * slot.r * meshAttachment.r * color.a); color.g = (byte)(g * slot.g * meshAttachment.g * color.a); color.b = (byte)(b * slot.b * meshAttachment.b * color.a); if (slot.data.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] = 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.mesh = mesh; mesh.vertices = vertices; mesh.colors32 = colors; mesh.uv = uvs; int submeshCount = submeshMaterials.Count; mesh.subMeshCount = submeshCount; for (int i = 0; i < submeshCount; ++i) { mesh.SetTriangles(submeshes[i].triangles, i); } mesh.RecalculateBounds(); if (newTriangles && calculateNormals) { Vector3[] normals = new Vector3[vertexCount]; Vector3 normal = new Vector3(0, 0, -1); for (int i = 0; i < vertexCount; i++) { normals[i] = normal; } (useMesh1 ? mesh2 : mesh1).vertices = vertices; // Set other mesh vertices. mesh1.normals = normals; mesh2.normals = normals; if (calculateTangents) { Vector4[] tangents = new Vector4[vertexCount]; Vector3 tangent = new Vector3(0, 0, 1); for (int i = 0; i < vertexCount; i++) { tangents[i] = tangent; } mesh1.tangents = tangents; mesh2.tangents = tangents; } } if (submeshRenderers.Length > 0) { foreach (var submeshRenderer in submeshRenderers) { if (submeshRenderer.submeshIndex < mMats.Length) { submeshRenderer.SetMesh(mRenderer, useMesh1 ? mesh1 : mesh2, mMats[submeshRenderer.submeshIndex]); } else { submeshRenderer.GetComponent <Renderer>().enabled = false; } } } useMesh1 = !useMesh1; }
public Attachment NewAttachment(Skin skin, AttachmentType type, String name) { if (type != AttachmentType.region) { throw new Exception("Unknown attachment type: " + type); } // Strip folder names. int index = name.LastIndexOfAny(new char[] { '/', '\\' }); if (index != -1) { name = name.Substring(index + 1); } tk2dSpriteDefinition attachmentParameters = null; for (int i = 0; i < sprites.inst.spriteDefinitions.Length; ++i) { tk2dSpriteDefinition def = sprites.inst.spriteDefinitions[i]; if (def.name == name) { attachmentParameters = def; break; } } if (attachmentParameters == null) { throw new Exception("Sprite not found in atlas: " + name + " (" + type + ")"); } if (attachmentParameters.complexGeometry) { throw new NotImplementedException("Complex geometry is not supported: " + name + " (" + type + ")"); } if (attachmentParameters.flipped == tk2dSpriteDefinition.FlipMode.TPackerCW) { throw new NotImplementedException("Only 2D Toolkit atlases are supported: " + name + " (" + type + ")"); } Vector2 minTexCoords = Vector2.one; Vector2 maxTexCoords = Vector2.zero; for (int i = 0; i < attachmentParameters.uvs.Length; ++i) { Vector2 uv = attachmentParameters.uvs[i]; minTexCoords = Vector2.Min(minTexCoords, uv); maxTexCoords = Vector2.Max(maxTexCoords, uv); } Texture texture = attachmentParameters.material.mainTexture; int width = (int)(Mathf.Abs(maxTexCoords.x - minTexCoords.x) * texture.width); int height = (int)(Mathf.Abs(maxTexCoords.y - minTexCoords.y) * texture.height); bool rotated = (attachmentParameters.flipped == tk2dSpriteDefinition.FlipMode.Tk2d); if (rotated) { float temp = minTexCoords.x; minTexCoords.x = maxTexCoords.x; maxTexCoords.x = temp; } RegionAttachment attachment = new RegionAttachment(name); attachment.SetUVs( minTexCoords.x, maxTexCoords.y, maxTexCoords.x, minTexCoords.y, rotated ); // TODO - Set attachment.RegionOffsetX/Y. What units does attachmentParameters.untrimmedBoundsData use?! attachment.RegionWidth = width; attachment.RegionHeight = height; attachment.RegionOriginalWidth = width; attachment.RegionOriginalHeight = height; return(attachment); }
/// <summary> /// Allows to perform custom drawing. /// </summary> /// <param name="gameTime">The elapsed game time.</param> public override void Draw(TimeSpan gameTime) { if (this.SkeletalData.Atlas == null || this.SkeletalAnimation.Skeleton == null) { return; } float opacity = this.Transform2D.GlobalOpacity; if (this.RenderManager.ShouldDrawFlag(Framework.Managers.DebugLinesFlags.DebugAlphaOpacity)) { opacity *= DebugAlpha; } int numVertices = 0; int numPrimitives = 0; VertexPositionColorTexture tempVertex; StandardMaterial material = null; // Process Mesh for (int i = 0; i < this.drawOrder.Count; i++) { var slot = this.drawOrder.Items[i]; var attachment = slot.Attachment; var skeleton = this.SkeletalAnimation.Skeleton; if (attachment is RegionAttachment) { RegionAttachment regionAttachment = attachment as RegionAttachment; byte a = (byte)(skeleton.A * 255 * slot.A * regionAttachment.A * opacity); byte r = (byte)(skeleton.R * slot.R * regionAttachment.R * a); byte g = (byte)(skeleton.G * slot.G * regionAttachment.G * a); byte b = (byte)(skeleton.B * slot.B * regionAttachment.B * a); if (slot.Data.BlendMode == SpineBlendMode.additive) { a = 0; } Color color = new Color(r, g, b, a); float[] uvs = regionAttachment.UVs; var region = (AtlasRegion)regionAttachment.RendererObject; material = (StandardMaterial)region.page.rendererObject; var computedVertices = this.ComputeAttachmentVertices(regionAttachment, slot); this.vertices = new VertexPositionColorTexture[4]; // Vertex TL tempVertex.Position = computedVertices[0]; tempVertex.Color = color; tempVertex.TexCoord.X = uvs[RegionAttachment.X1]; tempVertex.TexCoord.Y = uvs[RegionAttachment.Y1]; this.vertices[0] = tempVertex; // Vertex TR tempVertex.Position = computedVertices[1]; tempVertex.Color = color; tempVertex.TexCoord.X = uvs[RegionAttachment.X4]; tempVertex.TexCoord.Y = uvs[RegionAttachment.Y4]; this.vertices[1] = tempVertex; // Vertex BR tempVertex.Position = computedVertices[2]; tempVertex.Color = color; tempVertex.TexCoord.X = uvs[RegionAttachment.X3]; tempVertex.TexCoord.Y = uvs[RegionAttachment.Y3]; this.vertices[2] = tempVertex; // Vertex BL tempVertex.Position = computedVertices[3]; tempVertex.Color = color; tempVertex.TexCoord.X = uvs[RegionAttachment.X2]; tempVertex.TexCoord.Y = uvs[RegionAttachment.Y2]; this.vertices[3] = tempVertex; numVertices = 4; numPrimitives = 2; this.indices = this.quadIndices; } else if (attachment is MeshAttachment) { var mesh = (MeshAttachment)attachment; byte a = (byte)(skeleton.A * 255 * slot.A * mesh.A * opacity); byte r = (byte)(skeleton.R * slot.R * mesh.R * a); byte g = (byte)(skeleton.G * slot.G * mesh.G * a); byte b = (byte)(skeleton.B * slot.B * mesh.B * a); if (slot.Data.BlendMode == SpineBlendMode.additive) { a = 0; } Color color = new Color(r, g, b, a); numVertices = mesh.Vertices.Length; this.indices = this.CopyIndices(mesh.Triangles); numPrimitives = this.indices.Length / 3; var region = (AtlasRegion)mesh.RendererObject; material = (StandardMaterial)region.page.rendererObject; var computedVertices = this.ComputeAttachmentVertices(mesh, slot); this.vertices = new VertexPositionColorTexture[numVertices / 2]; float[] uvs = mesh.UVs; for (int v = 0, j = 0; v < numVertices; v += 2, j++) { tempVertex.Position = computedVertices[j]; tempVertex.Color = color; tempVertex.TexCoord.X = uvs[v]; tempVertex.TexCoord.Y = uvs[v + 1]; this.vertices[j] = tempVertex; } } else if (attachment is WeightedMeshAttachment) { var mesh = (WeightedMeshAttachment)attachment; byte a = (byte)(skeleton.A * 255 * slot.A * mesh.A * opacity); byte r = (byte)(skeleton.R * slot.R * mesh.R * a); byte g = (byte)(skeleton.G * slot.G * mesh.G * a); byte b = (byte)(skeleton.B * slot.B * mesh.B * a); if (slot.Data.BlendMode == SpineBlendMode.additive) { a = 0; } Color color = new Color(r, g, b, a); numVertices = mesh.UVs.Length; this.indices = this.CopyIndices(mesh.Triangles); numPrimitives = this.indices.Length / 3; var computedVertices = this.ComputeAttachmentVertices(mesh, slot); var region = (AtlasRegion)mesh.RendererObject; material = (StandardMaterial)region.page.rendererObject; this.vertices = new VertexPositionColorTexture[numVertices / 2]; float[] uvs = mesh.UVs; for (int v = 0, j = 0; v < numVertices; v += 2, j++) { tempVertex.Position = computedVertices[j]; tempVertex.Color = color; tempVertex.TexCoord.X = uvs[v]; tempVertex.TexCoord.Y = uvs[v + 1]; this.vertices[j] = tempVertex; } } if (attachment != null && material != null) { bool reset = false; if (this.spineMeshes[i] != null) { if (this.spineMeshes[i].VertexBuffer.VertexCount != this.vertices.Length || this.spineMeshes[i].IndexBuffer.Data.Length != this.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(this.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 - (i * this.ZOrderBias); mesh.DisableBatch = true; material.LayerId = this.LayerId; Matrix worldTransform = this.Transform2D.WorldTransform; this.RenderManager.DrawMesh(mesh, material, ref worldTransform, 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); 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; }
public override 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(); } // GetComponent<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 [X1], tempVertices [Y1], z); vertices [vertexIndex + 1] = new Vector3(tempVertices [X2], tempVertices [Y2], z); vertices [vertexIndex + 2] = new Vector3(tempVertices [X3], tempVertices [Y3], z); vertices [vertexIndex + 3] = new Vector3(tempVertices [X4], tempVertices [Y4], 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 [X1], regionUVs [Y1]); uvs [vertexIndex + 1] = new Vector2(regionUVs [X2], regionUVs [Y2]); uvs [vertexIndex + 2] = new Vector2(regionUVs [X3], regionUVs [Y3]); uvs [vertexIndex + 3] = new Vector2(regionUVs [X4], regionUVs [Y4]); vertexIndex += 4; } else { if (!renderMeshes) { continue; } if (attachment is MeshAttachment) { MeshAttachment meshAttachment = (MeshAttachment)attachment; int meshVertexCount = meshAttachment.vertices.Length; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } meshAttachment.ComputeWorldVertices(slot, tempVertices); color.a = (byte)(a * slot.a * meshAttachment.a); color.r = (byte)(r * slot.r * meshAttachment.r * color.a); color.g = (byte)(g * slot.g * meshAttachment.g * color.a); color.b = (byte)(b * slot.b * meshAttachment.b * color.a); if (slot.data.additiveBlending) { color.a = 0; } float[] meshUVs = meshAttachment.uvs; float z = i * zSpacing; for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { vertices [vertexIndex] = new Vector3(tempVertices [ii], tempVertices [ii + 1], z); colors [vertexIndex] = color; uvs [vertexIndex] = new Vector2(meshUVs [ii], meshUVs [ii + 1]); } } else if (attachment is SkinnedMeshAttachment) { SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment; int meshVertexCount = meshAttachment.uvs.Length; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } meshAttachment.ComputeWorldVertices(slot, tempVertices); color.a = (byte)(a * slot.a * meshAttachment.a); color.r = (byte)(r * slot.r * meshAttachment.r * color.a); color.g = (byte)(g * slot.g * meshAttachment.g * color.a); color.b = (byte)(b * slot.b * meshAttachment.b * color.a); if (slot.data.additiveBlending) { color.a = 0; } float[] meshUVs = meshAttachment.uvs; float z = i * zSpacing; for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { vertices [vertexIndex] = new Vector3(tempVertices [ii], tempVertices [ii + 1], z); colors [vertexIndex] = color; uvs [vertexIndex] = new Vector2(meshUVs [ii], meshUVs [ii + 1]); } } } } if (fillDrawCall != null) { fillDrawCall(vertices, colors, uvs); } }
public Attachment NewAttachment(Skin skin, AttachmentType type, String name) { switch (type) { case AttachmentType.region: break; case AttachmentType.boundingbox: return(new BoundingBoxAttachment(name)); default: throw new Exception("Unknown attachment type: " + type); } // Strip folder names. int index = name.LastIndexOfAny(new char[] { '/', '\\' }); if (index != -1) { name = name.Substring(index + 1); } tk2dSpriteDefinition def = sprites.inst.GetSpriteDefinition(name); if (def == null) { throw new Exception("Sprite not found in atlas: " + name + " (" + type + ")"); } if (def.complexGeometry) { throw new NotImplementedException("Complex geometry is not supported: " + name + " (" + type + ")"); } if (def.flipped == tk2dSpriteDefinition.FlipMode.TPackerCW) { throw new NotImplementedException("Only 2D Toolkit atlases are supported: " + name + " (" + type + ")"); } RegionAttachment attachment = new RegionAttachment(name); Vector2 minTexCoords = Vector2.one; Vector2 maxTexCoords = Vector2.zero; for (int i = 0; i < def.uvs.Length; ++i) { Vector2 uv = def.uvs[i]; minTexCoords = Vector2.Min(minTexCoords, uv); maxTexCoords = Vector2.Max(maxTexCoords, uv); } bool rotated = def.flipped == tk2dSpriteDefinition.FlipMode.Tk2d; if (rotated) { float temp = minTexCoords.x; minTexCoords.x = maxTexCoords.x; maxTexCoords.x = temp; } attachment.SetUVs( minTexCoords.x, maxTexCoords.y, maxTexCoords.x, minTexCoords.y, rotated ); attachment.RegionOriginalWidth = (int)(def.untrimmedBoundsData[1].x / def.texelSize.x); attachment.RegionOriginalHeight = (int)(def.untrimmedBoundsData[1].y / def.texelSize.y); attachment.RegionWidth = (int)(def.boundsData[1].x / def.texelSize.x); attachment.RegionHeight = (int)(def.boundsData[1].y / def.texelSize.y); float x0 = def.untrimmedBoundsData[0].x - def.untrimmedBoundsData[1].x / 2; float x1 = def.boundsData[0].x - def.boundsData[1].x / 2; attachment.RegionOffsetX = (int)((x1 - x0) / def.texelSize.x); float y0 = def.untrimmedBoundsData[0].y - def.untrimmedBoundsData[1].y / 2; float y1 = def.boundsData[0].y - def.boundsData[1].y / 2; attachment.RegionOffsetY = (int)((y1 - y0) / def.texelSize.y); attachment.RendererObject = def.material; return(attachment); }
/* */ private void UpdateMesh() { int quadIndex = 0; int drawCount = skeleton.DrawOrder.Count; Color currentColor = new Color(); for (int i = 0; i < drawCount; i++) { Slot slot = skeleton.DrawOrder[i]; Attachment attachment = slot.Attachment; if (attachment is RegionAttachment) { RegionAttachment regionAttachment = attachment as RegionAttachment; regionAttachment.ComputeVertices(slot.Bone, vertexPositions); int vertexIndex = quadIndex * 4; vertices[vertexIndex + 0] = new Vector3(vertexPositions[RegionAttachment.X1], vertexPositions[RegionAttachment.Y1], 0); vertices[vertexIndex + 1] = new Vector3(vertexPositions[RegionAttachment.X4], vertexPositions[RegionAttachment.Y4], 0); vertices[vertexIndex + 2] = new Vector3(vertexPositions[RegionAttachment.X2], vertexPositions[RegionAttachment.Y2], 0); vertices[vertexIndex + 3] = new Vector3(vertexPositions[RegionAttachment.X3], vertexPositions[RegionAttachment.Y3], 0); float[] regionUVs = regionAttachment.UVs; uvs[vertexIndex + 0] = 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]); currentColor.a = skeleton.A * slot.A; currentColor.r = skeleton.R * slot.R * slot.A; currentColor.g = skeleton.G * slot.G * slot.A; currentColor.b = skeleton.B * slot.B * slot.A; colors[vertexIndex] = currentColor; colors[vertexIndex + 1] = currentColor; colors[vertexIndex + 2] = currentColor; colors[vertexIndex + 3] = currentColor; int index = quadIndex * 6; triangles[index + 0] = vertexIndex; triangles[index + 1] = vertexIndex + 2; triangles[index + 2] = vertexIndex + 1; triangles[index + 3] = vertexIndex + 2; triangles[index + 4] = vertexIndex + 3; triangles[index + 5] = vertexIndex + 1; quadIndex++; } } mesh.Clear(); mesh.vertices = vertices; mesh.colors = colors; mesh.uv = uvs; mesh.triangles = triangles; if (skeletonDataAsset.normalGenerationMode != tk2dSpriteCollection.NormalGenerationMode.None) { mesh.RecalculateNormals(); if (skeletonDataAsset.normalGenerationMode == tk2dSpriteCollection.NormalGenerationMode.NormalsAndTangents) { Vector4[] tangents = new Vector4[mesh.normals.Length]; for (int t = 0; t < tangents.Length; ++t) { tangents[t] = new Vector4(1, 0, 0, 1); } mesh.tangents = tangents; } } renderer.sharedMaterial = skeletonDataAsset.spritesData.inst.materials[0]; }
/// <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> Sets the rotation. Call regionAttachment.UpdateOffset to apply the change.</summary> public static void SetRotation(this RegionAttachment regionAttachment, float rotation) { regionAttachment.rotation = rotation; }
// RegionAttachment protected void AddAttachment(Slot slot, RegionAttachment attachment) { var tempVertices = this.tempVertices; attachment.ComputeWorldVertices(slot.bone, tempVertices); float[] regionUVs = attachment.uvs; Color color = skeletonColor; color.r = color.r * attachment.r * slot.r; color.g = color.g * attachment.g * slot.g; color.b = color.b * attachment.b * slot.b; color.a = color.a * attachment.a * slot.a; if (premultiplyAlpha) { color.r *= color.a; color.g *= color.a; color.b *= color.a; if (slot.data.blendMode == BlendMode.additive) color.a = 0; } int fv = positions.Count; // first vertex index AddVert(new Vector3(tempVertices[RegionAttachment.X1] * scale, tempVertices[RegionAttachment.Y1] * scale), color, new Vector2(regionUVs[RegionAttachment.X1], regionUVs[RegionAttachment.Y1])); AddVert(new Vector3(tempVertices[RegionAttachment.X4] * scale, tempVertices[RegionAttachment.Y4] * scale), color, new Vector2(regionUVs[RegionAttachment.X4], regionUVs[RegionAttachment.Y4])); AddVert(new Vector3(tempVertices[RegionAttachment.X2] * scale, tempVertices[RegionAttachment.Y2] * scale), color, new Vector2(regionUVs[RegionAttachment.X2], regionUVs[RegionAttachment.Y2])); AddVert(new Vector3(tempVertices[RegionAttachment.X3] * scale, tempVertices[RegionAttachment.Y3] * scale), color, new Vector2(regionUVs[RegionAttachment.X3], regionUVs[RegionAttachment.Y3])); AddTriangle(fv, fv+2, fv+1); AddTriangle(fv+2, fv+3, fv+1); }
/// <summary> /// Creates a new RegionAttachment from a given AtlasRegion.</summary> public static RegionAttachment ToRegionAttachment (this AtlasRegion region, string attachmentName, float scale = 0.01f) { if (string.IsNullOrEmpty(attachmentName)) throw new System.ArgumentException("attachmentName can't be null or empty.", "attachmentName"); if (region == null) throw new System.ArgumentNullException("region"); // (AtlasAttachmentLoader.cs) var attachment = new RegionAttachment(attachmentName); attachment.RendererObject = region; attachment.SetUVs(region.u, region.v, region.u2, region.v2, region.rotate); attachment.regionOffsetX = region.offsetX; attachment.regionOffsetY = region.offsetY; attachment.regionWidth = region.width; attachment.regionHeight = region.height; attachment.regionOriginalWidth = region.originalWidth; attachment.regionOriginalHeight = region.originalHeight; attachment.Path = region.name; attachment.scaleX = 1; attachment.scaleY = 1; attachment.rotation = 0; // pass OriginalWidth and OriginalHeight because UpdateOffset uses it in its calculation. attachment.width = attachment.regionOriginalWidth * scale; attachment.height = attachment.regionOriginalHeight * scale; attachment.SetColor(Color.white); attachment.UpdateOffset(); return attachment; }
public virtual void LateUpdate() { if (!valid) { return; } if (cpuOptimizationLevel != 0) { skipFramesLateUpdate--; if (skipFramesLateUpdate > 0) { return; } skipFramesLateUpdate = cpuOptimizationLevel + UnityEngine.Random.Range(0, cpuOptimizationLevel); } if ( ( !meshRenderer.enabled ) #if SPINE_OPTIONAL_RENDEROVERRIDE && this.generateMeshOverride == null #endif #if SPINE_OPTIONAL_SUBMESHRENDERER && submeshRenderers.Length > 0 #endif ) { return; } // STEP 1. Determine a SmartMesh.Instruction. Split up instructions into submeshes. // This method caches several .Items arrays. // Never mutate their overlying ExposedList objects. ExposedList <Slot> drawOrder = skeleton.drawOrder; var drawOrderItems = drawOrder.Items; int drawOrderCount = drawOrder.Count; int separatorSlotCount = separatorSlots.Count; bool renderMeshes = this.renderMeshes; // Clear last state of attachments and submeshes var workingInstruction = this.currentInstructions; var workingAttachments = workingInstruction.attachments; workingAttachments.Clear(false); workingAttachments.GrowIfNeeded(drawOrderCount); workingAttachments.Count = drawOrderCount; var workingAttachmentsItems = workingInstruction.attachments.Items; #if SPINE_OPTIONAL_FRONTFACING var workingFlips = workingInstruction.attachmentFlips; workingFlips.Clear(false); workingFlips.GrowIfNeeded(drawOrderCount); workingFlips.Count = drawOrderCount; var workingFlipsItems = workingFlips.Items; #endif var workingSubmeshInstructions = workingInstruction.submeshInstructions; // Items array should not be cached. There is dynamic writing to this list. workingSubmeshInstructions.Clear(false); #if !SPINE_TK2D bool isCustomSlotMaterialsPopulated = customSlotMaterials.Count > 0; #endif int vertexCount = 0; int submeshVertexCount = 0; int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0; Material lastMaterial = null; for (int i = 0; i < drawOrderCount; i++) { Slot slot = drawOrderItems[i]; Attachment attachment = slot.attachment; workingAttachmentsItems[i] = attachment; #if SPINE_OPTIONAL_FRONTFACING bool flip = frontFacing && (slot.bone.WorldSignX != slot.bone.WorldSignY); workingFlipsItems[i] = flip; #endif object rendererObject; // An AtlasRegion in plain Spine-Unity. Spine-TK2D hooks into TK2D's system. eventual source of Material object. int attachmentVertexCount, attachmentTriangleCount; var regionAttachment = attachment as RegionAttachment; if (regionAttachment != null) { rendererObject = regionAttachment.RendererObject; attachmentVertexCount = 4; attachmentTriangleCount = 6; } else { if (!renderMeshes) { continue; } var meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { rendererObject = meshAttachment.RendererObject; attachmentVertexCount = meshAttachment.worldVerticesLength >> 1; attachmentTriangleCount = meshAttachment.triangles.Length; } else { continue; } } #if !SPINE_TK2D // Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject; // For no customSlotMaterials Material material; if (isCustomSlotMaterialsPopulated) { if (!customSlotMaterials.TryGetValue(slot, out material)) { material = (Material)((AtlasRegion)rendererObject).page.rendererObject; } } else { material = (Material)((AtlasRegion)rendererObject).page.rendererObject; } #else Material material = (rendererObject.GetType() == typeof(Material)) ? (Material)rendererObject : (Material)((AtlasRegion)rendererObject).page.rendererObject; #endif // Create a new SubmeshInstruction when material changes. (or when forced to separate by a submeshSeparator) bool forceSeparate = (separatorSlotCount > 0 && separatorSlots.Contains(slot)); if ((vertexCount > 0 && lastMaterial.GetInstanceID() != material.GetInstanceID()) || forceSeparate) { workingSubmeshInstructions.Add( new Spine.Unity.MeshGeneration.SubmeshInstruction { skeleton = this.skeleton, material = lastMaterial, startSlot = submeshStartSlotIndex, endSlot = i, triangleCount = submeshTriangleCount, firstVertexIndex = submeshFirstVertex, vertexCount = submeshVertexCount, forceSeparate = forceSeparate } ); submeshTriangleCount = 0; submeshVertexCount = 0; submeshFirstVertex = vertexCount; submeshStartSlotIndex = i; } lastMaterial = material; submeshTriangleCount += attachmentTriangleCount; vertexCount += attachmentVertexCount; submeshVertexCount += attachmentVertexCount; } if (submeshVertexCount != 0) { workingSubmeshInstructions.Add( new Spine.Unity.MeshGeneration.SubmeshInstruction { skeleton = this.skeleton, material = lastMaterial, startSlot = submeshStartSlotIndex, endSlot = drawOrderCount, triangleCount = submeshTriangleCount, firstVertexIndex = submeshFirstVertex, vertexCount = submeshVertexCount, forceSeparate = false } ); } workingInstruction.vertexCount = vertexCount; workingInstruction.immutableTriangles = this.immutableTriangles; #if SPINE_OPTIONAL_FRONTFACING workingInstruction.frontFacing = this.frontFacing; #endif // STEP 1.9. Post-process workingInstructions. #if SPINE_OPTIONAL_MATERIALOVERRIDE // Material overrides are done here so they can be applied per submesh instead of per slot // but they will still be passed through the GenerateMeshOverride delegate, // and will still go through the normal material match check step in STEP 3. if (customMaterialOverride.Count > 0) // isCustomMaterialOverridePopulated { var workingSubmeshInstructionsItems = workingSubmeshInstructions.Items; for (int i = 0; i < workingSubmeshInstructions.Count; i++) { var m = workingSubmeshInstructionsItems[i].material; Material mo; if (customMaterialOverride.TryGetValue(m, out mo)) { workingSubmeshInstructionsItems[i].material = mo; } } } #endif #if SPINE_OPTIONAL_RENDEROVERRIDE if (this.generateMeshOverride != null) { this.generateMeshOverride(workingInstruction); if (disableRenderingOnOverride) { return; } } #endif // STEP 2. Update vertex buffer based on verts from the attachments. // Uses values that were also stored in workingInstruction. Vector3[] vertices = this.vertices; bool vertexCountIncreased = vertexCount > vertices.Length; if (vertexCountIncreased) { this.vertices = vertices = new Vector3[vertexCount]; this.colors = new Color32[vertexCount]; this.uvs = new Vector2[vertexCount]; #if SPINE_OPTIONAL_NORMALS if (calculateNormals) { Vector3[] localNormals = this.normals = new Vector3[vertexCount]; Vector3 normal = new Vector3(0, 0, -1); for (int i = 0; i < vertexCount; i++) { localNormals[i] = normal; } } // For dynamic tangent calculation, you can remove the tangent-filling logic and add tangent calculation logic below. if (calculateTangents) { Vector4[] localTangents = this.tangents = new Vector4[vertexCount]; Vector4 tangent = new Vector4(1, 0, 0, -1); for (int i = 0; i < vertexCount; i++) { localTangents[i] = tangent; } } #endif } else { Vector3 zero = Vector3.zero; for (int i = vertexCount, n = vertices.Length; i < n; i++) { vertices[i] = zero; } } float zSpacing = this.zSpacing; float[] tempVertices = this.tempVertices; Vector2[] uvs = this.uvs; Color32[] colors = this.colors; int vertexIndex = 0; bool pmaVertexColors = this.pmaVertexColors; 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 = drawOrderItems[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; if (pmaVertexColors) { color.a = (byte)(a * slot.a * regionAttachment.a); color.r = (byte)(r * slot.r * regionAttachment.r * color.a); color.g = (byte)(g * slot.g * regionAttachment.g * color.a); color.b = (byte)(b * slot.b * regionAttachment.b * color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } } else { color.a = (byte)(a * slot.a * regionAttachment.a); color.r = (byte)(r * slot.r * regionAttachment.r * 255); color.g = (byte)(g * slot.g * regionAttachment.g * 255); color.b = (byte)(b * slot.b * regionAttachment.b * 255); } colors[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.worldVerticesLength; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } meshAttachment.ComputeWorldVertices(slot, tempVertices); if (pmaVertexColors) { color.a = (byte)(a * slot.a * meshAttachment.a); color.r = (byte)(r * slot.r * meshAttachment.r * color.a); color.g = (byte)(g * slot.g * meshAttachment.g * color.a); color.b = (byte)(b * slot.b * meshAttachment.b * color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } } else { color.a = (byte)(a * slot.a * meshAttachment.a); color.r = (byte)(r * slot.r * meshAttachment.r * 255); color.g = (byte)(g * slot.g * meshAttachment.g * 255); color.b = (byte)(b * slot.b * meshAttachment.b * 255); } float[] 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; } } } } } while (++i < drawOrderCount); } // Step 3. Move the mesh data into a UnityEngine.Mesh var currentSmartMesh = doubleBufferedMesh.GetNext(); // Double-buffer for performance. var currentMesh = currentSmartMesh.mesh; currentMesh.vertices = vertices; currentMesh.colors32 = colors; currentMesh.uv = uvs; Vector3 meshBoundsExtents = meshBoundsMax - meshBoundsMin; Vector3 meshBoundsCenter = meshBoundsMin + meshBoundsExtents * 0.5f; currentMesh.bounds = new Bounds(meshBoundsCenter, meshBoundsExtents); var currentSmartMeshInstructionUsed = currentSmartMesh.instructionUsed; #if SPINE_OPTIONAL_NORMALS if (currentSmartMeshInstructionUsed.vertexCount < vertexCount) { if (calculateNormals) { currentMesh.normals = normals; } // For dynamic calculated tangents, this needs to be moved out of the vertexCount check block when replacing the logic, also ensuring the size. if (calculateTangents) { currentMesh.tangents = this.tangents; } } #endif // Check if the triangles should also be updated. // This thorough structure check is cheaper than updating triangles every frame. bool mustUpdateMeshStructure = CheckIfMustUpdateMeshStructure(workingInstruction, currentSmartMeshInstructionUsed); if (mustUpdateMeshStructure) { var thisSubmeshMaterials = this.submeshMaterials; thisSubmeshMaterials.Clear(false); int submeshCount = workingSubmeshInstructions.Count; int oldSubmeshCount = submeshes.Count; submeshes.Capacity = submeshCount; for (int i = oldSubmeshCount; i < submeshCount; i++) { submeshes.Items[i] = new SubmeshTriangleBuffer(); } var mutableTriangles = !workingInstruction.immutableTriangles; for (int i = 0, last = submeshCount - 1; i < submeshCount; i++) { var submeshInstruction = workingSubmeshInstructions.Items[i]; if (mutableTriangles || i >= oldSubmeshCount) { SetSubmesh(i, submeshInstruction, #if SPINE_OPTIONAL_FRONTFACING currentInstructions.attachmentFlips, #endif i == last); } thisSubmeshMaterials.Add(submeshInstruction.material); } currentMesh.subMeshCount = submeshCount; for (int i = 0; i < submeshCount; ++i) { currentMesh.SetTriangles(submeshes.Items[i].triangles, i); } } // CheckIfMustUpdateMaterialArray (last pushed materials vs currently parsed materials) // Needs to check against the Working Submesh Instructions Materials instead of the cached submeshMaterials. { var lastPushedMaterials = this.sharedMaterials; bool mustUpdateRendererMaterials = mustUpdateMeshStructure || (lastPushedMaterials.Length != workingSubmeshInstructions.Count); if (!mustUpdateRendererMaterials) { var workingSubmeshInstructionsItems = workingSubmeshInstructions.Items; for (int i = 0, n = lastPushedMaterials.Length; i < n; i++) { if (lastPushedMaterials[i].GetInstanceID() != workingSubmeshInstructionsItems[i].material.GetInstanceID()) // Bounds check is implied above. { mustUpdateRendererMaterials = true; break; } } } if (mustUpdateRendererMaterials) { if (submeshMaterials.Count == sharedMaterials.Length) { submeshMaterials.CopyTo(sharedMaterials); } else { sharedMaterials = submeshMaterials.ToArray(); } meshRenderer.sharedMaterials = sharedMaterials; } } // Step 4. The UnityEngine.Mesh is ready. Set it as the MeshFilter's mesh. Store the instructions used for that mesh. meshFilter.sharedMesh = currentMesh; currentSmartMesh.instructionUsed.Set(workingInstruction); // Step 5. Miscellaneous // Add stuff here if you want #if SPINE_OPTIONAL_SUBMESHRENDERER if (submeshRenderers.Length > 0) { for (int i = 0; i < submeshRenderers.Length; i++) { var submeshRenderer = submeshRenderers[i]; if (submeshRenderer.submeshIndex < sharedMaterials.Length) { submeshRenderer.SetMesh(meshRenderer, currentMesh, sharedMaterials[submeshRenderer.submeshIndex]); } else { submeshRenderer.GetComponent <Renderer>().enabled = false; } } } #endif }
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); } } } }
/// <summary> /// 主要逻辑copy SkeletonJson.ReadAttachment /// </summary> /// <param name="sdEX"></param> /// <param name="atlasArray"></param> /// <returns></returns> public Skin GenSkinBySkniDataAsset(SkinDataEx sdEX, Atlas[] atlasArray) { #if SPINE_TK2D throw new NotImplementedException("GenSkinBySkniDataAsset Not Implemented"); #endif float scale = this.skeletonDataAsset.scale; var attachmentLoader = new AtlasAttachmentLoader(atlasArray); var skin = new Skin(sdEX.SkinName); var linkedMeshes = new List <SkeletonJson.LinkedMesh>(); Attachment attachment = null; foreach (var slot in sdEX.AllSlots) { var slotIndex = skeleton.Data.FindSlotIndex(slot.SlotName); foreach (var entry in slot.AllAttachments) { switch (entry.type) { case AttachmentType.Region: { RegionAttachment region = attachmentLoader.NewRegionAttachment(skin, entry.AttachmentName, entry.PathName); if (region == null) { Debug.LogError("RegionAttachment New Fail:" + entry.AttachmentName + "," + entry.PathName); continue; } region.Path = entry.PathName; #region Region数据的填充 CheckRegionData(entry.FloatValues); Single w = 32, h = 32; foreach (var f in entry.FloatValues) { switch (f.Key) { case "x": region.x = f.FloatValue * scale; break; case "y": region.y = f.FloatValue * scale; break; case "scaleX": region.scaleX = f.FloatValue; break; case "scaleY": region.scaleY = f.FloatValue; break; case "rotation": region.rotation = f.FloatValue; break; case "width": w = f.FloatValue; break; case "height": h = f.FloatValue; break; } } region.width = w * scale; region.height = h * scale; if (entry.ColorValues != null && entry.ColorValues.Count > 0) { foreach (var c in entry.ColorValues) { switch (c.Key) { case "color": region.r = c.ColorValue.r; region.g = c.ColorValue.g; region.b = c.ColorValue.b; region.a = c.ColorValue.a; break; } } } #endregion region.UpdateOffset(); attachment = region; } break; case AttachmentType.Boundingbox: { BoundingBoxAttachment box = attachmentLoader.NewBoundingBoxAttachment(skin, entry.AttachmentName); if (box == null) { Debug.LogError("BoundingBoxAttachment New Fail:" + entry.AttachmentName); continue; } #region Box数据填充 Int32 vertexCount = 0; if (entry.IntValues != null && entry.IntValues.Count > 0) { foreach (var i in entry.IntValues) { if (i.Key.Equals("vertexCount")) { vertexCount = i.IntValue; break; } } } foreach (var fs in entry.FloatArrayValues) { if (fs.Key.Equals("vertices")) { ReadVertices(fs, box, vertexCount << 1, scale); break; } } #endregion attachment = box; } break; case AttachmentType.Mesh: case AttachmentType.Linkedmesh: { MeshAttachment mesh = attachmentLoader.NewMeshAttachment(skin, entry.AttachmentName, entry.PathName); if (mesh == null) { Debug.LogError("MeshAttachment New Fail:" + entry.AttachmentName + "," + entry.PathName); continue; } #region Mesh数据填充 mesh.Path = entry.PathName; if (entry.ColorValues != null && entry.ColorValues.Count > 0) { foreach (var c in entry.ColorValues) { if (c.Key.Equals("color")) { mesh.r = c.ColorValue.r; mesh.g = c.ColorValue.g; mesh.b = c.ColorValue.b; mesh.a = c.ColorValue.a; break; } } } Single w = 0, h = 0; foreach (var f in entry.FloatValues) { switch (f.Key) { case "width": w = f.FloatValue * scale; break; case "height": h = f.FloatValue * scale; break; } } mesh.Width = w; mesh.Height = h; String parentStr = null, skinStr = null; Boolean deform = true; if (entry.StringValues != null && entry.StringValues.Count > 0) { foreach (var ss in entry.StringValues) { switch (ss.Key) { case "parent": parentStr = ss.StringValue; break; case "skin": skinStr = ss.StringValue; break; } } } if (entry.BoolValues != null && entry.BoolValues.Count > 0) { foreach (var b in entry.BoolValues) { if (b.Key.Equals("deform")) { deform = b.BooleanValue; break; } } } if (parentStr != null) { mesh.InheritDeform = deform; linkedMeshes.Add(new SkeletonJson.LinkedMesh(mesh, skinStr, slotIndex, parentStr)); } KeyFloatArrayPair kfap_Vs = new KeyFloatArrayPair(); Single[] uvs = null; foreach (var fs in entry.FloatArrayValues) { switch (fs.Key) { case "vertices": kfap_Vs = fs; break; case "uvs": uvs = fs.FloatArrayValue.ToArray(); break; } } ReadVertices(kfap_Vs, mesh, uvs.Length, scale); Int32[] triangles = null, edges = null; if (entry.IntArrayValues != null && entry.IntArrayValues.Count > 0) { foreach (var i32s in entry.IntArrayValues) { switch (i32s.Key) { case "triangles": triangles = i32s.IntArrayValue.ToArray(); break; case "edges": edges = i32s.IntArrayValue.ToArray(); break; } } } mesh.triangles = triangles; mesh.regionUVs = uvs; mesh.UpdateUVs(); Int32 hull = 0; if (entry.IntValues != null && entry.IntValues.Count > 0) { foreach (var i in entry.IntValues) { if (i.Key.Equals("hull")) { hull = i.IntValue * 2; break; } } } if (hull != 0) { mesh.HullLength = hull; } if (edges != null) { mesh.Edges = edges; } #endregion attachment = mesh; } break; case AttachmentType.Path: { PathAttachment pathAttachment = attachmentLoader.NewPathAttachment(skin, entry.AttachmentName); if (pathAttachment == null) { Debug.LogError("PathAttachment New Fail:" + entry.AttachmentName); continue; } #region Path填充数据 Boolean closed = false, constantSpeed = false; if (entry.BoolValues != null && entry.BoolValues.Count > 0) { foreach (var b in entry.BoolValues) { switch (b.Key) { case "closed": closed = b.BooleanValue; break; case "constantSpeed": constantSpeed = b.BooleanValue; break; } } } pathAttachment.closed = closed; pathAttachment.constantSpeed = constantSpeed; Int32 vertexCount = 0; if (entry.IntValues != null && entry.IntValues.Count > 0) { foreach (var i in entry.IntValues) { if (i.Key.Equals("vertexCount")) { vertexCount = i.IntValue; break; } } } foreach (var fs in entry.FloatArrayValues) { switch (fs.Key) { case "vertices": ReadVertices(fs, pathAttachment, vertexCount << 1, scale); break; case "lengths": var count = fs.FloatArrayValue.Count; pathAttachment.lengths = new Single[count]; for (var idx = 0; idx < count; idx++) { pathAttachment.lengths[idx] = fs.FloatArrayValue[idx] * scale; } break; } } #endregion attachment = pathAttachment; } break; case AttachmentType.Point: { PointAttachment point = attachmentLoader.NewPointAttachment(skin, entry.AttachmentName); if (point == null) { Debug.LogError("PointAttachment New Fail:" + entry.AttachmentName); continue; } #region Point填充数据 Single x = 0, y = 0, r = 0; if (entry.FloatValues != null && entry.FloatValues.Count > 0) { foreach (var f in entry.FloatValues) { switch (f.Key) { case "x": x = f.FloatValue * scale; break; case "y": y = f.FloatValue * scale; break; case "rotation": r = f.FloatValue; break; } } } point.x = x; point.y = y; point.rotation = r; #endregion attachment = point; } break; case AttachmentType.Clipping: { ClippingAttachment clip = attachmentLoader.NewClippingAttachment(skin, entry.AttachmentName); if (clip == null) { Debug.LogError("ClippingAttachment New Fail:" + entry.AttachmentName); continue; } #region Clipping填充数据 String end = null; if (entry.StringValues != null && entry.StringValues.Count > 0) { foreach (var s in entry.StringValues) { if (s.Key.Equals("end")) { end = s.StringValue; break; } } } if (end != null) { SlotData sd = skeleton.Data.FindSlot(end); if (sd == null) { throw new Exception("Clipping end slot not found: " + end); } clip.EndSlot = sd; } Int32 vertexCount = 0; if (entry.IntValues != null && entry.IntValues.Count > 0) { foreach (var i in entry.IntValues) { if (i.Key.Equals("vertexCount")) { vertexCount = i.IntValue; break; } } } foreach (var fs in entry.FloatArrayValues) { if (fs.Key.Equals("vertices")) { ReadVertices(fs, clip, vertexCount << 1, scale); break; } } #endregion attachment = clip; } break; default: break; } skin.SetAttachment(slot.SlotName, entry.AttachmentName, attachment, skeleton); } } // Linked meshes. for (int i = 0, n = linkedMeshes.Count; i < n; i++) { var linkedMesh = linkedMeshes[i]; Skin sk = linkedMesh.skin == null ? skeleton.Data.defaultSkin : skeleton.Data.FindSkin(linkedMesh.skin); if (sk == null) { throw new Exception("Slot not found: " + linkedMesh.skin); } Attachment parent = sk.GetAttachment(linkedMesh.slotIndex, linkedMesh.parent); if (parent == null) { throw new Exception("Parent mesh not found: " + linkedMesh.parent); } linkedMesh.mesh.ParentMesh = (MeshAttachment)parent; linkedMesh.mesh.UpdateUVs(); } skeleton.Data.Skins.Add(skin); return(skin); }
public static Color GetColor(this RegionAttachment a) { return(new Color(a.R, a.G, a.B, a.A)); }
public static void FillVerts(Skeleton skeleton, int startSlot, int endSlot, float zSpacing, bool pmaColors, Vector3[] verts, Vector2[] uvs, Color32[] colors, ref int vertexIndex, ref float[] tempVertBuffer, ref Vector3 boundsMin, ref Vector3 boundsMax, bool renderMeshes = true) { Color32 color = new Color32(0, 0, 0, 0); Slot[] items = skeleton.DrawOrder.Items; float num = skeleton.a * 255f; float r = skeleton.r; float g = skeleton.g; float b = skeleton.b; int num2 = vertexIndex; float[] array = tempVertBuffer; Vector3 vector = boundsMin; Vector3 vector2 = boundsMax; for (int i = startSlot; i < endSlot; i++) { Slot slot = items[i]; Attachment attachment = slot.attachment; float z = (float)i * zSpacing; RegionAttachment regionAttachment = attachment as RegionAttachment; if (regionAttachment != null) { regionAttachment.ComputeWorldVertices(slot.bone, array); float num3 = array[0]; float num4 = array[1]; float num5 = array[2]; float num6 = array[3]; float num7 = array[4]; float num8 = array[5]; float num9 = array[6]; float num10 = array[7]; verts[num2].x = num3; verts[num2].y = num4; verts[num2].z = z; verts[num2 + 1].x = num9; verts[num2 + 1].y = num10; verts[num2 + 1].z = z; verts[num2 + 2].x = num5; verts[num2 + 2].y = num6; verts[num2 + 2].z = z; verts[num2 + 3].x = num7; verts[num2 + 3].y = num8; verts[num2 + 3].z = z; if (pmaColors) { color.a = (byte)(num * slot.a * regionAttachment.a); color.r = (byte)(r * slot.r * regionAttachment.r * (float)color.a); color.g = (byte)(g * slot.g * regionAttachment.g * (float)color.a); color.b = (byte)(b * slot.b * regionAttachment.b * (float)color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } } else { color.a = (byte)(num * slot.a * regionAttachment.a); color.r = (byte)(r * slot.r * regionAttachment.r * 255f); color.g = (byte)(g * slot.g * regionAttachment.g * 255f); color.b = (byte)(b * slot.b * regionAttachment.b * 255f); } colors[num2] = color; colors[num2 + 1] = color; colors[num2 + 2] = color; colors[num2 + 3] = color; float[] uvs2 = regionAttachment.uvs; uvs[num2].x = uvs2[0]; uvs[num2].y = uvs2[1]; uvs[num2 + 1].x = uvs2[6]; uvs[num2 + 1].y = uvs2[7]; uvs[num2 + 2].x = uvs2[2]; uvs[num2 + 2].y = uvs2[3]; uvs[num2 + 3].x = uvs2[4]; uvs[num2 + 3].y = uvs2[5]; if (num3 < vector.x) { vector.x = num3; } else if (num3 > vector2.x) { vector2.x = num3; } if (num5 < vector.x) { vector.x = num5; } else if (num5 > vector2.x) { vector2.x = num5; } if (num7 < vector.x) { vector.x = num7; } else if (num7 > vector2.x) { vector2.x = num7; } if (num9 < vector.x) { vector.x = num9; } else if (num9 > vector2.x) { vector2.x = num9; } if (num4 < vector.y) { vector.y = num4; } else if (num4 > vector2.y) { vector2.y = num4; } if (num6 < vector.y) { vector.y = num6; } else if (num6 > vector2.y) { vector2.y = num6; } if (num8 < vector.y) { vector.y = num8; } else if (num8 > vector2.y) { vector2.y = num8; } if (num10 < vector.y) { vector.y = num10; } else if (num10 > vector2.y) { vector2.y = num10; } num2 += 4; } else if (renderMeshes) { MeshAttachment meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { int worldVerticesLength = meshAttachment.worldVerticesLength; if (array.Length < worldVerticesLength) { array = new float[worldVerticesLength]; } meshAttachment.ComputeWorldVertices(slot, array); if (pmaColors) { color.a = (byte)(num * slot.a * meshAttachment.a); color.r = (byte)(r * slot.r * meshAttachment.r * (float)color.a); color.g = (byte)(g * slot.g * meshAttachment.g * (float)color.a); color.b = (byte)(b * slot.b * meshAttachment.b * (float)color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } } else { color.a = (byte)(num * slot.a * meshAttachment.a); color.r = (byte)(r * slot.r * meshAttachment.r * 255f); color.g = (byte)(g * slot.g * meshAttachment.g * 255f); color.b = (byte)(b * slot.b * meshAttachment.b * 255f); } float[] uvs3 = meshAttachment.uvs; for (int j = 0; j < worldVerticesLength; j += 2) { float num11 = array[j]; float num12 = array[j + 1]; verts[num2].x = num11; verts[num2].y = num12; verts[num2].z = z; colors[num2] = color; uvs[num2].x = uvs3[j]; uvs[num2].y = uvs3[j + 1]; if (num11 < vector.x) { vector.x = num11; } else if (num11 > vector2.x) { vector2.x = num11; } if (num12 < vector.y) { vector.y = num12; } else if (num12 > vector2.y) { vector2.y = num12; } num2++; } } } } vertexIndex = num2; tempVertBuffer = array; boundsMin = vector; boundsMax = vector2; }
public virtual void LateUpdate() { if (!valid || meshRender == null) { 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(); } meshRender.sharedMaterials = sharedMaterials; #if UNITY_EDITOR for (int i = 0; i < meshRender.sharedMaterials.Length; ++i) { meshRender.sharedMaterials[i].shader = Shader.Find(meshRender.sharedMaterial.shader.name); } #endif // Ensure mesh data is the right size. Vector3[] vertices = this.vertices; bool newTriangles = vertexCount > vertices.Length; if (newTriangles) { // Not enough vertices, increase size. this.vertices = vertices = new Vector3[vertexCount]; this.colors = new Color32[vertexCount]; this.uvs = new Vector2[vertexCount]; mesh1.Clear(); mesh2.Clear(); } else { // Too many vertices, zero the extra. Vector3 zero = Vector3.zero; for (int i = vertexCount, n = lastVertexCount; i < n; i++) { vertices[i] = zero; } } lastVertexCount = vertexCount; // Setup mesh. float[] tempVertices = this.tempVertices; Vector2[] uvs = this.uvs; Color32[] colors = this.colors; int vertexIndex = 0; Color32 color = new Color32(); float zSpacing = this.zSpacing; float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b; for (int i = 0; i < drawOrderCount; i++) { Slot slot = drawOrder[i]; Attachment attachment = slot.attachment; if (attachment is RegionAttachment) { RegionAttachment regionAttachment = (RegionAttachment)attachment; regionAttachment.ComputeWorldVertices(slot.bone, tempVertices); float z = i * zSpacing; vertices[vertexIndex] = new Vector3(tempVertices[RegionAttachment.X1], tempVertices[RegionAttachment.Y1], z); vertices[vertexIndex + 1] = new Vector3(tempVertices[RegionAttachment.X4], tempVertices[RegionAttachment.Y4], z); vertices[vertexIndex + 2] = new Vector3(tempVertices[RegionAttachment.X2], tempVertices[RegionAttachment.Y2], z); vertices[vertexIndex + 3] = new Vector3(tempVertices[RegionAttachment.X3], tempVertices[RegionAttachment.Y3], z); color.a = (byte)(a * slot.a * regionAttachment.a); color.r = (byte)(r * slot.r * regionAttachment.r * color.a); color.g = (byte)(g * slot.g * regionAttachment.g * color.a); color.b = (byte)(b * slot.b * regionAttachment.b * color.a); if (slot.data.additiveBlending) { color.a = 0; } colors[vertexIndex] = color; colors[vertexIndex + 1] = color; colors[vertexIndex + 2] = color; colors[vertexIndex + 3] = color; float[] regionUVs = regionAttachment.uvs; uvs[vertexIndex] = new Vector2(regionUVs[RegionAttachment.X1], regionUVs[RegionAttachment.Y1]); uvs[vertexIndex + 1] = new Vector2(regionUVs[RegionAttachment.X4], regionUVs[RegionAttachment.Y4]); uvs[vertexIndex + 2] = new Vector2(regionUVs[RegionAttachment.X2], regionUVs[RegionAttachment.Y2]); uvs[vertexIndex + 3] = new Vector2(regionUVs[RegionAttachment.X3], regionUVs[RegionAttachment.Y3]); vertexIndex += 4; } else { if (!renderMeshes) { continue; } if (attachment is MeshAttachment) { MeshAttachment meshAttachment = (MeshAttachment)attachment; int meshVertexCount = meshAttachment.vertices.Length; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } meshAttachment.ComputeWorldVertices(slot, tempVertices); color.a = (byte)(a * slot.a * meshAttachment.a); color.r = (byte)(r * slot.r * meshAttachment.r * color.a); color.g = (byte)(g * slot.g * meshAttachment.g * color.a); color.b = (byte)(b * slot.b * meshAttachment.b * color.a); if (slot.data.additiveBlending) { color.a = 0; } float[] meshUVs = meshAttachment.uvs; float z = i * zSpacing; for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z); colors[vertexIndex] = color; uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]); } } else if (attachment is SkinnedMeshAttachment) { SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment; int meshVertexCount = meshAttachment.uvs.Length; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } meshAttachment.ComputeWorldVertices(slot, tempVertices); color.a = (byte)(a * slot.a * meshAttachment.a); color.r = (byte)(r * slot.r * meshAttachment.r * color.a); color.g = (byte)(g * slot.g * meshAttachment.g * color.a); color.b = (byte)(b * slot.b * meshAttachment.b * color.a); if (slot.data.additiveBlending) { color.a = 0; } float[] meshUVs = meshAttachment.uvs; float z = i * zSpacing; for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z); colors[vertexIndex] = color; uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]); } } } } // Double buffer mesh. Mesh mesh = useMesh1 ? mesh1 : mesh2; meshFilter.sharedMesh = mesh; mesh.vertices = vertices; mesh.colors32 = colors; mesh.uv = uvs; int submeshCount = submeshMaterials.Count; mesh.subMeshCount = submeshCount; for (int i = 0; i < submeshCount; ++i) { mesh.SetTriangles(submeshes[i].triangles, i); } mesh.RecalculateBounds(); if (newTriangles && calculateNormals) { Vector3[] normals = new Vector3[vertexCount]; Vector3 normal = new Vector3(0, 0, -1); for (int i = 0; i < vertexCount; i++) { normals[i] = normal; } (useMesh1 ? mesh2 : mesh1).vertices = vertices; // Set other mesh vertices. mesh1.normals = normals; mesh2.normals = normals; if (calculateTangents) { Vector4[] tangents = new Vector4[vertexCount]; Vector3 tangent = new Vector3(0, 0, 1); for (int i = 0; i < vertexCount; i++) { tangents[i] = tangent; } mesh1.tangents = tangents; mesh2.tangents = tangents; } } useMesh1 = !useMesh1; ///如果要替换材质 if (this.controllerMaterialByOut) { for (int i = 0; i < meshRender.sharedMaterials.Length; i++) { var texture = meshRender.sharedMaterials[i].GetTexture("_MainTex"); var alpha_texture = meshRender.sharedMaterials[i].GetTexture("_AlphaTex"); this.repMaterials[i].SetTexture("_MainTex", texture); this.repMaterials[i].SetTexture("_AlphaTex", alpha_texture); } meshRender.sharedMaterials = this.repMaterials; } ///如果在 NGUI 中要动态改层级 if (this.needControllerRenderQueue) { for (int i = 0; i < this.meshRender.sharedMaterials.Length; i++) { this.meshRender.sharedMaterials[i].renderQueue = renderQueue; } } }
public virtual void Update() { if (skeletonDataAsset == null) { Clear(); return; } SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(false); if (skeletonData == null) { Clear(); return; } // Initialize fields. if (skeleton == null || skeleton.Data != skeletonData) { Initialize(); } UpdateSkeleton(Time.deltaTime); // Count quads and submeshes. int quadCount = 0, submeshQuadCount = 0; Material lastMaterial = null; submeshMaterials.Clear(); List <Slot> drawOrder = skeleton.DrawOrder; for (int i = 0, n = drawOrder.Count; i < n; i++) { RegionAttachment regionAttachment = drawOrder[i].Attachment as RegionAttachment; if (regionAttachment == null) { continue; } // Add submesh when material changes. Material material = (Material)regionAttachment.RendererObject; if (lastMaterial != material && lastMaterial != null) { addSubmesh(lastMaterial, quadCount, submeshQuadCount, false); submeshQuadCount = 0; } lastMaterial = material; quadCount++; submeshQuadCount++; } addSubmesh(lastMaterial, quadCount, submeshQuadCount, true); // Set materials. if (submeshMaterials.Count == sharedMaterials.Length) { submeshMaterials.CopyTo(sharedMaterials); } else { sharedMaterials = submeshMaterials.ToArray(); } renderer.sharedMaterials = sharedMaterials; // Double buffer mesh. Mesh mesh = useMesh1 ? mesh1 : mesh2; meshFilter.sharedMesh = mesh; // Ensure mesh data is the right size. Vector3[] vertices = this.vertices; int vertexCount = quadCount * 4; 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[] vertexPositions = this.vertexPositions; Vector2[] uvs = this.uvs; Color32[] colors = this.colors; int vertexIndex = 0; Color32 color = new Color32(); float a = skeleton.A * 255, r = skeleton.R, g = skeleton.G, b = skeleton.B, zSpacing = this.zSpacing; for (int i = 0, n = drawOrder.Count; i < n; i++) { Slot slot = drawOrder[i]; RegionAttachment regionAttachment = slot.Attachment as RegionAttachment; if (regionAttachment == null) { continue; } regionAttachment.ComputeWorldVertices(skeleton.X, skeleton.Y, slot.Bone, vertexPositions); float z = i * zSpacing; vertices[vertexIndex] = new Vector3(vertexPositions[RegionAttachment.X1], vertexPositions[RegionAttachment.Y1], z); vertices[vertexIndex + 1] = new Vector3(vertexPositions[RegionAttachment.X4], vertexPositions[RegionAttachment.Y4], z); vertices[vertexIndex + 2] = new Vector3(vertexPositions[RegionAttachment.X2], vertexPositions[RegionAttachment.Y2], z); vertices[vertexIndex + 3] = new Vector3(vertexPositions[RegionAttachment.X3], vertexPositions[RegionAttachment.Y3], z); color.a = (byte)(a * slot.A); color.r = (byte)(r * slot.R * color.a); color.g = (byte)(g * slot.G * color.a); color.b = (byte)(b * slot.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; } 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].indexes, 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 static Color GetColor(this RegionAttachment a) { return(new Color(a.r, a.g, a.b, a.a)); }
Attachment readAttachment(Skin skin, string attachmentName, bool nonessential) { string name = ReadString(); if (name == "") { name = attachmentName; } int type = Read(); switch ((AttachmentType)type) { case AttachmentType.region: { string path = ReadString(); if (path == "") { path = name; } RegionAttachment region = m_attachmentLoader.NewRegionAttachment(skin, name, path); if (region == null) { return(null); } region.Path = path; region.X = ReadFloat(); region.Y = ReadFloat(); region.ScaleX = ReadFloat(); region.ScaleY = ReadFloat(); region.Rotation = ReadFloat(); region.Width = ReadFloat(); region.Height = ReadFloat(); //Color Color color = ReadColor(); region.R = color.r; region.G = color.g; region.B = color.b; region.A = color.a; region.UpdateOffset(); return(region); } case AttachmentType.boundingbox: { BoundingBoxAttachment box = m_attachmentLoader.NewBoundingBoxAttachment(skin, name); if (box == null) { return(null); } box.Vertices = readFloatArray(); return(box); } case AttachmentType.mesh: { string path = ReadString(); if (path == "") { path = name; } MeshAttachment mesh = m_attachmentLoader.NewMeshAttachment(skin, name, path); if (mesh == null) { return(null); } mesh.Path = path; float[] uvs = readFloatArray(); int[] triangles = readShortArray(); float[] vertices = readFloatArray(); mesh.vertices = vertices; mesh.Triangles = triangles; mesh.regionUVs = uvs; mesh.UpdateUVs(); //Color Color color = ReadColor(); mesh.R = color.r; mesh.G = color.g; mesh.B = color.b; mesh.A = color.a; mesh.HullLength = ReadInt() * 2; if (nonessential) { mesh.Edges = readIntArray(); mesh.Width = ReadFloat(); mesh.Height = ReadFloat(); } return(mesh); } case AttachmentType.skinnedmesh: { string path = ReadString(); if (path == "") { path = name; } SkinnedMeshAttachment mesh = m_attachmentLoader.NewSkinnedMeshAttachment(skin, name, path); if (mesh == null) { return(null); } mesh.Path = path; float[] uvs = readFloatArray(); int[] triangles = readShortArray(); int vertexCount = ReadInt(); List <float> weights = new List <float>(uvs.Length * 3 * 3); List <int> bones = new List <int>(uvs.Length * 3); for (int i = 0; i < vertexCount; i++) { int boneCount = (int)ReadFloat(); bones.Add(boneCount); for (int j = i + boneCount * 4; i < j; i += 4) { bones.Add((int)ReadFloat()); weights.Add(ReadFloat()); weights.Add(ReadFloat()); weights.Add(ReadFloat()); } } mesh.bones = bones.ToArray(); mesh.Weights = weights.ToArray(); mesh.Triangles = triangles; mesh.regionUVs = uvs; mesh.UpdateUVs(); //Color Color color = ReadColor(); mesh.R = color.r; mesh.G = color.g; mesh.B = color.b; mesh.A = color.a; mesh.HullLength = ReadInt() * 2; if (nonessential) { mesh.Edges = readIntArray(); mesh.Width = ReadFloat(); mesh.Height = ReadFloat(); } return(mesh); } } return(null); }
public virtual void LateUpdate() { if (!valid) { return; } // Exit early if there is nothing to render if (!meshRenderer.enabled && submeshRenderers.Length == 0) { return; } // This method caches several .Items arrays. Whenever it does, there should be no mutations done on the overlying ExposedList object. // Count vertices and submesh triangles. int vertexCount = 0; int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0; Material lastMaterial = null; ExposedList <Slot> drawOrder = skeleton.drawOrder; var drawOrderItems = drawOrder.Items; 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; workingAttachments.Clear(true); workingState.UpdateAttachmentCount(drawOrderCount); var workingAttachmentsItems = workingAttachments.Items; var workingFlips = workingState.attachmentsFlipState; var workingFlipsItems = workingState.attachmentsFlipState.Items; 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; var storedFlips = storedState.attachmentsFlipState; var storedFlipsItems = storedFlips.Items; bool mustUpdateMeshStructure = storedState.requiresUpdate || // Force update if the mesh was cleared. (prevents flickering due to incorrect state) drawOrderCount != storedAttachments.Count || // Number of slots changed (when does this happen?) immutableTriangles != storedState.immutableTriangles; // Immutable Triangles flag changed. bool isCustomMaterialsPopulated = customSlotMaterials.Count > 0; for (int i = 0; i < drawOrderCount; i++) { Slot slot = drawOrderItems[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 triangle winding (for lighting?). bool flip = frontFacing && (bone.WorldSignX != bone.WorldSignY); 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) { rendererObject = regionAttachment.RendererObject; attachmentVertexCount = 4; attachmentTriangleCount = 6; } else { if (!renderMeshes) { continue; } var meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { rendererObject = meshAttachment.RendererObject; attachmentVertexCount = meshAttachment.vertices.Length >> 1; attachmentTriangleCount = meshAttachment.triangles.Length; } else { var skinnedMeshAttachment = attachment as WeightedMeshAttachment; 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; // For no customSlotMaterials Material material; if (isCustomMaterialsPopulated) { if (!customSlotMaterials.TryGetValue(slot, out material)) { material = (Material)((AtlasRegion)rendererObject).page.rendererObject; } } else { 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 ((vertexCount > 0 && 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(); var workingSubmeshArgumentsItems = workingSubmeshArguments.Items; for (int i = 0, n = workingSubmeshArguments.Count; i < n; i++) { AddSubmesh(workingSubmeshArgumentsItems[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 = drawOrderItems[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 { WeightedMeshAttachment weightedMeshAttachment = attachment as WeightedMeshAttachment; if (weightedMeshAttachment != null) { int meshVertexCount = weightedMeshAttachment.uvs.Length; if (tempVertices.Length < meshVertexCount) { this.tempVertices = tempVertices = new float[meshVertexCount]; } weightedMeshAttachment.ComputeWorldVertices(slot, tempVertices); color.a = (byte)(a * slot.a * weightedMeshAttachment.a); color.r = (byte)(r * slot.r * weightedMeshAttachment.r * color.a); color.g = (byte)(g * slot.g * weightedMeshAttachment.g * color.a); color.b = (byte)(b * slot.b * weightedMeshAttachment.b * color.a); if (slot.data.blendMode == BlendMode.additive) { color.a = 0; } float[] meshUVs = weightedMeshAttachment.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]; Vector4 tangent = new Vector4(1, 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; }
public void Update() { // Clear fields if missing information to render. if (skeletonDataAsset == null || skeletonDataAsset.GetSkeletonData(false) == null) { Clear(); return; } // Initialize fields. if (skeleton == null || skeleton.Data != skeletonDataAsset.GetSkeletonData(false)) { Initialize(); } // Keep AnimationState in sync with animationName and loop fields. if (animationName == null && state.Animation != null) { state.ClearAnimation(); } else if (state.Animation == null || animationName != state.Animation.Name) { Spine.Animation animation = skeleton.Data.FindAnimation(animationName); if (animation != null) { state.SetAnimation(animation, loop); } } state.Loop = loop; UpdateAnimation(); // Count quads. int quadCount = 0; List <Slot> drawOrder = skeleton.DrawOrder; for (int i = 0, n = drawOrder.Count; i < n; i++) { Slot slot = drawOrder[i]; Attachment attachment = slot.Attachment; if (attachment is RegionAttachment) { quadCount++; } } // Ensure mesh data is the right size. if (quadCount != this.quadCount) { this.quadCount = quadCount; vertices = new Vector3[quadCount * 4]; uvs = new Vector2[quadCount * 4]; triangles = new int[quadCount * 6]; } // Setup mesh. int quadIndex = 0; 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; regionAttachment.UpdateVertices(slot.Bone); float[] regionVertices = regionAttachment.Vertices; int vertexIndex = quadIndex * 4; vertices[vertexIndex] = new Vector3(regionVertices[RegionAttachment.X1], regionVertices[RegionAttachment.Y1], 0); vertices[vertexIndex + 1] = new Vector3(regionVertices[RegionAttachment.X4], regionVertices[RegionAttachment.Y4], 0); vertices[vertexIndex + 2] = new Vector3(regionVertices[RegionAttachment.X2], regionVertices[RegionAttachment.Y2], 0); vertices[vertexIndex + 3] = new Vector3(regionVertices[RegionAttachment.X3], regionVertices[RegionAttachment.Y3], 0); AtlasRegion region = regionAttachment.Region; if (region.rotate) { uvs[vertexIndex + 1] = new Vector2(region.u, 1 - region.v2); uvs[vertexIndex + 2] = new Vector2(region.u2, 1 - region.v2); uvs[vertexIndex + 3] = new Vector2(region.u, 1 - region.v); uvs[vertexIndex] = new Vector2(region.u2, 1 - region.v); } else { uvs[vertexIndex] = new Vector2(region.u, 1 - region.v2); uvs[vertexIndex + 1] = new Vector2(region.u2, 1 - region.v2); uvs[vertexIndex + 2] = new Vector2(region.u, 1 - region.v); uvs[vertexIndex + 3] = new Vector2(region.u2, 1 - region.v); } int index = quadIndex * 6; triangles[index] = vertexIndex; triangles[index + 1] = vertexIndex + 2; triangles[index + 2] = vertexIndex + 1; triangles[index + 3] = vertexIndex + 2; triangles[index + 4] = vertexIndex + 3; triangles[index + 5] = vertexIndex + 1; quadIndex++; } } mesh.vertices = vertices; mesh.uv = uvs; mesh.triangles = triangles; renderer.sharedMaterial = skeletonDataAsset.atlasAsset.material; }
/// <summary> Sets the scale. Call regionAttachment.UpdateOffset to apply the change.</summary> public static void SetScale(this RegionAttachment regionAttachment, float x, float y) { regionAttachment.scaleX = x; regionAttachment.scaleY = y; }
public void UpdateSkeletonGeometry() { skeletonGeometry.ClearInstances(); BlendState blend; var drawOrder = Skeleton.DrawOrder; var drawOrderItems = Skeleton.DrawOrder.Items; float skeletonR = Skeleton.R, skeletonG = Skeleton.G, skeletonB = Skeleton.B, skeletonA = Skeleton.A; Color color; for (int i = 0, n = drawOrder.Count; i < n; i++) { Slot slot = drawOrderItems[i]; Attachment attachment = slot.Attachment; blend = slot.Data.BlendMode == BlendMode.Additive ? BlendState.Additive : PremultipliedAlpha ? BlendState.AlphaBlend : BlendState.NonPremultiplied; float attachmentColorR, attachmentColorG, attachmentColorB, attachmentColorA; CCTexture2D texture = null; int verticesCount = 0; //float[] vertices = this.vertices; int indicesCount = 0; int[] indices = null; float[] uvs = null; if (attachment is RegionAttachment) { RegionAttachment regionAttachment = (RegionAttachment)attachment; attachmentColorR = regionAttachment.R; attachmentColorG = regionAttachment.G; attachmentColorB = regionAttachment.B; attachmentColorA = regionAttachment.A; AtlasRegion region = (AtlasRegion)regionAttachment.RendererObject; texture = (CCTexture2D)region.page.rendererObject; verticesCount = 4; regionAttachment.ComputeWorldVertices(slot.Bone, vertices, 0, 2); indicesCount = 6; indices = quadTriangles; uvs = regionAttachment.UVs; } else if (attachment is MeshAttachment) { MeshAttachment mesh = (MeshAttachment)attachment; attachmentColorR = mesh.R; attachmentColorG = mesh.G; attachmentColorB = mesh.B; attachmentColorA = mesh.A; AtlasRegion region = (AtlasRegion)mesh.RendererObject; texture = (CCTexture2D)region.page.rendererObject; int vertexCount = mesh.WorldVerticesLength; if (vertices.Length < vertexCount) { vertices = new float[vertexCount]; } verticesCount = vertexCount >> 1; mesh.ComputeWorldVertices(slot, vertices); indicesCount = mesh.Triangles.Length; indices = mesh.Triangles; uvs = mesh.UVs; } else if (attachment is ClippingAttachment) { ClippingAttachment clip = (ClippingAttachment)attachment; clipper.ClipStart(slot, clip); continue; } else { continue; } // calculate color float a = skeletonA * slot.A * attachmentColorA; if (PremultipliedAlpha) { color = new Color( skeletonR * slot.R * attachmentColorR * a, skeletonG * slot.G * attachmentColorG * a, skeletonB * slot.B * attachmentColorB * a, a); } else { color = new Color( skeletonR * slot.R * attachmentColorR, skeletonG * slot.G * attachmentColorG, skeletonB * slot.B * attachmentColorB, a); } //Color darkColor = new Color(); //if (slot.HasSecondColor) //{ // darkColor = new Color(slot.R2 * a, slot.G2 * a, slot.B2 * a); //} //darkColor.A = PremultipliedAlpha ? (byte)255 : (byte)0; // clip if (clipper.IsClipping) { clipper.ClipTriangles(vertices, verticesCount << 1, indices, indicesCount, uvs); vertices = clipper.ClippedVertices.Items; verticesCount = clipper.ClippedVertices.Count >> 1; indices = clipper.ClippedTriangles.Items; indicesCount = clipper.ClippedTriangles.Count; uvs = clipper.ClippedUVs.Items; } if (verticesCount == 0 || indicesCount == 0) { continue; } // submit to batch var item = skeletonGeometry.CreateGeometryInstance(verticesCount, indicesCount); item.InstanceAttributes.BlendState = blend; item.GeometryPacket.Texture = texture; for (int ii = 0, nn = indicesCount; ii < nn; ii++) { item.GeometryPacket.Indicies[ii] = indices[ii]; } var itemVertices = item.GeometryPacket.Vertices; for (int ii = 0, v = 0, nn = verticesCount << 1; v < nn; ii++, v += 2) { itemVertices[ii].Colors = new CCColor4B(color.R, color.G, color.B, color.A); //itemVertices[ii].Colors2 = new CCColor4B(darkColor.R, darkColor.G, darkColor.B, darkColor.A); 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]; } clipper.ClipEnd(slot); } clipper.ClipEnd(); }
/// <summary> Sets the position offset. Call regionAttachment.UpdateOffset to apply the change.</summary> public static void SetPositionOffset(this RegionAttachment regionAttachment, float x, float y) { regionAttachment.x = x; regionAttachment.y = y; }
public virtual void Update() { // Clear fields if missing information to render. if (skeletonDataAsset == null || skeletonDataAsset.GetSkeletonData(false) == null) { Clear(); return; } // Initialize fields. if (skeleton == null || skeleton.Data != skeletonDataAsset.GetSkeletonData(false)) { Initialize(); } UpdateSkeleton(); // Count quads. int quadCount = 0; List <Slot> drawOrder = skeleton.DrawOrder; for (int i = 0, n = drawOrder.Count; i < n; i++) { Slot slot = drawOrder[i]; Attachment attachment = slot.Attachment; if (attachment is RegionAttachment) { quadCount++; } } // Ensure mesh data is the right size. if (quadCount > vertices.Length / 4) { vertices = new Vector3[quadCount * 4]; colors = new Color[quadCount * 4]; uvs = new Vector2[quadCount * 4]; triangles = new int[quadCount * 6]; mesh.Clear(); for (int i = 0, n = quadCount; i < n; i++) { int index = i * 6; int vertexIndex = i * 4; triangles[index] = vertexIndex; triangles[index + 1] = vertexIndex + 2; triangles[index + 2] = vertexIndex + 1; triangles[index + 3] = vertexIndex + 2; triangles[index + 4] = vertexIndex + 3; triangles[index + 5] = vertexIndex + 1; } } else { Vector3 zero = new Vector3(0, 0, 0); for (int i = quadCount * 4, n = vertices.Length; i < n; i++) { vertices[i] = zero; } } // Setup mesh. float[] vertexPositions = this.vertexPositions; int quadIndex = 0; Color color = new Color(); 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; regionAttachment.ComputeVertices(skeleton.X, skeleton.Y, slot.Bone, vertexPositions); int vertexIndex = quadIndex * 4; vertices[vertexIndex] = new Vector3(vertexPositions[RegionAttachment.X1], vertexPositions[RegionAttachment.Y1], 0); vertices[vertexIndex + 1] = new Vector3(vertexPositions[RegionAttachment.X4], vertexPositions[RegionAttachment.Y4], 0); vertices[vertexIndex + 2] = new Vector3(vertexPositions[RegionAttachment.X2], vertexPositions[RegionAttachment.Y2], 0); vertices[vertexIndex + 3] = new Vector3(vertexPositions[RegionAttachment.X3], vertexPositions[RegionAttachment.Y3], 0); color.a = skeleton.A * slot.A; color.r = skeleton.R * slot.R * color.a; color.g = skeleton.G * slot.G * color.a; color.b = skeleton.B * slot.B * color.a; 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], 1 - regionUVs[RegionAttachment.Y1]); uvs[vertexIndex + 1] = new Vector2(regionUVs[RegionAttachment.X4], 1 - regionUVs[RegionAttachment.Y4]); uvs[vertexIndex + 2] = new Vector2(regionUVs[RegionAttachment.X2], 1 - regionUVs[RegionAttachment.Y2]); uvs[vertexIndex + 3] = new Vector2(regionUVs[RegionAttachment.X3], 1 - regionUVs[RegionAttachment.Y3]); quadIndex++; } } mesh.vertices = vertices; mesh.colors = colors; mesh.uv = uvs; mesh.triangles = triangles; renderer.sharedMaterial = skeletonDataAsset.atlasAsset.material; }
/// <summary>Gets the region (image) of a RegionAttachment</summary> public static AtlasRegion GetRegion(this RegionAttachment regionAttachment) { return(regionAttachment.RendererObject as AtlasRegion); }
public void Attach () { var skeletonComponent = GetComponent<ISkeletonComponent>(); var skeletonRenderer = skeletonComponent as SkeletonRenderer; if (skeletonRenderer != null) this.applyPMA = skeletonRenderer.pmaVertexColors; else { var skeletonGraphic = skeletonComponent as SkeletonGraphic; if (skeletonGraphic != null) this.applyPMA = skeletonGraphic.SpineMeshGenerator.PremultiplyVertexColors; } Shader attachmentShader = applyPMA ? Shader.Find(DefaultPMAShader) : Shader.Find(DefaultStraightAlphaShader); attachment = applyPMA ? sprite.ToRegionAttachmentPMAClone(attachmentShader) : sprite.ToRegionAttachment(SpriteAttacher.GetPageFor(sprite.texture, attachmentShader)); skeletonComponent.Skeleton.FindSlot(slot).Attachment = attachment; }