Merged with Nate's changes

This commit is contained in:
badlogic 2017-03-31 10:25:45 +02:00
commit 1675658f1a
13 changed files with 133 additions and 92 deletions

View File

@ -105,7 +105,7 @@ public class ClippingTest extends ApplicationAdapter {
// -140, 50, // // -140, 50, //
// }); // });
clip.setWorldVerticesLength(8); clip.setWorldVerticesLength(8);
clip.setEnd(skeleton.findSlot("front_hand")); clip.setEndSlot(skeleton.findSlot("front_hand").data.index);
SlotData clipSlotData = new SlotData(skeletonData.getSlots().size, "clip slot", skeletonData.getBones().first()); SlotData clipSlotData = new SlotData(skeletonData.getSlots().size, "clip slot", skeletonData.getBones().first());
skeletonData.getSlots().add(clipSlotData); skeletonData.getSlots().add(clipSlotData);

View File

@ -42,7 +42,7 @@ public class BoneData {
TransformMode transformMode = TransformMode.normal; TransformMode transformMode = TransformMode.normal;
// Nonessential. // Nonessential.
final Color color = new Color(0.61f, 0.61f, 0.61f, 1); final Color color = new Color(0.61f, 0.61f, 0.61f, 1); // 9b9b9bff
/** @param parent May be null. */ /** @param parent May be null. */
public BoneData (int index, String name, BoneData parent) { public BoneData (int index, String name, BoneData parent) {

View File

@ -68,6 +68,7 @@ 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.BoundingBoxAttachment;
import com.esotericsoftware.spine.attachments.ClippingAttachment;
import com.esotericsoftware.spine.attachments.MeshAttachment; import com.esotericsoftware.spine.attachments.MeshAttachment;
import com.esotericsoftware.spine.attachments.PathAttachment; import com.esotericsoftware.spine.attachments.PathAttachment;
import com.esotericsoftware.spine.attachments.PointAttachment; import com.esotericsoftware.spine.attachments.PointAttachment;
@ -377,7 +378,6 @@ public class SkeletonBinary {
region.updateOffset(); region.updateOffset();
return region; return region;
} }
// BOZO! - Binary clip export.
case boundingbox: { case boundingbox: {
int vertexCount = input.readInt(true); int vertexCount = input.readInt(true);
Vertices vertices = readVertices(input, vertexCount); Vertices vertices = readVertices(input, vertexCount);
@ -486,6 +486,21 @@ public class SkeletonBinary {
if (nonessential) Color.rgba8888ToColor(point.getColor(), color); if (nonessential) Color.rgba8888ToColor(point.getColor(), color);
return point; return point;
} }
case clipping: {
int endSlotIndex = input.readInt(true);
int vertexCount = input.readInt(true);
Vertices vertices = readVertices(input, vertexCount);
int color = nonessential ? input.readInt() : 0;
ClippingAttachment clip = attachmentLoader.newClippingAttachment(skin, name);
if (clip == null) return null;
clip.setEndSlot(endSlotIndex);
clip.setWorldVerticesLength(vertexCount << 1);
clip.setVertices(vertices.vertices);
clip.setBones(vertices.bones);
if (nonessential) Color.rgba8888ToColor(clip.getColor(), color);
return clip;
}
} }
return null; return null;
} }

View File

