public void Draw(Skeleton skeleton) { var drawOrder = skeleton.DrawOrder; var drawOrderItems = skeleton.DrawOrder.Items; float skeletonR = skeleton.R, skeletonG = skeleton.G, skeletonB = skeleton.B, skeletonA = skeleton.A; Color color = new Color(); for (int i = 0, n = drawOrder.Count; i < n; i++) { Slot slot = drawOrderItems[i]; Attachment attachment = slot.Attachment; float attachmentColorR, attachmentColorG, attachmentColorB, attachmentColorA; Texture2D 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 = (Texture2D)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 = (Texture2D)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; } // set blend state BlendState blendState = new BlendState(); Blend blendSrc; Blend blendDst; if (premultipliedAlpha) { blendState.AlphaBlendFunction = BlendState.AlphaBlend.AlphaBlendFunction; blendState.BlendFactor = BlendState.AlphaBlend.BlendFactor; blendState.ColorBlendFunction = BlendState.AlphaBlend.ColorBlendFunction; blendState.ColorWriteChannels = BlendState.AlphaBlend.ColorWriteChannels; blendState.ColorWriteChannels1 = BlendState.AlphaBlend.ColorWriteChannels1; blendState.ColorWriteChannels2 = BlendState.AlphaBlend.ColorWriteChannels2; blendState.ColorWriteChannels3 = BlendState.AlphaBlend.ColorWriteChannels3; blendState.MultiSampleMask = BlendState.AlphaBlend.MultiSampleMask; } else { blendState.AlphaBlendFunction = BlendState.NonPremultiplied.AlphaBlendFunction; blendState.BlendFactor = BlendState.NonPremultiplied.BlendFactor; blendState.ColorBlendFunction = BlendState.NonPremultiplied.ColorBlendFunction; blendState.ColorWriteChannels = BlendState.NonPremultiplied.ColorWriteChannels; blendState.ColorWriteChannels1 = BlendState.NonPremultiplied.ColorWriteChannels1; blendState.ColorWriteChannels2 = BlendState.NonPremultiplied.ColorWriteChannels2; blendState.ColorWriteChannels3 = BlendState.NonPremultiplied.ColorWriteChannels3; blendState.MultiSampleMask = BlendState.NonPremultiplied.MultiSampleMask; } switch (slot.Data.BlendMode) { case BlendMode.Additive: blendState = BlendState.Additive; break; case BlendMode.Multiply: blendSrc = BlendXna.GetXNABlend(BlendXna.GL_DST_COLOR); blendDst = BlendXna.GetXNABlend(BlendXna.GL_ONE_MINUS_SRC_ALPHA); blendState.ColorSourceBlend = blendSrc; blendState.AlphaSourceBlend = blendSrc; blendState.ColorDestinationBlend = blendDst; blendState.AlphaDestinationBlend = blendDst; break; case BlendMode.Screen: blendSrc = BlendXna.GetXNABlend(premultipliedAlpha ? BlendXna.GL_ONE : BlendXna.GL_SRC_ALPHA); blendDst = BlendXna.GetXNABlend(BlendXna.GL_ONE_MINUS_SRC_COLOR); blendState.ColorSourceBlend = blendSrc; blendState.AlphaSourceBlend = blendSrc; blendState.ColorDestinationBlend = blendDst; blendState.AlphaDestinationBlend = blendDst; break; default: blendState = defaultBlendState; break; } if (device.BlendState != blendState) { End(); device.BlendState = blendState; } // 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) { if (premultipliedAlpha) { darkColor = new Color(slot.R2 * a, slot.G2 * a, slot.B2 * a); } else { 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 MeshItem item = batcher.NextItem(verticesCount, indicesCount); item.texture = texture; for (int ii = 0, nn = indicesCount; ii < nn; ii++) { item.triangles[ii] = indices[ii]; } VertexPositionColorTextureColor[] itemVertices = item.vertices; for (int ii = 0, v = 0, nn = verticesCount << 1; v < nn; ii++, v += 2) { itemVertices[ii].Color = color; itemVertices[ii].Color2 = darkColor; itemVertices[ii].Position.X = vertices[v]; itemVertices[ii].Position.Y = vertices[v + 1]; itemVertices[ii].Position.Z = 0; itemVertices[ii].TextureCoordinate.X = uvs[v]; itemVertices[ii].TextureCoordinate.Y = uvs[v + 1]; } clipper.ClipEnd(slot); } clipper.ClipEnd(); }
float[] ComputeWorldPositions(PathAttachment path, int spacesCount, bool tangents, bool percentPosition, bool percentSpacing) { Slot target = this.target; float position = this.position; float[] spacesItems = this.spaces.Items, output = this.positions.Resize(spacesCount * 3 + 2).Items, world; bool closed = path.Closed; int verticesLength = path.WorldVerticesLength, curveCount = verticesLength / 6, prevCurve = NONE; float pathLength; if (!path.ConstantSpeed) { float[] lengths = path.Lengths; curveCount -= closed ? 1 : 2; pathLength = lengths[curveCount]; if (percentPosition) { position *= pathLength; } if (percentSpacing) { for (int i = 0; i < spacesCount; i++) { spacesItems[i] *= pathLength; } } world = this.world.Resize(8).Items; for (int i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { float space = spacesItems[i]; position += space; float p = position; if (closed) { p %= pathLength; if (p < 0) { p += pathLength; } curve = 0; } else if (p < 0) { if (prevCurve != BEFORE) { prevCurve = BEFORE; path.ComputeWorldVertices(target, 2, 4, world, 0); } AddBeforePosition(p, world, 0, output, o); continue; } else if (p > pathLength) { if (prevCurve != AFTER) { prevCurve = AFTER; path.ComputeWorldVertices(target, verticesLength - 6, 4, world, 0); } AddAfterPosition(p - pathLength, world, 0, output, o); continue; } // Determine curve containing position. for (;; curve++) { float length = lengths[curve]; if (p > length) { continue; } if (curve == 0) { p /= length; } else { float prev = lengths[curve - 1]; p = (p - prev) / (length - prev); } break; } if (curve != prevCurve) { prevCurve = curve; if (closed && curve == curveCount) { path.ComputeWorldVertices(target, verticesLength - 4, 4, world, 0); path.ComputeWorldVertices(target, 0, 4, world, 4); } else { path.ComputeWorldVertices(target, curve * 6 + 2, 8, world, 0); } } AddCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], output, o, tangents || (i > 0 && space < PathConstraint.Epsilon)); } return(output); } // World vertices. if (closed) { verticesLength += 2; world = this.world.Resize(verticesLength).Items; path.ComputeWorldVertices(target, 2, verticesLength - 4, world, 0); path.ComputeWorldVertices(target, 0, 2, world, verticesLength - 4); world[verticesLength - 2] = world[0]; world[verticesLength - 1] = world[1]; } else { curveCount--; verticesLength -= 4; world = this.world.Resize(verticesLength).Items; path.ComputeWorldVertices(target, 2, verticesLength, world, 0); } // Curve lengths. float[] curves = this.curves.Resize(curveCount).Items; pathLength = 0; float x1 = world[0], y1 = world[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0; float tmpx, tmpy, dddfx, dddfy, ddfx, ddfy, dfx, dfy; for (int i = 0, w = 2; i < curveCount; i++, w += 6) { cx1 = world[w]; cy1 = world[w + 1]; cx2 = world[w + 2]; cy2 = world[w + 3]; x2 = world[w + 4]; y2 = world[w + 5]; tmpx = (x1 - cx1 * 2 + cx2) * 0.1875f; tmpy = (y1 - cy1 * 2 + cy2) * 0.1875f; dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375f; dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375f; ddfx = tmpx * 2 + dddfx; ddfy = tmpy * 2 + dddfy; dfx = (cx1 - x1) * 0.75f + tmpx + dddfx * 0.16666667f; dfy = (cy1 - y1) * 0.75f + tmpy + dddfy * 0.16666667f; pathLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); dfx += ddfx; dfy += ddfy; ddfx += dddfx; ddfy += dddfy; pathLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); dfx += ddfx; dfy += ddfy; pathLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); dfx += ddfx + dddfx; dfy += ddfy + dddfy; pathLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); curves[i] = pathLength; x1 = x2; y1 = y2; } if (percentPosition) { position *= pathLength; } if (percentSpacing) { for (int i = 0; i < spacesCount; i++) { spacesItems[i] *= pathLength; } } float[] segments = this.segments; float curveLength = 0; for (int i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { float space = spacesItems[i]; position += space; float p = position; if (closed) { p %= pathLength; if (p < 0) { p += pathLength; } curve = 0; } else if (p < 0) { AddBeforePosition(p, world, 0, output, o); continue; } else if (p > pathLength) { AddAfterPosition(p - pathLength, world, verticesLength - 4, output, o); continue; } // Determine curve containing position. for (;; curve++) { float length = curves[curve]; if (p > length) { continue; } if (curve == 0) { p /= length; } else { float prev = curves[curve - 1]; p = (p - prev) / (length - prev); } break; } // Curve segment lengths. if (curve != prevCurve) { prevCurve = curve; int ii = curve * 6; x1 = world[ii]; y1 = world[ii + 1]; cx1 = world[ii + 2]; cy1 = world[ii + 3]; cx2 = world[ii + 4]; cy2 = world[ii + 5]; x2 = world[ii + 6]; y2 = world[ii + 7]; tmpx = (x1 - cx1 * 2 + cx2) * 0.03f; tmpy = (y1 - cy1 * 2 + cy2) * 0.03f; dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006f; dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006f; ddfx = tmpx * 2 + dddfx; ddfy = tmpy * 2 + dddfy; dfx = (cx1 - x1) * 0.3f + tmpx + dddfx * 0.16666667f; dfy = (cy1 - y1) * 0.3f + tmpy + dddfy * 0.16666667f; curveLength = (float)Math.Sqrt(dfx * dfx + dfy * dfy); segments[0] = curveLength; for (ii = 1; ii < 8; ii++) { dfx += ddfx; dfy += ddfy; ddfx += dddfx; ddfy += dddfy; curveLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); segments[ii] = curveLength; } dfx += ddfx; dfy += ddfy; curveLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); segments[8] = curveLength; dfx += ddfx + dddfx; dfy += ddfy + dddfy; curveLength += (float)Math.Sqrt(dfx * dfx + dfy * dfy); segments[9] = curveLength; segment = 0; } // Weight by segment length. p *= curveLength; for (;; segment++) { float length = segments[segment]; if (p > length) { continue; } if (segment == 0) { p /= length; } else { float prev = segments[segment - 1]; p = segment + (p - prev) / (length - prev); } break; } AddCurvePosition(p * 0.1f, x1, y1, cx1, cy1, cx2, cy2, x2, y2, output, o, tangents || (i > 0 && space < PathConstraint.Epsilon)); } return(output); }