/// <summary>Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose.</summary> /// <param name="x">The horizontal distance between the skeleton origin and the left side of the AABB.</param> /// <param name="y">The vertical distance between the skeleton origin and the bottom side of the AABB.</param> /// <param name="width">The width of the AABB</param> /// <param name="height">The height of the AABB.</param> /// <param name="vertexBuffer">Reference to hold a float[]. May be a null reference. This method will assign it a new float[] with the appropriate size as needed.</param> public void GetBounds(out float x, out float y, out float width, out float height, ref float[] vertexBuffer) { float[] temp = vertexBuffer; temp = temp ?? new float[8]; var drawOrderItems = this.drawOrder.Items; float minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue; for (int i = 0, n = this.drawOrder.Count; i < n; i++) { Slot slot = drawOrderItems[i]; int verticesLength = 0; float[] vertices = null; Attachment attachment = slot.attachment; var regionAttachment = attachment as RegionAttachment; if (regionAttachment != null) { verticesLength = 8; vertices = temp; if (vertices.Length < 8) { vertices = temp = new float[8]; } regionAttachment.ComputeWorldVertices(slot.bone, temp, 0); } else { var meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { MeshAttachment mesh = meshAttachment; verticesLength = mesh.WorldVerticesLength; vertices = temp; if (vertices.Length < verticesLength) { vertices = temp = new float[verticesLength]; } mesh.ComputeWorldVertices(slot, 0, verticesLength, temp, 0); } } if (vertices != null) { for (int ii = 0; ii < verticesLength; ii += 2) { float vx = vertices[ii], vy = vertices[ii + 1]; minX = Math.Min(minX, vx); minY = Math.Min(minY, vy); maxX = Math.Max(maxX, vx); maxY = Math.Max(maxY, vy); } } } x = minX; y = minY; width = maxX - minX; height = maxY - minY; vertexBuffer = temp; }
public MeshAttachment NewMeshAttachment(Skin skin, string name, string path) { AtlasRegion region = FindRegion(path); if (region == null) { throw new ArgumentException(string.Format("Region not found in atlas: {0} (region attachment: {1})", path, name)); } MeshAttachment attachment = new MeshAttachment(name); attachment.RendererObject = region; attachment.RegionU = region.u; attachment.RegionV = region.v; attachment.RegionU2 = region.u2; attachment.RegionV2 = region.v2; attachment.RegionRotate = 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; return(attachment); }
private Attachment ReadAttachment(Stream input, SkeletonData skeletonData, Skin skin, int slotIndex, String attachmentName, bool nonessential) { float scale = Scale; String name = ReadString(input); if (name == null) { name = attachmentName; } AttachmentType type = (AttachmentType)input.ReadByte(); switch (type) { case AttachmentType.Region: { String path = ReadString(input); float rotation = ReadFloat(input); float x = ReadFloat(input); float y = ReadFloat(input); float scaleX = ReadFloat(input); float scaleY = ReadFloat(input); float width = ReadFloat(input); float height = ReadFloat(input); int color = ReadInt(input); if (path == null) { path = name; } RegionAttachment region = attachmentLoader.NewRegionAttachment(skin, name, path); if (region == null) { return(null); } region.Path = path; region.x = x * scale; region.y = y * scale; region.scaleX = scaleX; region.scaleY = scaleY; region.rotation = rotation; region.width = width * scale; region.height = height * scale; region.r = ((color & 0xff000000) >> 24) / 255f; region.g = ((color & 0x00ff0000) >> 16) / 255f; region.b = ((color & 0x0000ff00) >> 8) / 255f; region.a = ((color & 0x000000ff)) / 255f; region.UpdateOffset(); return(region); } case AttachmentType.Boundingbox: { int vertexCount = ReadVarint(input, true); Vertices vertices = ReadVertices(input, vertexCount); if (nonessential) { ReadInt(input); //int color = nonessential ? ReadInt(input) : 0; // Avoid unused local warning. } BoundingBoxAttachment box = attachmentLoader.NewBoundingBoxAttachment(skin, name); if (box == null) { return(null); } box.worldVerticesLength = vertexCount << 1; box.vertices = vertices.vertices; box.bones = vertices.bones; return(box); } case AttachmentType.Mesh: { String path = ReadString(input); int color = ReadInt(input); int vertexCount = ReadVarint(input, true); float[] uvs = ReadFloatArray(input, vertexCount << 1, 1); int[] triangles = ReadShortArray(input); Vertices vertices = ReadVertices(input, vertexCount); int hullLength = ReadVarint(input, true); int[] edges = null; float width = 0, height = 0; if (nonessential) { edges = ReadShortArray(input); width = ReadFloat(input); height = ReadFloat(input); } if (path == null) { path = name; } MeshAttachment mesh = attachmentLoader.NewMeshAttachment(skin, name, path); if (mesh == null) { return(null); } mesh.Path = path; mesh.r = ((color & 0xff000000) >> 24) / 255f; mesh.g = ((color & 0x00ff0000) >> 16) / 255f; mesh.b = ((color & 0x0000ff00) >> 8) / 255f; mesh.a = ((color & 0x000000ff)) / 255f; mesh.bones = vertices.bones; mesh.vertices = vertices.vertices; mesh.WorldVerticesLength = vertexCount << 1; mesh.triangles = triangles; mesh.regionUVs = uvs; mesh.UpdateUVs(); mesh.HullLength = hullLength << 1; if (nonessential) { mesh.Edges = edges; mesh.Width = width * scale; mesh.Height = height * scale; } return(mesh); } case AttachmentType.Linkedmesh: { String path = ReadString(input); int color = ReadInt(input); String skinName = ReadString(input); String parent = ReadString(input); bool inheritDeform = ReadBoolean(input); float width = 0, height = 0; if (nonessential) { width = ReadFloat(input); height = ReadFloat(input); } if (path == null) { path = name; } MeshAttachment mesh = attachmentLoader.NewMeshAttachment(skin, name, path); if (mesh == null) { return(null); } mesh.Path = path; mesh.r = ((color & 0xff000000) >> 24) / 255f; mesh.g = ((color & 0x00ff0000) >> 16) / 255f; mesh.b = ((color & 0x0000ff00) >> 8) / 255f; mesh.a = ((color & 0x000000ff)) / 255f; mesh.inheritDeform = inheritDeform; if (nonessential) { mesh.Width = width * scale; mesh.Height = height * scale; } linkedMeshes.Add(new SkeletonJson.LinkedMesh(mesh, skinName, slotIndex, parent)); return(mesh); } case AttachmentType.Path: { bool closed = ReadBoolean(input); bool constantSpeed = ReadBoolean(input); int vertexCount = ReadVarint(input, true); Vertices vertices = ReadVertices(input, vertexCount); float[] lengths = new float[vertexCount / 3]; for (int i = 0, n = lengths.Length; i < n; i++) { lengths[i] = ReadFloat(input) * scale; } if (nonessential) { ReadInt(input); //int color = nonessential ? ReadInt(input) : 0; } PathAttachment path = attachmentLoader.NewPathAttachment(skin, name); if (path == null) { return(null); } path.closed = closed; path.constantSpeed = constantSpeed; path.worldVerticesLength = vertexCount << 1; path.vertices = vertices.vertices; path.bones = vertices.bones; path.lengths = lengths; return(path); } case AttachmentType.Point: { float rotation = ReadFloat(input); float x = ReadFloat(input); float y = ReadFloat(input); if (nonessential) { ReadInt(input); //int color = nonessential ? ReadInt(input) : 0; } PointAttachment point = attachmentLoader.NewPointAttachment(skin, name); if (point == null) { return(null); } point.x = x * scale; point.y = y * scale; point.rotation = rotation; //if (nonessential) point.color = color; return(point); } case AttachmentType.Clipping: { int endSlotIndex = ReadVarint(input, true); int vertexCount = ReadVarint(input, true); Vertices vertices = ReadVertices(input, vertexCount); if (nonessential) { ReadInt(input); } ClippingAttachment clip = attachmentLoader.NewClippingAttachment(skin, name); if (clip == null) { return(null); } clip.EndSlot = skeletonData.slots.Items[endSlotIndex]; clip.worldVerticesLength = vertexCount << 1; clip.vertices = vertices.vertices; clip.bones = vertices.bones; return(clip); } } return(null); }
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(); if (VertexEffect != null) { VertexEffect.Begin(skeleton); } 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]; if (VertexEffect != null) { VertexEffect.Transform(ref itemVertices[ii]); } } clipper.ClipEnd(slot); } clipper.ClipEnd(); if (VertexEffect != null) { VertexEffect.End(); } }