@ -65,6 +65,7 @@ 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.BoundingBoxAttachment;
import com.esotericsoftware.spine.attachments.ClippingAttachment;
import com.esotericsoftware.spine.attachments.MeshAttachment; import com.esotericsoftware.spine.attachments.MeshAttachment;
import com.esotericsoftware.spine.attachments.PathAttachment; import com.esotericsoftware.spine.attachments.PathAttachment;
import com.esotericsoftware.spine.attachments.PointAttachment; import com.esotericsoftware.spine.attachments.PointAttachment;
@ -207,7 +208,7 @@ public class SkeletonJson {
data.local = constraintMap.getBoolean("local", false); data.local = constraintMap.getBoolean("local", false);
data.relative = constraintMap.getBoolean("relative", false); data.relative = constraintMap.getBoolean("relative", false);
data.offsetRotation = constraintMap.getFloat("rotation", 0); data.offsetRotation = constraintMap.getFloat("rotation", 0);
data.offsetX = constraintMap.getFloat("x", 0) * scale; data.offsetX = constraintMap.getFloat("x", 0) * scale;
data.offsetY = constraintMap.getFloat("y", 0) * scale; data.offsetY = constraintMap.getFloat("y", 0) * scale;
@ -261,7 +262,7 @@ public class SkeletonJson {
if (slot == null) throw new SerializationException("Slot not found: " + slotEntry.name); if (slot == null) throw new SerializationException("Slot not found: " + slotEntry.name);
for (JsonValue entry = slotEntry.child; entry != null; entry = entry.next) { for (JsonValue entry = slotEntry.child; entry != null; entry = entry.next) {
try { try {
Attachment attachment = readAttachment(entry, skin, slot.index, entry.name); Attachment attachment = readAttachment(entry, skin, slot.index, entry.name, skeletonData);
if (attachment != null) skin.addAttachment(slot.index, entry.name, attachment); if (attachment != null) skin.addAttachment(slot.index, entry.name, attachment);
} catch (Exception ex) { } catch (Exception ex) {
throw new SerializationException("Error reading attachment: " + entry.name + ", skin: " + skin, ex); throw new SerializationException("Error reading attachment: " + entry.name + ", skin: " + skin, ex);
@ -311,7 +312,7 @@ public class SkeletonJson {
return skeletonData; return skeletonData;
} }
private Attachment readAttachment (JsonValue map, Skin skin, int slotIndex, String name) { private Attachment readAttachment (JsonValue map, Skin skin, int slotIndex, String name, SkeletonData skeletonData) {
float scale = this.scale; float scale = this.scale;
name = map.getString("name", name); name = map.getString("name", name);
@ -337,7 +338,6 @@ public class SkeletonJson {
region.updateOffset(); region.updateOffset();
return region; return region;
} }
// BOZO! - JSON clip export.
case boundingbox: { case boundingbox: {
BoundingBoxAttachment box = attachmentLoader.newBoundingBoxAttachment(skin, name); BoundingBoxAttachment box = attachmentLoader.newBoundingBoxAttachment(skin, name);
if (box == null) return null; if (box == null) return null;
@ -407,6 +407,20 @@ public class SkeletonJson {
if (color != null) point.getColor().set(Color.valueOf(color)); if (color != null) point.getColor().set(Color.valueOf(color));
return point; return point;
} }
case clipping: {
ClippingAttachment clip = attachmentLoader.newClippingAttachment(skin, name);
if (clip == null) return null;
SlotData slot = skeletonData.findSlot(map.getString("end"));
if (slot == null) throw new SerializationException("Slot not found: " + map.getString("end"));
clip.setEndSlot(slot.index);
readVertices(map, clip, map.getInt("vertexCount") << 1);
String color = map.getString("color", null);
if (color != null) clip.getColor().set(Color.valueOf(color));
return clip;
}
} }
return null; return null;
} }

View File

@ -40,6 +40,7 @@ import com.badlogic.gdx.graphics.glutils.ImmediateModeRenderer;
import com.badlogic.gdx.graphics.glutils.ImmediateModeRenderer20; import com.badlogic.gdx.graphics.glutils.ImmediateModeRenderer20;
import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Disposable;
import com.badlogic.gdx.utils.FloatArray; import com.badlogic.gdx.utils.FloatArray;
import com.badlogic.gdx.utils.NumberUtils; import com.badlogic.gdx.utils.NumberUtils;
import com.badlogic.gdx.utils.ShortArray; import com.badlogic.gdx.utils.ShortArray;
@ -52,26 +53,25 @@ import com.esotericsoftware.spine.utils.Clipper;
import com.esotericsoftware.spine.utils.ConvexDecomposer; import com.esotericsoftware.spine.utils.ConvexDecomposer;
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch; import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
public class SkeletonRenderer { public class SkeletonRenderer implements Disposable {
static private final short[] quadTriangles = { 0, 1, 2, 2, 3, 0 }; static private final short[] quadTriangles = {0, 1, 2, 2, 3, 0};
private boolean softwareClipping; private boolean softwareClipping;
private boolean premultipliedAlpha; private boolean premultipliedAlpha;
private final FloatArray vertices = new FloatArray(32); private final FloatArray vertices = new FloatArray(32);
private ClippingAttachment clipAttachment; private ClippingAttachment clipAttachment;
private Slot clipEnd;
private Clipper clipper = new Clipper(); private Clipper clipper = new Clipper();
private ConvexDecomposer decomposer = new ConvexDecomposer(); private ConvexDecomposer decomposer = new ConvexDecomposer();
private FloatArray clippingPolygon = new FloatArray(400); private FloatArray clippingPolygon = new FloatArray(400);
private Array<FloatArray> convexClippingPolygons; private Array<FloatArray> convexClippingPolygons;
private FloatArray clipOutput = new FloatArray(400); private FloatArray clipOutput = new FloatArray(400);
private FloatArray clippedVertices = new FloatArray(400); private FloatArray clippedVertices = new FloatArray(400);
private ShortArray clippedTriangles = new ShortArray(400); private ShortArray clippedTriangles = new ShortArray(400);
private final Matrix4 combinedMatrix = new Matrix4(); private final Matrix4 combinedMatrix = new Matrix4();
private ImmediateModeRenderer renderer; // BOZO! - Dispose. private ImmediateModeRenderer renderer;
public void draw(Batch batch, Skeleton skeleton) { public void draw (Batch batch, Skeleton skeleton) {
boolean premultipliedAlpha = this.premultipliedAlpha; boolean premultipliedAlpha = this.premultipliedAlpha;
float[] vertices = this.vertices.items; float[] vertices = this.vertices.items;
Color skeletonColor = skeleton.color; Color skeletonColor = skeleton.color;
@ -81,14 +81,14 @@ public class SkeletonRenderer {
Slot slot = drawOrder.get(i); Slot slot = drawOrder.get(i);
Attachment attachment = slot.attachment; Attachment attachment = slot.attachment;
if (attachment instanceof RegionAttachment) { if (attachment instanceof RegionAttachment) {
RegionAttachment region = (RegionAttachment) attachment; RegionAttachment region = (RegionAttachment)attachment;
region.computeWorldVertices(slot.getBone(), vertices, 0, 5); region.computeWorldVertices(slot.getBone(), vertices, 0, 5);
Color color = region.getColor(), slotColor = slot.getColor(); Color color = region.getColor(), slotColor = slot.getColor();
float alpha = a * slotColor.a * color.a * 255; float alpha = a * slotColor.a * color.a * 255;
float c = NumberUtils.intToFloatColor(((int) alpha << 24) // float c = NumberUtils.intToFloatColor(((int)alpha << 24) //
| ((int) (b * slotColor.b * color.b * alpha) << 16) // | ((int)(b * slotColor.b * color.b * alpha) << 16) //
| ((int) (g * slotColor.g * color.g * alpha) << 8) // | ((int)(g * slotColor.g * color.g * alpha) << 8) //
| (int) (r * slotColor.r * color.r * alpha)); | (int)(r * slotColor.r * color.r * alpha));
float[] uvs = region.getUVs(); float[] uvs = region.getUVs();
for (int u = 0, v = 2; u < 8; u += 2, v += 5) { for (int u = 0, v = 2; u < 8; u += 2, v += 5) {
vertices[v] = c; vertices[v] = c;
@ -101,7 +101,7 @@ public class SkeletonRenderer {
batch.draw(region.getRegion().getTexture(), vertices, 0, 20); batch.draw(region.getRegion().getTexture(), vertices, 0, 20);
} else if (attachment instanceof ClippingAttachment) { } else if (attachment instanceof ClippingAttachment) {
ClippingAttachment clip = (ClippingAttachment) attachment; ClippingAttachment clip = (ClippingAttachment)attachment;
if (!softwareClipping) batch.end(); if (!softwareClipping) batch.end();
clipStart(batch.getProjectionMatrix(), batch.getTransformMatrix(), slot, clip); clipStart(batch.getProjectionMatrix(), batch.getTransformMatrix(), slot, clip);
if (!softwareClipping) batch.begin(); if (!softwareClipping) batch.begin();
@ -111,7 +111,7 @@ public class SkeletonRenderer {
throw new RuntimeException("SkeletonMeshRenderer is required to render meshes."); throw new RuntimeException("SkeletonMeshRenderer is required to render meshes.");
} else if (attachment instanceof SkeletonAttachment) { } else if (attachment instanceof SkeletonAttachment) {
Skeleton attachmentSkeleton = ((SkeletonAttachment) attachment).getSkeleton(); Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
if (attachmentSkeleton != null) { if (attachmentSkeleton != null) {
Bone bone = slot.getBone(); Bone bone = slot.getBone();
Bone rootBone = attachmentSkeleton.getRootBone(); Bone rootBone = attachmentSkeleton.getRootBone();
@ -137,7 +137,7 @@ public class SkeletonRenderer {
} }
} }
if (slot == clipEnd) { if (clipAttachment != null && i == clipAttachment.getEndSlot()) {
batch.flush(); batch.flush();
clipEnd(); clipEnd();
} }
@ -145,7 +145,7 @@ public class SkeletonRenderer {
} }
@SuppressWarnings("null") @SuppressWarnings("null")
public void draw(PolygonSpriteBatch batch, Skeleton skeleton) { public void draw (PolygonSpriteBatch batch, Skeleton skeleton) {
boolean premultipliedAlpha = this.premultipliedAlpha; boolean premultipliedAlpha = this.premultipliedAlpha;
BlendMode blendMode = null; BlendMode blendMode = null;
int verticesLength = 0; int verticesLength = 0;
@ -154,13 +154,13 @@ public class SkeletonRenderer {
Texture texture = null; Texture texture = null;
Color color = null, skeletonColor = skeleton.color; Color color = null, skeletonColor = skeleton.color;
float r = skeletonColor.r, g = skeletonColor.g, b = skeletonColor.b, a = skeletonColor.a; float r = skeletonColor.r, g = skeletonColor.g, b = skeletonColor.b, a = skeletonColor.a;
Array<Slot> drawOrder = skeleton.drawOrder; Array<Slot> drawOrder = skeleton.drawOrder;
for (int i = 0, n = drawOrder.size; i < n; i++) { for (int i = 0, n = drawOrder.size; i < n; i++) {
final int vertexSize = (softwareClipping && clipAttachment != null) ? 2 : 5; final int vertexSize = (softwareClipping && clipAttachment != null) ? 2 : 5;
Slot slot = drawOrder.get(i); Slot slot = drawOrder.get(i);
Attachment attachment = slot.attachment; Attachment attachment = slot.attachment;
if (attachment instanceof RegionAttachment) { if (attachment instanceof RegionAttachment) {
RegionAttachment region = (RegionAttachment) attachment; RegionAttachment region = (RegionAttachment)attachment;
verticesLength = vertexSize << 2; verticesLength = vertexSize << 2;
vertices = this.vertices.items; vertices = this.vertices.items;
region.computeWorldVertices(slot.getBone(), vertices, 0, vertexSize); region.computeWorldVertices(slot.getBone(), vertices, 0, vertexSize);
@ -170,7 +170,7 @@ public class SkeletonRenderer {
color = region.getColor(); color = region.getColor();
} else if (attachment instanceof MeshAttachment) { } else if (attachment instanceof MeshAttachment) {
MeshAttachment mesh = (MeshAttachment) attachment; MeshAttachment mesh = (MeshAttachment)attachment;
int count = mesh.getWorldVerticesLength(); int count = mesh.getWorldVerticesLength();
verticesLength = (count >> 1) * vertexSize; verticesLength = (count >> 1) * vertexSize;
vertices = this.vertices.setSize(verticesLength); vertices = this.vertices.setSize(verticesLength);
@ -181,14 +181,14 @@ public class SkeletonRenderer {
color = mesh.getColor(); color = mesh.getColor();
} else if (attachment instanceof ClippingAttachment) { } else if (attachment instanceof ClippingAttachment) {
ClippingAttachment clip = (ClippingAttachment) attachment; ClippingAttachment clip = (ClippingAttachment)attachment;
if (!softwareClipping) batch.end(); if (!softwareClipping) batch.end();
clipStart(batch.getProjectionMatrix(), batch.getTransformMatrix(), slot, clip); clipStart(batch.getProjectionMatrix(), batch.getTransformMatrix(), slot, clip);
if (!softwareClipping) batch.begin(); if (!softwareClipping) batch.begin();
continue; continue;
} else if (attachment instanceof SkeletonAttachment) { } else if (attachment instanceof SkeletonAttachment) {
Skeleton attachmentSkeleton = ((SkeletonAttachment) attachment).getSkeleton(); Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
if (attachmentSkeleton != null) { if (attachmentSkeleton != null) {
Bone bone = slot.getBone(); Bone bone = slot.getBone();
Bone rootBone = attachmentSkeleton.getRootBone(); Bone rootBone = attachmentSkeleton.getRootBone();
@ -216,10 +216,10 @@ public class SkeletonRenderer {
if (texture != null) { if (texture != null) {
Color slotColor = slot.getColor(); Color slotColor = slot.getColor();
float alpha = a * slotColor.a * color.a * 255; float alpha = a * slotColor.a * color.a * 255;
float c = NumberUtils.intToFloatColor(((int) alpha << 24) // float c = NumberUtils.intToFloatColor(((int)alpha << 24) //
| ((int) (b * slotColor.b * color.b * alpha) << 16) // | ((int)(b * slotColor.b * color.b * alpha) << 16) //
| ((int) (g * slotColor.g * color.g * alpha) << 8) // | ((int)(g * slotColor.g * color.g * alpha) << 8) //
| (int) (r * slotColor.r * color.r * alpha)); | (int)(r * slotColor.r * color.r * alpha));
BlendMode slotBlendMode = slot.data.getBlendMode(); BlendMode slotBlendMode = slot.data.getBlendMode();
if (slotBlendMode != blendMode) { if (slotBlendMode != blendMode) {
@ -228,8 +228,10 @@ public class SkeletonRenderer {
} }
if (softwareClipping) { if (softwareClipping) {
if (clipAttachment != null) { if (clipAttachment != null) {
clipSoftware(vertices, 0, verticesLength, triangles, 0, triangles.length, uvs, 0, c, false, clippedVertices, clippedTriangles); clipSoftware(vertices, 0, verticesLength, triangles, 0, triangles.length, uvs, 0, c, false, clippedVertices,
batch.draw(texture, clippedVertices.items, 0, clippedVertices.size, clippedTriangles.items, 0, clippedTriangles.size); clippedTriangles);
batch.draw(texture, clippedVertices.items, 0, clippedVertices.size, clippedTriangles.items, 0,
clippedTriangles.size);
} else { } else {
for (int v = 2, u = 0; v < verticesLength; v += 5, u += 2) { for (int v = 2, u = 0; v < verticesLength; v += 5, u += 2) {
vertices[v] = c; vertices[v] = c;
@ -248,7 +250,7 @@ public class SkeletonRenderer {
} }
} }
if (slot == clipEnd) { if (clipAttachment != null && i == clipAttachment.getEndSlot()) {
if (!softwareClipping) batch.flush(); if (!softwareClipping) batch.flush();
clipEnd(); clipEnd();
} }
@ -256,7 +258,7 @@ public class SkeletonRenderer {
} }
@SuppressWarnings("null") @SuppressWarnings("null")
public void draw(TwoColorPolygonBatch batch, Skeleton skeleton) { public void draw (TwoColorPolygonBatch batch, Skeleton skeleton) {
boolean premultipliedAlpha = this.premultipliedAlpha; boolean premultipliedAlpha = this.premultipliedAlpha;
BlendMode blendMode = null; BlendMode blendMode = null;
int verticesLength = 0; int verticesLength = 0;
@ -265,13 +267,13 @@ public class SkeletonRenderer {
Texture texture = null; Texture texture = null;
Color color = null, skeletonColor = skeleton.color; Color color = null, skeletonColor = skeleton.color;
float r = skeletonColor.r, g = skeletonColor.g, b = skeletonColor.b, a = skeletonColor.a; float r = skeletonColor.r, g = skeletonColor.g, b = skeletonColor.b, a = skeletonColor.a;
Array<Slot> drawOrder = skeleton.drawOrder; Array<Slot> drawOrder = skeleton.drawOrder;
for (int i = 0, n = drawOrder.size; i < n; i++) { for (int i = 0, n = drawOrder.size; i < n; i++) {
final int vertexSize = (softwareClipping && clipAttachment != null) ? 2 : 6; final int vertexSize = (softwareClipping && clipAttachment != null) ? 2 : 6;
Slot slot = drawOrder.get(i); Slot slot = drawOrder.get(i);
Attachment attachment = slot.attachment; Attachment attachment = slot.attachment;
if (attachment instanceof RegionAttachment) { if (attachment instanceof RegionAttachment) {
RegionAttachment region = (RegionAttachment) attachment; RegionAttachment region = (RegionAttachment)attachment;
verticesLength = vertexSize << 2; verticesLength = vertexSize << 2;
vertices = this.vertices.items; vertices = this.vertices.items;
region.computeWorldVertices(slot.getBone(), vertices, 0, vertexSize); region.computeWorldVertices(slot.getBone(), vertices, 0, vertexSize);
@ -281,7 +283,7 @@ public class SkeletonRenderer {
color = region.getColor(); color = region.getColor();
} else if (attachment instanceof MeshAttachment) { } else if (attachment instanceof MeshAttachment) {
MeshAttachment mesh = (MeshAttachment) attachment; MeshAttachment mesh = (MeshAttachment)attachment;
int count = mesh.getWorldVerticesLength(); int count = mesh.getWorldVerticesLength();
verticesLength = count * (vertexSize >> 1); verticesLength = count * (vertexSize >> 1);
vertices = this.vertices.setSize(verticesLength); vertices = this.vertices.setSize(verticesLength);
@ -292,14 +294,14 @@ public class SkeletonRenderer {
color = mesh.getColor(); color = mesh.getColor();
} else if (attachment instanceof ClippingAttachment) { } else if (attachment instanceof ClippingAttachment) {
ClippingAttachment clip = (ClippingAttachment) attachment; ClippingAttachment clip = (ClippingAttachment)attachment;
if (!softwareClipping) batch.end(); if (!softwareClipping) batch.end();
clipStart(batch.getProjectionMatrix(), batch.getTransformMatrix(), slot, clip); clipStart(batch.getProjectionMatrix(), batch.getTransformMatrix(), slot, clip);
if (!softwareClipping) batch.begin(); if (!softwareClipping) batch.begin();
continue; continue;
} else if (attachment instanceof SkeletonAttachment) { } else if (attachment instanceof SkeletonAttachment) {
Skeleton attachmentSkeleton = ((SkeletonAttachment) attachment).getSkeleton(); Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
if (attachmentSkeleton != null) { if (attachmentSkeleton != null) {
Bone bone = slot.getBone(); Bone bone = slot.getBone();
Bone rootBone = attachmentSkeleton.getRootBone(); Bone rootBone = attachmentSkeleton.getRootBone();
@ -327,28 +329,29 @@ public class SkeletonRenderer {
if (texture != null) { if (texture != null) {
Color lightColor = slot.getColor(); Color lightColor = slot.getColor();
float alpha = a * lightColor.a * color.a * 255; float alpha = a * lightColor.a * color.a * 255;
float light = NumberUtils.intToFloatColor(((int) alpha << 24) // float light = NumberUtils.intToFloatColor(((int)alpha << 24) //
| ((int) (b * lightColor.b * color.b * alpha) << 16) // | ((int)(b * lightColor.b * color.b * alpha) << 16) //
| ((int) (g * lightColor.g * color.g * alpha) << 8) // | ((int)(g * lightColor.g * color.g * alpha) << 8) //
| (int) (r * lightColor.r * color.r * alpha)); | (int)(r * lightColor.r * color.r * alpha));
Color darkColor = slot.getDarkColor(); Color darkColor = slot.getDarkColor();
if (darkColor == null) if (darkColor == null) darkColor = Color.BLACK;
darkColor = Color.BLACK;
float dark = NumberUtils.intToFloatColor( // float dark = NumberUtils.intToFloatColor( //
((int) (b * darkColor.b * color.b * 255) << 16) // ((int)(b * darkColor.b * color.b * 255) << 16) //
| ((int) (g * darkColor.g * color.g * 255) << 8) // | ((int)(g * darkColor.g * color.g * 255) << 8) //
| (int) (r * darkColor.r * color.r * 255)); | (int)(r * darkColor.r * color.r * 255));
BlendMode slotBlendMode = slot.data.getBlendMode(); BlendMode slotBlendMode = slot.data.getBlendMode();
if (slotBlendMode != blendMode) { if (slotBlendMode != blendMode) {
blendMode = slotBlendMode; blendMode = slotBlendMode;
batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest()); batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest());
} }
if (softwareClipping) { if (softwareClipping) {
if (clipAttachment != null) { if (clipAttachment != null) {
clipSoftware(vertices, 0, verticesLength, triangles, 0, triangles.length, uvs, dark, light, true, clippedVertices, clippedTriangles); clipSoftware(vertices, 0, verticesLength, triangles, 0, triangles.length, uvs, dark, light, true,
batch.draw(texture, clippedVertices.items, 0, clippedVertices.size, clippedTriangles.items, 0, clippedTriangles.size); clippedVertices, clippedTriangles);
batch.draw(texture, clippedVertices.items, 0, clippedVertices.size, clippedTriangles.items, 0,
clippedTriangles.size);
} else { } else {
for (int v = 2, u = 0; v < verticesLength; v += 6, u += 2) { for (int v = 2, u = 0; v < verticesLength; v += 6, u += 2) {
vertices[v] = light; vertices[v] = light;
@ -369,17 +372,16 @@ public class SkeletonRenderer {
} }
} }
if (slot == clipEnd) { if (clipAttachment != null && i == clipAttachment.getEndSlot()) {
if (!softwareClipping) batch.flush(); if (!softwareClipping) batch.flush();
clipEnd(); clipEnd();
} }
} }
} }
private void clipStart(Matrix4 transformMatrix, Matrix4 projectionMatrix, Slot slot, ClippingAttachment clip) { private void clipStart (Matrix4 transformMatrix, Matrix4 projectionMatrix, Slot slot, ClippingAttachment clip) {
if (clipEnd != null) return; if (clipAttachment != null) return;
clipAttachment = clip; clipAttachment = clip;
clipEnd = clip.getEnd();
if (!softwareClipping) { if (!softwareClipping) {
int n = clip.getWorldVerticesLength(); int n = clip.getWorldVerticesLength();
@ -402,7 +404,7 @@ public class SkeletonRenderer {
renderer.end(); renderer.end();
Gdx.gl.glColorMask(true, true, true, true); Gdx.gl.glColorMask(true, true, true, true);
Gdx.gl.glStencilFunc(clip.getInvert() ? GL20.GL_NOTEQUAL : GL20.GL_EQUAL, 1, 1); Gdx.gl.glStencilFunc(false ? GL20.GL_NOTEQUAL : GL20.GL_EQUAL, 1, 1);
Gdx.gl.glStencilOp(GL20.GL_KEEP, GL20.GL_KEEP, GL20.GL_KEEP); Gdx.gl.glStencilOp(GL20.GL_KEEP, GL20.GL_KEEP, GL20.GL_KEEP);
} else { } else {
int n = clip.getWorldVerticesLength(); int n = clip.getWorldVerticesLength();
@ -423,11 +425,12 @@ public class SkeletonRenderer {
clippingPolygon.clear(); clippingPolygon.clear();
convexClippingPolygons = null; convexClippingPolygons = null;
clipAttachment = null; clipAttachment = null;
clipEnd = null;
if (!softwareClipping) Gdx.gl.glDisable(GL20.GL_STENCIL_TEST); if (!softwareClipping) Gdx.gl.glDisable(GL20.GL_STENCIL_TEST);
} }
private void clipSoftware(final float[] vertices, final int offset, final int verticesLength, final short[] triangles, final int triangleOffset, final int trianglesLength, final float uvs[], final float dark, final float light, final boolean twoColor, final FloatArray clippedVertices, final ShortArray clippedTriangles) { private void clipSoftware (final float[] vertices, final int offset, final int verticesLength, final short[] triangles,
final int triangleOffset, final int trianglesLength, final float uvs[], final float dark, final float light,
final boolean twoColor, final FloatArray clippedVertices, final ShortArray clippedTriangles) {
short idx = 0; short idx = 0;
clippedVertices.clear(); clippedVertices.clear();
clippedTriangles.clear(); clippedTriangles.clear();
@ -555,15 +558,19 @@ public class SkeletonRenderer {
} }
} }
public void setPremultipliedAlpha(boolean premultipliedAlpha) { public void setPremultipliedAlpha (boolean premultipliedAlpha) {
this.premultipliedAlpha = premultipliedAlpha; this.premultipliedAlpha = premultipliedAlpha;
} }
public void dispose () {
renderer.dispose();
}
public boolean getSoftwareClipping () { public boolean getSoftwareClipping () {
return softwareClipping; return softwareClipping;
} }
public void setSoftwareClipping(boolean softwareClipping) { public void setSoftwareClipping (boolean softwareClipping) {
this.softwareClipping = softwareClipping; this.softwareClipping = softwareClipping;
} }
} }

View File

@ -50,9 +50,8 @@ public class SkeletonRendererDebug {
static private final Color boneLineColor = Color.RED; static private final Color boneLineColor = Color.RED;
static private final Color boneOriginColor = Color.GREEN; static private final Color boneOriginColor = Color.GREEN;
static private final Color attachmentLineColor = new Color(0, 0, 1, 0.5f); static private final Color attachmentLineColor = new Color(0, 0, 1, 0.5f);
static private final Color triangleLineColor = new Color(1, 0.64f, 0, 0.5f); static private final Color triangleLineColor = new Color(1, 0.64f, 0, 0.5f); // ffa3007f
static private final Color aabbColor = new Color(0, 1, 0, 0.5f); static private final Color aabbColor = new Color(0, 1, 0, 0.5f);
static private final Color clippingLineColor = Color.MAGENTA;
private final ShapeRenderer shapes; private final ShapeRenderer shapes;
private boolean drawBones = true, drawRegionAttachments = true, drawBoundingBoxes = true, drawPoints = true; private boolean drawBones = true, drawRegionAttachments = true, drawBoundingBoxes = true, drawPoints = true;
@ -190,7 +189,7 @@ public class SkeletonRendererDebug {
int nn = clip.getWorldVerticesLength(); int nn = clip.getWorldVerticesLength();
float[] vertices = this.vertices.setSize(nn); float[] vertices = this.vertices.setSize(nn);
clip.computeWorldVertices(slot, 0, nn, vertices, 0, 2); clip.computeWorldVertices(slot, 0, nn, vertices, 0, 2);
shapes.setColor(clippingLineColor); shapes.setColor(clip.getColor());
for (int ii = 2; ii < nn; ii += 2) for (int ii = 2; ii < nn; ii += 2)
shapes.line(vertices[ii - 2], vertices[ii - 1], vertices[ii], vertices[ii + 1]); shapes.line(vertices[ii - 2], vertices[ii - 1], vertices[ii], vertices[ii + 1]);
shapes.line(vertices[0], vertices[1], vertices[nn - 2], vertices[nn - 1]); shapes.line(vertices[0], vertices[1], vertices[nn - 2], vertices[nn - 1]);
@ -296,6 +295,10 @@ public class SkeletonRendererDebug {
public void setPoints (boolean points) { public void setPoints (boolean points) {
this.drawPoints = points; this.drawPoints = points;
} }
public void setClipping (boolean clipping) {
this.drawClipping = clipping;
}
public void setPremultipliedAlpha (boolean premultipliedAlpha) { public void setPremultipliedAlpha (boolean premultipliedAlpha) {
this.premultipliedAlpha = premultipliedAlpha; this.premultipliedAlpha = premultipliedAlpha;

View File

@ -31,7 +31,7 @@
package com.esotericsoftware.spine.attachments; package com.esotericsoftware.spine.attachments;
public enum AttachmentType { public enum AttachmentType {
region, boundingbox, mesh, linkedmesh, path, point; region, boundingbox, mesh, linkedmesh, path, point, clipping;
static public AttachmentType[] values = values(); static public AttachmentType[] values = values();
} }

View File

@ -40,7 +40,7 @@ import com.esotericsoftware.spine.SkeletonBounds;
* Guide. */ * Guide. */
public class BoundingBoxAttachment extends VertexAttachment { public class BoundingBoxAttachment extends VertexAttachment {
// Nonessential. // Nonessential.
final Color color = new Color(0.38f, 0.94f, 0, 1); final Color color = new Color(0.38f, 0.94f, 0, 1); // 60f000ff
public BoundingBoxAttachment (String name) { public BoundingBoxAttachment (String name) {
super(name); super(name);

View File

@ -31,37 +31,25 @@
package com.esotericsoftware.spine.attachments; package com.esotericsoftware.spine.attachments;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.esotericsoftware.spine.Slot;
/** An attachment with vertices that make up a polygon used for clipping the rendering of other attachments. */ /** An attachment with vertices that make up a polygon used for clipping the rendering of other attachments. */
public class ClippingAttachment extends VertexAttachment { public class ClippingAttachment extends VertexAttachment {
Slot end; int endSlot;
boolean invert;
// Nonessential. // Nonessential.
final Color color = new Color(0.38f, 0.94f, 0, 1); final Color color = new Color(0.2275f, 0.2275f, 0.8078f, 1); // ce3a3aff
public ClippingAttachment (String name) { public ClippingAttachment (String name) {
super(name); super(name);
} }
/** Clipping is performed between the clipping polygon's slot and the end slot. */ /** Clipping is performed between the clipping polygon's slot and the end slot. */
public Slot getEnd () { public int getEndSlot () {
return end; return endSlot;
} }
public void setEnd (Slot end) { public void setEndSlot (int slotIndex) {
this.end = end; this.endSlot = slotIndex;
}
/** If false, attachments outside the clipping polygon will be drawn. If true, attachments inside the clipping polygon will be
* drawn. */
public boolean getInvert () {
return invert;
}
public void setInvert (boolean invert) {
this.invert = invert;
} }
/** The color of the clipping polygon as it was in Spine. Available only when nonessential data was exported. Clipping polygons /** The color of the clipping polygon as it was in Spine. Available only when nonessential data was exported. Clipping polygons

View File

@ -41,7 +41,7 @@ public class PathAttachment extends VertexAttachment {
boolean closed, constantSpeed; boolean closed, constantSpeed;
// Nonessential. // Nonessential.
final Color color = new Color(1, 0.5f, 0, 1); final Color color = new Color(1, 0.5f, 0, 1); // ff7f00ff
public PathAttachment (String name) { public PathAttachment (String name) {
super(name); super(name);

View File

@ -45,7 +45,7 @@ public class PointAttachment extends Attachment {
float x, y, rotation; float x, y, rotation;
// Nonessential. // Nonessential.
final Color color = new Color(0.38f, 0.94f, 0, 1); final Color color = new Color(0.9451f, 0.9451f, 0, 1); // f1f100ff
public PointAttachment (String name) { public PointAttachment (String name) {
super(name); super(name);

View File

@ -299,6 +299,7 @@ public class SkeletonViewer extends ApplicationAdapter {
debugRenderer.setMeshTriangles(ui.debugMeshTrianglesCheckbox.isChecked()); debugRenderer.setMeshTriangles(ui.debugMeshTrianglesCheckbox.isChecked());
debugRenderer.setPaths(ui.debugPathsCheckbox.isChecked()); debugRenderer.setPaths(ui.debugPathsCheckbox.isChecked());
debugRenderer.setPoints(ui.debugPointsCheckbox.isChecked()); debugRenderer.setPoints(ui.debugPointsCheckbox.isChecked());
debugRenderer.setClipping(ui.debugClippingCheckbox.isChecked());
debugRenderer.draw(skeleton); debugRenderer.draw(skeleton);
} }
@ -396,6 +397,7 @@ public class SkeletonViewer extends ApplicationAdapter {
CheckBox debugMeshTrianglesCheckbox = new CheckBox("Triangles", skin); CheckBox debugMeshTrianglesCheckbox = new CheckBox("Triangles", skin);
CheckBox debugPathsCheckbox = new CheckBox("Paths", skin); CheckBox debugPathsCheckbox = new CheckBox("Paths", skin);
CheckBox debugPointsCheckbox = new CheckBox("Points", skin); CheckBox debugPointsCheckbox = new CheckBox("Points", skin);
CheckBox debugClippingCheckbox = new CheckBox("Clipping", skin);
Slider scaleSlider = new Slider(0.1f, 3, 0.01f, false, skin); Slider scaleSlider = new Slider(0.1f, 3, 0.01f, false, skin);
Slider zoomSlider = new Slider(0.01f, 10, 0.01f, false, skin); Slider zoomSlider = new Slider(0.01f, 10, 0.01f, false, skin);
Label scaleLabel = new Label("1.0", skin); Label scaleLabel = new Label("1.0", skin);
@ -452,7 +454,7 @@ public class SkeletonViewer extends ApplicationAdapter {
window.setX(-3); window.setX(-3);
window.setY(-2); window.setY(-2);
window.getTitleLabel().setColor(new Color(0.76f, 1, 1, 1)); window.getTitleLabel().setColor(new Color(0xc1ffffff));
window.getTitleTable().add(openButton).space(3); window.getTitleTable().add(openButton).space(3);
window.getTitleTable().add(minimizeButton).width(20); window.getTitleTable().add(minimizeButton).width(20);
@ -486,7 +488,7 @@ public class SkeletonViewer extends ApplicationAdapter {
root.add("Debug:"); root.add("Debug:");
root.add(table(debugBonesCheckbox, debugRegionsCheckbox, debugBoundingBoxesCheckbox)).row(); root.add(table(debugBonesCheckbox, debugRegionsCheckbox, debugBoundingBoxesCheckbox)).row();
root.add(); root.add();
root.add(table(debugPathsCheckbox, debugPointsCheckbox)).row(); root.add(table(debugPathsCheckbox, debugPointsCheckbox, debugClippingCheckbox)).row();
root.add(); root.add();
root.add(table(debugMeshHullCheckbox, debugMeshTrianglesCheckbox)).row(); root.add(table(debugMeshHullCheckbox, debugMeshTrianglesCheckbox)).row();
root.add("Atlas alpha:"); root.add("Atlas alpha:");
@ -784,6 +786,7 @@ public class SkeletonViewer extends ApplicationAdapter {
debugMeshTrianglesCheckbox.addListener(savePrefsListener); debugMeshTrianglesCheckbox.addListener(savePrefsListener);
debugPathsCheckbox.addListener(savePrefsListener); debugPathsCheckbox.addListener(savePrefsListener);
debugPointsCheckbox.addListener(savePrefsListener); debugPointsCheckbox.addListener(savePrefsListener);
debugClippingCheckbox.addListener(savePrefsListener);
premultipliedCheckbox.addListener(savePrefsListener); premultipliedCheckbox.addListener(savePrefsListener);
loopCheckbox.addListener(savePrefsListener); loopCheckbox.addListener(savePrefsListener);
multipleMixingCheckbox.addListener(savePrefsListener); multipleMixingCheckbox.addListener(savePrefsListener);
@ -848,6 +851,7 @@ public class SkeletonViewer extends ApplicationAdapter {
prefs.putBoolean("debugMeshTriangles", debugMeshTrianglesCheckbox.isChecked()); prefs.putBoolean("debugMeshTriangles", debugMeshTrianglesCheckbox.isChecked());
prefs.putBoolean("debugPaths", debugPathsCheckbox.isChecked()); prefs.putBoolean("debugPaths", debugPathsCheckbox.isChecked());
prefs.putBoolean("debugPoints", debugPointsCheckbox.isChecked()); prefs.putBoolean("debugPoints", debugPointsCheckbox.isChecked());
prefs.putBoolean("debugClipping", debugClippingCheckbox.isChecked());
prefs.putBoolean("premultiplied", premultipliedCheckbox.isChecked()); prefs.putBoolean("premultiplied", premultipliedCheckbox.isChecked());
prefs.putBoolean("loop", loopCheckbox.isChecked()); prefs.putBoolean("loop", loopCheckbox.isChecked());
prefs.putBoolean("multipleMixing", multipleMixingCheckbox.isChecked()); prefs.putBoolean("multipleMixing", multipleMixingCheckbox.isChecked());
@ -874,6 +878,7 @@ public class SkeletonViewer extends ApplicationAdapter {
debugMeshTrianglesCheckbox.setChecked(prefs.getBoolean("debugMeshTriangles", false)); debugMeshTrianglesCheckbox.setChecked(prefs.getBoolean("debugMeshTriangles", false));
debugPathsCheckbox.setChecked(prefs.getBoolean("debugPaths", true)); debugPathsCheckbox.setChecked(prefs.getBoolean("debugPaths", true));
debugPointsCheckbox.setChecked(prefs.getBoolean("debugPoints", true)); debugPointsCheckbox.setChecked(prefs.getBoolean("debugPoints", true));
debugClippingCheckbox.setChecked(prefs.getBoolean("debugClipping", true));
premultipliedCheckbox.setChecked(prefs.getBoolean("premultiplied", true)); premultipliedCheckbox.setChecked(prefs.getBoolean("premultiplied", true));
loopCheckbox.setChecked(prefs.getBoolean("loop", false)); loopCheckbox.setChecked(prefs.getBoolean("loop", false));
multipleMixingCheckbox.setChecked(prefs.getBoolean("multipleMixing", false)); multipleMixingCheckbox.setChecked(prefs.getBoolean("multipleMixing", false));

View File

@ -305,9 +305,11 @@ namespace Spine.Unity.Modules.AttachmentTools {
var skinAttachments = o.Attachments; var skinAttachments = o.Attachments;
var newSkin = new Skin(newName); var newSkin = new Skin(newName);
// Use these to detect and use shared regions.
var existingRegions = new Dictionary<AtlasRegion, int>(); var existingRegions = new Dictionary<AtlasRegion, int>();
var regionIndexes = new List<int>(); var regionIndexes = new List<int>();
// Collect all textures from the attachments of the original skin.
var repackedAttachments = new List<Attachment>(); var repackedAttachments = new List<Attachment>();
var texturesToPack = new List<Texture2D>(); var texturesToPack = new List<Texture2D>();
var originalRegions = new List<AtlasRegion>(); var originalRegions = new List<AtlasRegion>();
@ -334,11 +336,13 @@ namespace Spine.Unity.Modules.AttachmentTools {
newSkin.AddAttachment(key.slotIndex, key.name, newAttachment); newSkin.AddAttachment(key.slotIndex, key.name, newAttachment);
} }
// Fill a new texture with the collected attachment textures.
var newTexture = new Texture2D(maxAtlasSize, maxAtlasSize, textureFormat, mipmaps); var newTexture = new Texture2D(maxAtlasSize, maxAtlasSize, textureFormat, mipmaps);
newTexture.anisoLevel = texturesToPack[0].anisoLevel; newTexture.anisoLevel = texturesToPack[0].anisoLevel;
newTexture.name = newName; newTexture.name = newName;
var rects = newTexture.PackTextures(texturesToPack.ToArray(), padding, maxAtlasSize); var rects = newTexture.PackTextures(texturesToPack.ToArray(), padding, maxAtlasSize);
// Rehydrate the repacked textures as a Material, Spine atlas and Spine.AtlasAttachments
var newMaterial = new Material(shader); var newMaterial = new Material(shader);
newMaterial.name = newName; newMaterial.name = newName;
newMaterial.mainTexture = newTexture; newMaterial.mainTexture = newTexture;
@ -352,11 +356,16 @@ namespace Spine.Unity.Modules.AttachmentTools {
repackedRegions.Add(newRegion); repackedRegions.Add(newRegion);
} }
// Map the cloned attachments to the repacked atlas.
for (int i = 0, n = repackedAttachments.Count; i < n; i++) { for (int i = 0, n = repackedAttachments.Count; i < n; i++) {
var a = repackedAttachments[i]; var a = repackedAttachments[i];
a.SetRegion(repackedRegions[regionIndexes[i]]); a.SetRegion(repackedRegions[regionIndexes[i]]);
} }
// Clean up
foreach (var ttp in texturesToPack)
UnityEngine.Object.Destroy(ttp);
t = newTexture; t = newTexture;
m = newMaterial; m = newMaterial;
return newSkin; return newSkin;
@ -706,7 +715,7 @@ namespace Spine.Unity.Modules.AttachmentTools {
ma.hulllength = o.hulllength; ma.hulllength = o.hulllength;
// Nonessential. // Nonessential.
ma.Edges = o.Edges.Clone() as int[]; ma.Edges = (o.Edges == null) ? null : o.Edges.Clone() as int[]; // Allow absence of Edges array when nonessential data is not exported.
ma.Width = o.Width; ma.Width = o.Width;
ma.Height = o.Height; ma.Height = o.Height;
} }