mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +08:00
Bounding box support.
This commit is contained in:
parent
7d7158894d
commit
318a3c8ece
@ -38,6 +38,7 @@ import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
|
|||||||
import com.esotericsoftware.spine.attachments.Attachment;
|
import com.esotericsoftware.spine.attachments.Attachment;
|
||||||
import com.esotericsoftware.spine.attachments.AttachmentLoader;
|
import com.esotericsoftware.spine.attachments.AttachmentLoader;
|
||||||
import com.esotericsoftware.spine.attachments.AttachmentType;
|
import com.esotericsoftware.spine.attachments.AttachmentType;
|
||||||
|
import com.esotericsoftware.spine.attachments.BoundingBoxAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment;
|
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment.Mode;
|
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment.Mode;
|
||||||
@ -187,9 +188,8 @@ public class SkeletonBinary {
|
|||||||
RegionSequenceAttachment regionSequenceAttachment = (RegionSequenceAttachment)attachment;
|
RegionSequenceAttachment regionSequenceAttachment = (RegionSequenceAttachment)attachment;
|
||||||
regionSequenceAttachment.setFrameTime(1 / input.readFloat());
|
regionSequenceAttachment.setFrameTime(1 / input.readFloat());
|
||||||
regionSequenceAttachment.setMode(Mode.values()[input.readInt(true)]);
|
regionSequenceAttachment.setMode(Mode.values()[input.readInt(true)]);
|
||||||
}
|
|
||||||
|
|
||||||
if (attachment instanceof RegionAttachment) {
|
} else if (attachment instanceof RegionAttachment) {
|
||||||
RegionAttachment regionAttachment = (RegionAttachment)attachment;
|
RegionAttachment regionAttachment = (RegionAttachment)attachment;
|
||||||
regionAttachment.setX(input.readFloat() * scale);
|
regionAttachment.setX(input.readFloat() * scale);
|
||||||
regionAttachment.setY(input.readFloat() * scale);
|
regionAttachment.setY(input.readFloat() * scale);
|
||||||
@ -199,6 +199,14 @@ public class SkeletonBinary {
|
|||||||
regionAttachment.setWidth(input.readFloat() * scale);
|
regionAttachment.setWidth(input.readFloat() * scale);
|
||||||
regionAttachment.setHeight(input.readFloat() * scale);
|
regionAttachment.setHeight(input.readFloat() * scale);
|
||||||
regionAttachment.updateOffset();
|
regionAttachment.updateOffset();
|
||||||
|
|
||||||
|
} else if (attachment instanceof BoundingBoxAttachment) {
|
||||||
|
BoundingBoxAttachment box = (BoundingBoxAttachment)attachment;
|
||||||
|
int n = input.readInt(true);
|
||||||
|
float[] points = new float[n];
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
points[i] = input.readFloat();
|
||||||
|
box.setPoints(points);
|
||||||
}
|
}
|
||||||
|
|
||||||
return attachment;
|
return attachment;
|
||||||
|
|||||||
182
spine-libgdx/src/com/esotericsoftware/spine/SkeletonBounds.java
Normal file
182
spine-libgdx/src/com/esotericsoftware/spine/SkeletonBounds.java
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.esotericsoftware.spine.attachments.Attachment;
|
||||||
|
import com.esotericsoftware.spine.attachments.BoundingBoxAttachment;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
|
||||||
|
public class SkeletonBounds {
|
||||||
|
private boolean aabb;
|
||||||
|
private float minX, minY, maxX, maxY;
|
||||||
|
private Array<BoundingBoxAttachment> boundingBoxAttachments = new Array();
|
||||||
|
|
||||||
|
public void update (Skeleton skeleton) {
|
||||||
|
aabb = false;
|
||||||
|
Array<BoundingBoxAttachment> polygons = this.boundingBoxAttachments;
|
||||||
|
polygons.clear();
|
||||||
|
Array<Slot> slots = skeleton.slots;
|
||||||
|
for (int i = 0, n = slots.size; i < n; i++) {
|
||||||
|
Slot slot = slots.get(i);
|
||||||
|
Attachment attachment = slot.attachment;
|
||||||
|
if (attachment instanceof BoundingBoxAttachment) {
|
||||||
|
BoundingBoxAttachment boundingBox = (BoundingBoxAttachment)attachment;
|
||||||
|
boundingBox.updateVertices(slot);
|
||||||
|
polygons.add(boundingBox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void aabbCompute () {
|
||||||
|
float minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE;
|
||||||
|
Array<BoundingBoxAttachment> boundingBoxes = this.boundingBoxAttachments;
|
||||||
|
for (int i = 0, n = boundingBoxes.size; i < n; i++) {
|
||||||
|
float[] vertices = boundingBoxes.get(i).getVertices();
|
||||||
|
for (int ii = 0, nn = vertices.length; ii < nn; ii += 2) {
|
||||||
|
float x = vertices[ii];
|
||||||
|
float y = vertices[ii + 1];
|
||||||
|
minX = Math.min(minX, x);
|
||||||
|
minY = Math.min(minY, y);
|
||||||
|
maxX = Math.max(maxX, x);
|
||||||
|
maxY = Math.max(maxY, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.minX = minX;
|
||||||
|
this.minY = minY;
|
||||||
|
this.maxX = maxX;
|
||||||
|
this.maxY = maxY;
|
||||||
|
aabb = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the axis aligned bounding box contains the point. */
|
||||||
|
public boolean aabbContainsPoint (float x, float y) {
|
||||||
|
if (!aabb) aabbCompute();
|
||||||
|
return x >= minX && x <= maxX && y >= minY && y <= maxY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the axis aligned bounding box intersects the line segment. */
|
||||||
|
public boolean aabbIntersectsSegment (float x1, float y1, float x2, float y2) {
|
||||||
|
if (!aabb) aabbCompute();
|
||||||
|
float minX = this.minX;
|
||||||
|
float minY = this.minY;
|
||||||
|
float maxX = this.maxX;
|
||||||
|
float maxY = this.maxY;
|
||||||
|
if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY))
|
||||||
|
return false;
|
||||||
|
float m = (y2 - y1) / (x2 - x1);
|
||||||
|
float y = m * (minX - x1) + y1;
|
||||||
|
if (y > minY && y < maxY) return true;
|
||||||
|
y = m * (maxX - x1) + y1;
|
||||||
|
if (y > minY && y < maxY) return true;
|
||||||
|
float x = (minY - y1) / m + x1;
|
||||||
|
if (x > minX && x < maxX) return true;
|
||||||
|
x = (maxY - y1) / m + x1;
|
||||||
|
if (x > minX && x < maxX) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */
|
||||||
|
public boolean aabbIntersectsSkeleton (SkeletonBounds bounds) {
|
||||||
|
if (!aabb) aabbCompute();
|
||||||
|
if (!bounds.aabb) bounds.aabbCompute();
|
||||||
|
return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more
|
||||||
|
* efficient to only call this method if {@link #aabbContainsPoint(float, float)} return true. */
|
||||||
|
public BoundingBoxAttachment containsPoint (float x, float y) {
|
||||||
|
Array<BoundingBoxAttachment> boundingBoxes = this.boundingBoxAttachments;
|
||||||
|
for (int i = 0, n = boundingBoxes.size; i < n; i++) {
|
||||||
|
BoundingBoxAttachment attachment = boundingBoxes.get(i);
|
||||||
|
if (containsPoint(attachment, x, y)) return attachment;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the bounding box attachment contains the point. */
|
||||||
|
public boolean containsPoint (BoundingBoxAttachment attachment, float x, float y) {
|
||||||
|
float[] vertices = attachment.getVertices();
|
||||||
|
int nn = vertices.length;
|
||||||
|
int prevIndex = nn - 2;
|
||||||
|
boolean inside = false;
|
||||||
|
for (int ii = 0; ii < nn; ii += 2) {
|
||||||
|
float vertexY = vertices[ii + 1];
|
||||||
|
float prevY = vertices[prevIndex + 1];
|
||||||
|
if (vertexY < y && prevY >= y || prevY < y && vertexY >= y) {
|
||||||
|
float vertexX = vertices[ii];
|
||||||
|
if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside;
|
||||||
|
}
|
||||||
|
prevIndex = ii;
|
||||||
|
}
|
||||||
|
return inside;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually
|
||||||
|
* more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} return true. */
|
||||||
|
public BoundingBoxAttachment intersectsSegment (float x1, float y1, float x2, float y2) {
|
||||||
|
Array<BoundingBoxAttachment> boundingBoxes = this.boundingBoxAttachments;
|
||||||
|
for (int i = 0, n = boundingBoxes.size; i < n; i++) {
|
||||||
|
BoundingBoxAttachment attachment = boundingBoxes.get(i);
|
||||||
|
if (intersectsSegment(attachment, x1, y1, x2, y2)) return attachment;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the bounding box attachment contains the line segment. */
|
||||||
|
public boolean intersectsSegment (BoundingBoxAttachment attachment, float x1, float y1, float x2, float y2) {
|
||||||
|
float[] vertices = attachment.getVertices();
|
||||||
|
float width12 = x1 - x2, height12 = y1 - y2;
|
||||||
|
float det1 = x1 * y2 - y1 * x2;
|
||||||
|
int nn = vertices.length;
|
||||||
|
float x3 = vertices[nn - 2], y3 = vertices[nn - 1];
|
||||||
|
for (int ii = 0; ii < nn; ii += 2) {
|
||||||
|
float x4 = vertices[ii], y4 = vertices[ii + 1];
|
||||||
|
float det2 = x3 * y4 - y3 * x4;
|
||||||
|
float width34 = x3 - x4, height34 = y3 - y4;
|
||||||
|
float det3 = width12 * height34 - height12 * width34;
|
||||||
|
float x = (det1 * width34 - width12 * det2) / det3;
|
||||||
|
if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) {
|
||||||
|
float y = (det1 * height34 - height12 * det2) / det3;
|
||||||
|
if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true;
|
||||||
|
}
|
||||||
|
x3 = x4;
|
||||||
|
y3 = y4;
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMinX () {
|
||||||
|
if (!aabb) aabbCompute();
|
||||||
|
return minX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMinY () {
|
||||||
|
if (!aabb) aabbCompute();
|
||||||
|
return minY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMaxX () {
|
||||||
|
if (!aabb) aabbCompute();
|
||||||
|
return maxX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMaxY () {
|
||||||
|
if (!aabb) aabbCompute();
|
||||||
|
return maxY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getWidth () {
|
||||||
|
if (!aabb) aabbCompute();
|
||||||
|
return maxX - minX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getHeight () {
|
||||||
|
if (!aabb) aabbCompute();
|
||||||
|
return maxY - minY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<BoundingBoxAttachment> getBoundingBoxAttachments () {
|
||||||
|
return boundingBoxAttachments;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -38,6 +38,7 @@ import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
|
|||||||
import com.esotericsoftware.spine.attachments.Attachment;
|
import com.esotericsoftware.spine.attachments.Attachment;
|
||||||
import com.esotericsoftware.spine.attachments.AttachmentLoader;
|
import com.esotericsoftware.spine.attachments.AttachmentLoader;
|
||||||
import com.esotericsoftware.spine.attachments.AttachmentType;
|
import com.esotericsoftware.spine.attachments.AttachmentType;
|
||||||
|
import com.esotericsoftware.spine.attachments.BoundingBoxAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment;
|
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment.Mode;
|
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment.Mode;
|
||||||
@ -172,9 +173,8 @@ public class SkeletonJson {
|
|||||||
|
|
||||||
String modeString = map.getString("mode");
|
String modeString = map.getString("mode");
|
||||||
regionSequenceAttachment.setMode(modeString == null ? Mode.forward : Mode.valueOf(modeString));
|
regionSequenceAttachment.setMode(modeString == null ? Mode.forward : Mode.valueOf(modeString));
|
||||||
}
|
|
||||||
|
|
||||||
if (attachment instanceof RegionAttachment) {
|
} else if (attachment instanceof RegionAttachment) {
|
||||||
RegionAttachment regionAttachment = (RegionAttachment)attachment;
|
RegionAttachment regionAttachment = (RegionAttachment)attachment;
|
||||||
regionAttachment.setX(map.getFloat("x", 0) * scale);
|
regionAttachment.setX(map.getFloat("x", 0) * scale);
|
||||||
regionAttachment.setY(map.getFloat("y", 0) * scale);
|
regionAttachment.setY(map.getFloat("y", 0) * scale);
|
||||||
@ -184,6 +184,15 @@ public class SkeletonJson {
|
|||||||
regionAttachment.setWidth(map.getFloat("width", 32) * scale);
|
regionAttachment.setWidth(map.getFloat("width", 32) * scale);
|
||||||
regionAttachment.setHeight(map.getFloat("height", 32) * scale);
|
regionAttachment.setHeight(map.getFloat("height", 32) * scale);
|
||||||
regionAttachment.updateOffset();
|
regionAttachment.updateOffset();
|
||||||
|
|
||||||
|
} else if (attachment instanceof BoundingBoxAttachment) {
|
||||||
|
BoundingBoxAttachment box = (BoundingBoxAttachment)attachment;
|
||||||
|
JsonValue pointsArray = map.require("points");
|
||||||
|
float[] points = new float[pointsArray.size];
|
||||||
|
int i = 0;
|
||||||
|
for (JsonValue point = pointsArray.child; point != null; point = point.next())
|
||||||
|
points[i++] = point.asFloat();
|
||||||
|
box.setPoints(points);
|
||||||
}
|
}
|
||||||
|
|
||||||
return attachment;
|
return attachment;
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
package com.esotericsoftware.spine;
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
import com.esotericsoftware.spine.attachments.Attachment;
|
import com.esotericsoftware.spine.attachments.Attachment;
|
||||||
|
import com.esotericsoftware.spine.attachments.BoundingBoxAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
|
|
||||||
import static com.badlogic.gdx.graphics.g2d.SpriteBatch.*;
|
import static com.badlogic.gdx.graphics.g2d.SpriteBatch.*;
|
||||||
@ -14,9 +15,15 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
|
|||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
|
||||||
public class SkeletonRendererDebug {
|
public class SkeletonRendererDebug {
|
||||||
static private final Color slotLineColor = new Color(0, 0, 1, 0.5f);
|
static private final Color boneLineColor = Color.RED;
|
||||||
|
static private final Color boneOriginColor = Color.GREEN;
|
||||||
|
static private final Color regionAttachmentLineColor = new Color(0, 0, 1, 0.5f);
|
||||||
|
static private final Color boundingBoxColor = new Color(0, 1, 0, 0.8f);
|
||||||
|
static private final Color aabbColor = new Color(0, 1, 0, 0.5f);
|
||||||
|
|
||||||
private ShapeRenderer renderer;
|
private final ShapeRenderer renderer;
|
||||||
|
private boolean drawBones = true, drawRegionAttachments = true, drawBoundingBoxes = true;
|
||||||
|
private final SkeletonBounds bounds = new SkeletonBounds();
|
||||||
|
|
||||||
public SkeletonRendererDebug () {
|
public SkeletonRendererDebug () {
|
||||||
renderer = new ShapeRenderer();
|
renderer = new ShapeRenderer();
|
||||||
@ -27,47 +34,78 @@ public class SkeletonRendererDebug {
|
|||||||
float skeletonY = skeleton.getY();
|
float skeletonY = skeleton.getY();
|
||||||
|
|
||||||
Gdx.gl.glEnable(GL10.GL_BLEND);
|
Gdx.gl.glEnable(GL10.GL_BLEND);
|
||||||
|
ShapeRenderer renderer = this.renderer;
|
||||||
renderer.begin(ShapeType.Line);
|
renderer.begin(ShapeType.Line);
|
||||||
|
|
||||||
renderer.setColor(Color.RED);
|
|
||||||
Array<Bone> bones = skeleton.getBones();
|
Array<Bone> bones = skeleton.getBones();
|
||||||
for (int i = 0, n = bones.size; i < n; i++) {
|
if (drawBones) {
|
||||||
Bone bone = bones.get(i);
|
renderer.setColor(boneLineColor);
|
||||||
if (bone.parent == null) continue;
|
for (int i = 0, n = bones.size; i < n; i++) {
|
||||||
float x = skeletonX + bone.data.length * bone.m00 + bone.worldX;
|
Bone bone = bones.get(i);
|
||||||
float y = skeletonY + bone.data.length * bone.m10 + bone.worldY;
|
if (bone.parent == null) continue;
|
||||||
renderer.line(skeletonX + bone.worldX, skeletonY + bone.worldY, x, y);
|
float x = skeletonX + bone.data.length * bone.m00 + bone.worldX;
|
||||||
}
|
float y = skeletonY + bone.data.length * bone.m10 + bone.worldY;
|
||||||
|
renderer.line(skeletonX + bone.worldX, skeletonY + bone.worldY, x, y);
|
||||||
renderer.setColor(slotLineColor);
|
|
||||||
Array<Slot> slots = skeleton.getSlots();
|
|
||||||
for (int i = 0, n = slots.size; i < n; i++) {
|
|
||||||
Slot slot = slots.get(i);
|
|
||||||
Attachment attachment = slot.attachment;
|
|
||||||
if (attachment instanceof RegionAttachment) {
|
|
||||||
RegionAttachment regionAttachment = (RegionAttachment)attachment;
|
|
||||||
regionAttachment.updateVertices(slot, false);
|
|
||||||
float[] vertices = regionAttachment.getVertices();
|
|
||||||
renderer.line(vertices[X1], vertices[Y1], vertices[X2], vertices[Y2]);
|
|
||||||
renderer.line(vertices[X2], vertices[Y2], vertices[X3], vertices[Y3]);
|
|
||||||
renderer.line(vertices[X3], vertices[Y3], vertices[X4], vertices[Y4]);
|
|
||||||
renderer.line(vertices[X4], vertices[Y4], vertices[X1], vertices[Y1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.end();
|
if (drawRegionAttachments) {
|
||||||
|
renderer.setColor(regionAttachmentLineColor);
|
||||||
renderer.setColor(Color.GREEN);
|
Array<Slot> slots = skeleton.getSlots();
|
||||||
renderer.begin(ShapeType.Filled);
|
for (int i = 0, n = slots.size; i < n; i++) {
|
||||||
for (int i = 0, n = bones.size; i < n; i++) {
|
Slot slot = slots.get(i);
|
||||||
Bone bone = bones.get(i);
|
Attachment attachment = slot.attachment;
|
||||||
renderer.setColor(Color.GREEN);
|
if (attachment instanceof RegionAttachment) {
|
||||||
renderer.circle(skeletonX + bone.worldX, skeletonY + bone.worldY, 3);
|
RegionAttachment regionAttachment = (RegionAttachment)attachment;
|
||||||
|
regionAttachment.updateVertices(slot, false);
|
||||||
|
float[] vertices = regionAttachment.getVertices();
|
||||||
|
renderer.line(vertices[X1], vertices[Y1], vertices[X2], vertices[Y2]);
|
||||||
|
renderer.line(vertices[X2], vertices[Y2], vertices[X3], vertices[Y3]);
|
||||||
|
renderer.line(vertices[X3], vertices[Y3], vertices[X4], vertices[Y4]);
|
||||||
|
renderer.line(vertices[X4], vertices[Y4], vertices[X1], vertices[Y1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (drawBoundingBoxes) {
|
||||||
|
SkeletonBounds bounds = this.bounds;
|
||||||
|
bounds.update(skeleton);
|
||||||
|
renderer.setColor(aabbColor);
|
||||||
|
renderer.rect(bounds.getMinX(), bounds.getMinY(), bounds.getWidth(), bounds.getHeight());
|
||||||
|
renderer.setColor(boundingBoxColor);
|
||||||
|
Array<BoundingBoxAttachment> boundingBoxes = bounds.getBoundingBoxAttachments();
|
||||||
|
for (int i = 0, n = boundingBoxes.size; i < n; i++)
|
||||||
|
renderer.polygon(boundingBoxes.get(i).getVertices());
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.end();
|
||||||
|
renderer.begin(ShapeType.Filled);
|
||||||
|
|
||||||
|
if (drawBones) {
|
||||||
|
renderer.setColor(boneOriginColor);
|
||||||
|
for (int i = 0, n = bones.size; i < n; i++) {
|
||||||
|
Bone bone = bones.get(i);
|
||||||
|
renderer.setColor(Color.GREEN);
|
||||||
|
renderer.circle(skeletonX + bone.worldX, skeletonY + bone.worldY, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
renderer.end();
|
renderer.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShapeRenderer getShapeRenderer () {
|
public ShapeRenderer getShapeRenderer () {
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBones (boolean bones) {
|
||||||
|
this.drawBones = bones;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegionAttachments (boolean regionAttachments) {
|
||||||
|
this.drawRegionAttachments = regionAttachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBoundingBoxes (boolean boundingBoxes) {
|
||||||
|
this.drawBoundingBoxes = boundingBoxes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,9 +44,11 @@ public class AtlasAttachmentLoader implements AttachmentLoader {
|
|||||||
case region:
|
case region:
|
||||||
attachment = new RegionAttachment(name);
|
attachment = new RegionAttachment(name);
|
||||||
break;
|
break;
|
||||||
case regionSequence:
|
case regionsequence:
|
||||||
attachment = new RegionSequenceAttachment(name);
|
attachment = new RegionSequenceAttachment(name);
|
||||||
break;
|
break;
|
||||||
|
case boundingbox:
|
||||||
|
return new BoundingBoxAttachment(name);
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown attachment type: " + type);
|
throw new IllegalArgumentException("Unknown attachment type: " + type);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,5 +26,5 @@
|
|||||||
package com.esotericsoftware.spine.attachments;
|
package com.esotericsoftware.spine.attachments;
|
||||||
|
|
||||||
public enum AttachmentType {
|
public enum AttachmentType {
|
||||||
region, regionSequence
|
region, regionsequence, boundingbox
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,71 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
package com.esotericsoftware.spine.attachments;
|
||||||
|
|
||||||
|
import com.esotericsoftware.spine.Bone;
|
||||||
|
import com.esotericsoftware.spine.Skeleton;
|
||||||
|
import com.esotericsoftware.spine.Slot;
|
||||||
|
|
||||||
|
public class BoundingBoxAttachment extends Attachment {
|
||||||
|
private float[] points;
|
||||||
|
private float[] vertices;
|
||||||
|
|
||||||
|
public BoundingBoxAttachment (String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateVertices (Slot slot) {
|
||||||
|
Bone bone = slot.getBone();
|
||||||
|
Skeleton skeleton = slot.getSkeleton();
|
||||||
|
float x = bone.getWorldX() + skeleton.getX();
|
||||||
|
float y = bone.getWorldY() + skeleton.getY();
|
||||||
|
float m00 = bone.getM00();
|
||||||
|
float m01 = bone.getM01();
|
||||||
|
float m10 = bone.getM10();
|
||||||
|
float m11 = bone.getM11();
|
||||||
|
float[] vertices = this.vertices;
|
||||||
|
float[] points = this.points;
|
||||||
|
for (int i = 0, n = points.length; i < n; i += 2) {
|
||||||
|
float px = points[i];
|
||||||
|
float py = points[i + 1];
|
||||||
|
vertices[i] = px * m00 + py * m01 + x;
|
||||||
|
vertices[i + 1] = px * m10 + py * m11 + y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float[] getVertices () {
|
||||||
|
return vertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float[] getPoints () {
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPoints (float[] points) {
|
||||||
|
this.points = points;
|
||||||
|
if (vertices == null || vertices.length != points.length) vertices = new float[points.length];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -177,6 +177,10 @@ public class RegionAttachment extends Attachment {
|
|||||||
return vertices;
|
return vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float[] getOffset () {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
public float getX () {
|
public float getX () {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user