Merge branch '3.7-beta' into 3.7-beta-cpp

This commit is contained in:
badlogic 2018-07-03 13:45:19 +02:00
commit fbe0692c4c
12 changed files with 196 additions and 140 deletions

View File

@ -53,7 +53,7 @@ RegionAttachment *AtlasAttachmentLoader::newRegionAttachment(Skin &skin, const S
SP_UNUSED(skin); SP_UNUSED(skin);
AtlasRegion *regionP = findRegion(path); AtlasRegion *regionP = findRegion(path);
assert(regionP != NULL); if (!regionP) return NULL;
AtlasRegion &region = *regionP; AtlasRegion &region = *regionP;
@ -75,7 +75,7 @@ MeshAttachment *AtlasAttachmentLoader::newMeshAttachment(Skin &skin, const Strin
SP_UNUSED(skin); SP_UNUSED(skin);
AtlasRegion *regionP = findRegion(path); AtlasRegion *regionP = findRegion(path);
assert(regionP != NULL); if (!regionP) return NULL;
AtlasRegion &region = *regionP; AtlasRegion &region = *regionP;

View File

@ -506,6 +506,12 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
case AttachmentType_Linkedmesh: { case AttachmentType_Linkedmesh: {
attachment = _attachmentLoader->newMeshAttachment(*skin, attachmentName, attachmentPath); attachment = _attachmentLoader->newMeshAttachment(*skin, attachmentName, attachmentPath);
if (!attachment) {
delete skeletonData;
setError(root, "Error reading attachment: ", skinAttachmentName);
return NULL;
}
MeshAttachment *mesh = static_cast<MeshAttachment *>(attachment); MeshAttachment *mesh = static_cast<MeshAttachment *>(attachment);
mesh->_path = attachmentPath; mesh->_path = attachmentPath;

View File

@ -50,7 +50,7 @@ public class TestHarness extends ApplicationAdapter {
skeleton = new Skeleton(skeletonData); skeleton = new Skeleton(skeletonData);
skeleton.setPosition(320, 590); skeleton.setPosition(320, 590);
skeleton.flipY = true; skeleton.setScaleY(-1);
AnimationStateData stateData = new AnimationStateData(skeletonData); AnimationStateData stateData = new AnimationStateData(skeletonData);
state = new AnimationState(stateData); state = new AnimationState(stateData);

View File

@ -30,13 +30,12 @@
package com.esotericsoftware.spine; package com.esotericsoftware.spine;
import static com.esotericsoftware.spine.utils.SpineUtils.*;
import static com.badlogic.gdx.math.Matrix3.*; import static com.badlogic.gdx.math.Matrix3.*;
import static com.esotericsoftware.spine.utils.SpineUtils.*;
import com.badlogic.gdx.math.Matrix3; import com.badlogic.gdx.math.Matrix3;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import com.esotericsoftware.spine.BoneData.TransformMode;
/** Stores a bone's current pose. /** Stores a bone's current pose.
* <p> * <p>
@ -111,28 +110,14 @@ public class Bone implements Updatable {
Bone parent = this.parent; Bone parent = this.parent;
if (parent == null) { // Root bone. if (parent == null) { // Root bone.
float rotationY = rotation + 90 + shearY;
float la = cosDeg(rotation + shearX) * scaleX;
float lb = cosDeg(rotationY) * scaleY;
float lc = sinDeg(rotation + shearX) * scaleX;
float ld = sinDeg(rotationY) * scaleY;
Skeleton skeleton = this.skeleton; Skeleton skeleton = this.skeleton;
if (skeleton.flipX) { float rotationY = rotation + 90 + shearY, sx = skeleton.scaleX, sy = skeleton.scaleY;
x = -x; a = cosDeg(rotation + shearX) * scaleX * sx;
la = -la; b = cosDeg(rotationY) * scaleY * sy;
lb = -lb; c = sinDeg(rotation + shearX) * scaleX * sx;
} d = sinDeg(rotationY) * scaleY * sy;
if (skeleton.flipY) { worldX = x * sx + skeleton.x;
y = -y; worldY = y * sy + skeleton.y;
lc = -lc;
ld = -ld;
}
a = la;
b = lb;
c = lc;
d = ld;
worldX = x + skeleton.x;
worldY = y + skeleton.y;
return; return;
} }
@ -188,8 +173,8 @@ public class Bone implements Updatable {
case noScale: case noScale:
case noScaleOrReflection: { case noScaleOrReflection: {
float cos = cosDeg(rotation), sin = sinDeg(rotation); float cos = cosDeg(rotation), sin = sinDeg(rotation);
float za = pa * cos + pb * sin; float za = (pa * cos + pb * sin) / skeleton.scaleX;
float zc = pc * cos + pd * sin; float zc = (pc * cos + pd * sin) / skeleton.scaleY;
float s = (float)Math.sqrt(za * za + zc * zc); float s = (float)Math.sqrt(za * za + zc * zc);
if (s > 0.00001f) s = 1 / s; if (s > 0.00001f) s = 1 / s;
za *= s; za *= s;
@ -201,26 +186,18 @@ public class Bone implements Updatable {
float la = cosDeg(shearX) * scaleX; float la = cosDeg(shearX) * scaleX;
float lb = cosDeg(90 + shearY) * scaleY; float lb = cosDeg(90 + shearY) * scaleY;
float lc = sinDeg(shearX) * scaleX; float lc = sinDeg(shearX) * scaleX;
float ld = sinDeg(90 + shearY) * scaleY; float ld = sinDeg(90 + shearY) * scaleY;
if (data.transformMode != TransformMode.noScaleOrReflection ? pa * pd - pb * pc < 0 : skeleton.flipX != skeleton.flipY) {
zb = -zb;
zd = -zd;
}
a = za * la + zb * lc; a = za * la + zb * lc;
b = za * lb + zb * ld; b = za * lb + zb * ld;
c = zc * la + zd * lc; c = zc * la + zd * lc;
d = zc * lb + zd * ld; d = zc * lb + zd * ld;
return; break;
} }
} }
if (skeleton.flipX) { a *= skeleton.scaleX;
a = -a; b *= skeleton.scaleX;
b = -b; c *= skeleton.scaleY;
} d *= skeleton.scaleY;
if (skeleton.flipY) {
c = -c;
d = -d;
}
} }
/** Sets this bone's local transform to the setup pose. */ /** Sets this bone's local transform to the setup pose. */

View File

@ -30,14 +30,14 @@
package com.esotericsoftware.spine; package com.esotericsoftware.spine;
import static com.esotericsoftware.spine.utils.SpineUtils.cosDeg; import static com.esotericsoftware.spine.utils.SpineUtils.*;
import static com.esotericsoftware.spine.utils.SpineUtils.sinDeg;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.FloatArray; import com.badlogic.gdx.utils.FloatArray;
import com.badlogic.gdx.utils.ObjectMap.Entry; import com.badlogic.gdx.utils.ObjectMap.Entry;
import com.esotericsoftware.spine.Skin.Key; import com.esotericsoftware.spine.Skin.Key;
import com.esotericsoftware.spine.attachments.Attachment; import com.esotericsoftware.spine.attachments.Attachment;
import com.esotericsoftware.spine.attachments.MeshAttachment; import com.esotericsoftware.spine.attachments.MeshAttachment;
@ -61,7 +61,7 @@ public class Skeleton {
Skin skin; Skin skin;
final Color color; final Color color;
float time; float time;
boolean flipX, flipY; float scaleX = 1, scaleY = 1;
float x, y; float x, y;
public Skeleton (SkeletonData data) { public Skeleton (SkeletonData data) {
@ -150,8 +150,8 @@ public class Skeleton {
skin = skeleton.skin; skin = skeleton.skin;
color = new Color(skeleton.color); color = new Color(skeleton.color);
time = skeleton.time; time = skeleton.time;
flipX = skeleton.flipX; scaleX = skeleton.scaleX;
flipY = skeleton.flipY; scaleY = skeleton.scaleY;
updateCache(); updateCache();
} }
@ -331,9 +331,9 @@ public class Skeleton {
for (int i = 0, n = updateCache.size; i < n; i++) for (int i = 0, n = updateCache.size; i < n; i++)
updateCache.get(i).update(); updateCache.get(i).update();
} }
/** Updates the world transform for each bone and applies all constraints. The /** Updates the world transform for each bone and applies all constraints. The root bone will be temporarily parented to the
* root bone will be temporarily parented to the specified bone. * specified bone.
* <p> * <p>
* See <a href="http://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine * See <a href="http://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine
* Runtimes Guide. */ * Runtimes Guide. */
@ -353,7 +353,7 @@ public class Skeleton {
bone.ashearY = bone.shearY; bone.ashearY = bone.shearY;
bone.appliedValid = true; bone.appliedValid = true;
} }
// Apply the parent bone transform to the root bone. The root bone // Apply the parent bone transform to the root bone. The root bone
// always inherits scale, rotation and reflection. // always inherits scale, rotation and reflection.
Bone rootBone = getRootBone(); Bone rootBone = getRootBone();
@ -366,20 +366,11 @@ public class Skeleton {
float lb = cosDeg(rotationY) * rootBone.scaleY; float lb = cosDeg(rotationY) * rootBone.scaleY;
float lc = sinDeg(rootBone.rotation + rootBone.shearX) * rootBone.scaleX; float lc = sinDeg(rootBone.rotation + rootBone.shearX) * rootBone.scaleX;
float ld = sinDeg(rotationY) * rootBone.scaleY; float ld = sinDeg(rotationY) * rootBone.scaleY;
rootBone.a = pa * la + pb * lc; rootBone.a = (pa * la + pb * lc) * scaleX;
rootBone.b = pa * lb + pb * ld; rootBone.b = (pa * lb + pb * ld) * scaleX;
rootBone.c = pc * la + pd * lc; rootBone.c = (pc * la + pd * lc) * scaleY;
rootBone.d = pc * lb + pd * ld; rootBone.d = (pc * lb + pd * ld) * scaleY;
if (flipY) {
rootBone.a = -rootBone.a;
rootBone.b = -rootBone.b;
}
if (flipX) {
rootBone.c = -rootBone.c;
rootBone.d = -rootBone.d;
}
// Update everything except root bone. // Update everything except root bone.
Array<Updatable> updateCache = this.updateCache; Array<Updatable> updateCache = this.updateCache;
for (int i = 0, n = updateCache.size; i < n; i++) { for (int i = 0, n = updateCache.size; i < n; i++) {
@ -685,29 +676,29 @@ public class Skeleton {
this.color.set(color); this.color.set(color);
} }
/** If true, the entire skeleton is flipped over the Y axis. This affects all bones, even if the bone's transform mode /** Scales the entire skeleton on the X axis. This affects all bones, even if the bone's transform mode disallows scale
* disallows scale inheritance. */ * inheritance. */
public boolean getFlipX () { public float getScaleX () {
return flipX; return scaleX;
} }
public void setFlipX (boolean flipX) { public void setScaleX (float scaleX) {
this.flipX = flipX; this.scaleX = scaleX;
} }
/** If true, the entire skeleton is flipped over the X axis. This affects all bones, even if the bone's transform mode /** Scales the entire skeleton on the Y axis. This affects all bones, even if the bone's transform mode disallows scale
* disallows scale inheritance. */ * inheritance. */
public boolean getFlipY () { public float getScaleY () {
return flipY; return scaleY;
} }
public void setFlipY (boolean flipY) { public void setScaleY (float scaleY) {
this.flipY = flipY; this.scaleY = scaleY;
} }
public void setFlip (boolean flipX, boolean flipY) { public void setScale (float scaleX, float scaleY) {
this.flipX = flipX; this.scaleX = scaleX;
this.flipY = flipY; this.scaleY = scaleY;
} }
/** Sets the skeleton X position, which is added to the root bone worldX position. */ /** Sets the skeleton X position, which is added to the root bone worldX position. */

View File

@ -70,7 +70,7 @@ public class SkeletonActorPool extends Pool<SkeletonActor> {
protected void reset (Skeleton skeleton) { protected void reset (Skeleton skeleton) {
skeleton.setColor(Color.WHITE); skeleton.setColor(Color.WHITE);
skeleton.setFlip(false, false); skeleton.setScale(1, 1);
skeleton.setSkin((Skin)null); skeleton.setSkin((Skin)null);
skeleton.setSkin(SkeletonActorPool.this.skeletonData.getDefaultSkin()); skeleton.setSkin(SkeletonActorPool.this.skeletonData.getDefaultSkin());
skeleton.setToSetupPose(); skeleton.setToSetupPose();

View File

@ -192,11 +192,11 @@ public class SkeletonViewer extends ApplicationAdapter {
String extension = skeletonFile.extension(); String extension = skeletonFile.extension();
if (extension.equalsIgnoreCase("json") || extension.equalsIgnoreCase("txt")) { if (extension.equalsIgnoreCase("json") || extension.equalsIgnoreCase("txt")) {
SkeletonJson json = new SkeletonJson(atlas); SkeletonJson json = new SkeletonJson(atlas);
json.setScale(ui.scaleSlider.getValue()); json.setScale(ui.loadScaleSlider.getValue());
skeletonData = json.readSkeletonData(skeletonFile); skeletonData = json.readSkeletonData(skeletonFile);
} else { } else {
SkeletonBinary binary = new SkeletonBinary(atlas); SkeletonBinary binary = new SkeletonBinary(atlas);
binary.setScale(ui.scaleSlider.getValue()); binary.setScale(ui.loadScaleSlider.getValue());
skeletonData = binary.readSkeletonData(skeletonFile); skeletonData = binary.readSkeletonData(skeletonFile);
if (skeletonData.getBones().size == 0) throw new Exception("No bones in skeleton data."); if (skeletonData.getBones().size == 0) throw new Exception("No bones in skeleton data.");
} }
@ -311,7 +311,10 @@ public class SkeletonViewer extends ApplicationAdapter {
renderer.setPremultipliedAlpha(ui.premultipliedCheckbox.isChecked()); renderer.setPremultipliedAlpha(ui.premultipliedCheckbox.isChecked());
batch.setPremultipliedAlpha(ui.premultipliedCheckbox.isChecked()); batch.setPremultipliedAlpha(ui.premultipliedCheckbox.isChecked());
skeleton.setFlip(ui.flipXCheckbox.isChecked(), ui.flipYCheckbox.isChecked()); float scaleX = ui.xScaleSlider.getValue(), scaleY = ui.yScaleSlider.getValue();
if (skeleton.scaleX == 0) skeleton.scaleX = 0.01f;
if (skeleton.scaleY == 0) skeleton.scaleY = 0.01f;
skeleton.setScale(scaleX, scaleY);
delta = Math.min(delta, 0.032f) * ui.speedSlider.getValue(); delta = Math.min(delta, 0.032f) * ui.speedSlider.getValue();
skeleton.update(delta); skeleton.update(delta);
@ -412,16 +415,21 @@ public class SkeletonViewer extends ApplicationAdapter {
TextButton openButton = new TextButton("Open", skin); TextButton openButton = new TextButton("Open", skin);
TextButton minimizeButton = new TextButton("-", skin); TextButton minimizeButton = new TextButton("-", skin);
Slider scaleSlider = new Slider(0.1f, 3, 0.01f, false, skin); Slider loadScaleSlider = new Slider(0.1f, 3, 0.01f, false, skin);
Label scaleLabel = new Label("1.0", skin); Label loadScaleLabel = new Label("100%", skin);
TextButton scaleResetButton = new TextButton("Reset", skin); TextButton loadScaleResetButton = new TextButton("Reset", skin);
Slider zoomSlider = new Slider(0.01f, 10, 0.01f, false, skin); Slider zoomSlider = new Slider(0.01f, 10, 0.01f, false, skin);
Label zoomLabel = new Label("1.0", skin); Label zoomLabel = new Label("100%", skin);
TextButton zoomResetButton = new TextButton("Reset", skin); TextButton zoomResetButton = new TextButton("Reset", skin);
CheckBox flipXCheckbox = new CheckBox("X", skin); Slider xScaleSlider = new Slider(-2, 2, 0.01f, false, skin);
CheckBox flipYCheckbox = new CheckBox("Y", skin); Label xScaleLabel = new Label("100%", skin);
TextButton xScaleResetButton = new TextButton("Reset", skin);
Slider yScaleSlider = new Slider(-2, 2, 0.01f, false, skin);
Label yScaleLabel = new Label("100%", skin);
TextButton yScaleResetButton = new TextButton("Reset", skin);
CheckBox debugBonesCheckbox = new CheckBox("Bones", skin); CheckBox debugBonesCheckbox = new CheckBox("Bones", skin);
CheckBox debugRegionsCheckbox = new CheckBox("Regions", skin); CheckBox debugRegionsCheckbox = new CheckBox("Regions", skin);
@ -448,17 +456,17 @@ public class SkeletonViewer extends ApplicationAdapter {
CheckBox addCheckbox = new CheckBox("Add", skin); CheckBox addCheckbox = new CheckBox("Add", skin);
Slider alphaSlider = new Slider(0, 1, 0.01f, false, skin); Slider alphaSlider = new Slider(0, 1, 0.01f, false, skin);
Label alphaLabel = new Label("1.0", skin); Label alphaLabel = new Label("100%", skin);
List<String> animationList = new List(skin); List<String> animationList = new List(skin);
ScrollPane animationScroll = new ScrollPane(animationList, skin, "bg"); ScrollPane animationScroll = new ScrollPane(animationList, skin, "bg");
Slider speedSlider = new Slider(0, 3, 0.01f, false, skin); Slider speedSlider = new Slider(0, 3, 0.01f, false, skin);
Label speedLabel = new Label("1.0", skin); Label speedLabel = new Label("1.0x", skin);
TextButton speedResetButton = new TextButton("Reset", skin); TextButton speedResetButton = new TextButton("Reset", skin);
Slider mixSlider = new Slider(0, 4, 0.01f, false, skin); Slider mixSlider = new Slider(0, 4, 0.01f, false, skin);
Label mixLabel = new Label("0.3", skin); Label mixLabel = new Label("0.3s", skin);
Label statusLabel = new Label("", skin); Label statusLabel = new Label("", skin);
WidgetGroup toasts = new WidgetGroup(); WidgetGroup toasts = new WidgetGroup();
@ -483,21 +491,27 @@ public class SkeletonViewer extends ApplicationAdapter {
loopCheckbox.setChecked(true); loopCheckbox.setChecked(true);
scaleSlider.setValue(1); loadScaleSlider.setValue(1);
scaleSlider.setSnapToValues(new float[] {0.5f, 1, 1.5f, 2, 2.5f, 3, 3.5f}, 0.01f); loadScaleSlider.setSnapToValues(new float[] {0.5f, 1, 1.5f, 2, 2.5f}, 0.09f);
zoomSlider.setValue(1); zoomSlider.setValue(1);
zoomSlider.setSnapToValues(new float[] {0.5f, 1, 1.5f, 2, 2.5f, 3, 3.5f}, 0.01f); zoomSlider.setSnapToValues(new float[] {1, 2}, 0.30f);
xScaleSlider.setValue(1);
xScaleSlider.setSnapToValues(new float[] {-1.5f, -1, -0.5f, 0.5f, 1, 1.5f}, 0.12f);
yScaleSlider.setValue(1);
yScaleSlider.setSnapToValues(new float[] {-1.5f, -1, -0.5f, 0.5f, 1, 1.5f}, 0.12f);
mixSlider.setValue(0.3f); mixSlider.setValue(0.3f);
mixSlider.setSnapToValues(new float[] {1, 1.5f, 2, 2.5f, 3, 3.5f}, 0.1f); mixSlider.setSnapToValues(new float[] {1, 1.5f, 2, 2.5f, 3, 3.5f}, 0.12f);
speedSlider.setValue(1); speedSlider.setValue(1);
speedSlider.setSnapToValues(new float[] {0.5f, 0.75f, 1, 1.25f, 1.5f, 2, 2.5f}, 0.01f); speedSlider.setSnapToValues(new float[] {0.5f, 0.75f, 1, 1.25f, 1.5f, 2, 2.5f}, 0.09f);
alphaSlider.setValue(1); alphaSlider.setValue(1);
alphaSlider.setDisabled(true); alphaSlider.setDisabled(true);
addCheckbox.setDisabled(true); addCheckbox.setDisabled(true);
window.setMovable(false); window.setMovable(false);
@ -519,12 +533,12 @@ public class SkeletonViewer extends ApplicationAdapter {
root.defaults().space(6); root.defaults().space(6);
root.columnDefaults(0).top().right().padTop(3); root.columnDefaults(0).top().right().padTop(3);
root.columnDefaults(1).left(); root.columnDefaults(1).left();
root.add("Scale:"); root.add("Load scale:");
{ {
Table table = table(); Table table = table();
table.add(scaleLabel).width(29); table.add(loadScaleLabel).width(29);
table.add(scaleSlider).growX(); table.add(loadScaleSlider).growX();
table.add(scaleResetButton); table.add(loadScaleResetButton);
root.add(table).fill().row(); root.add(table).fill().row();
} }
root.add("Zoom:"); root.add("Zoom:");
@ -535,8 +549,22 @@ public class SkeletonViewer extends ApplicationAdapter {
table.add(zoomResetButton); table.add(zoomResetButton);
root.add(table).fill().row(); root.add(table).fill().row();
} }
root.add("Flip:"); root.add("Scale X:");
root.add(table(flipXCheckbox, flipYCheckbox)).row(); {
Table table = table();
table.add(xScaleLabel).width(29);
table.add(xScaleSlider).growX();
table.add(xScaleResetButton).row();
root.add(table).fill().row();
}
root.add("Scale Y:");
{
Table table = table();
table.add(yScaleLabel).width(29);
table.add(yScaleSlider).growX();
table.add(yScaleResetButton);
root.add(table).fill().row();
}
root.add("Debug:"); root.add("Debug:");
root.add(table(debugBonesCheckbox, debugRegionsCheckbox, debugBoundingBoxesCheckbox)).row(); root.add(table(debugBonesCheckbox, debugRegionsCheckbox, debugBoundingBoxesCheckbox)).row();
root.add(); root.add();
@ -677,25 +705,25 @@ public class SkeletonViewer extends ApplicationAdapter {
} }
}); });
scaleSlider.addListener(new ChangeListener() { loadScaleSlider.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) { public void changed (ChangeEvent event, Actor actor) {
scaleLabel.setText(Float.toString((int)(scaleSlider.getValue() * 100) / 100f)); loadScaleLabel.setText(Integer.toString((int)(loadScaleSlider.getValue() * 100)) + "%");
if (!scaleSlider.isDragging()) loadSkeleton(skeletonFile); if (!loadScaleSlider.isDragging()) loadSkeleton(skeletonFile);
} }
}); });
scaleResetButton.addListener(new ChangeListener() { loadScaleResetButton.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) { public void changed (ChangeEvent event, Actor actor) {
resetCameraPosition(); resetCameraPosition();
if (scaleSlider.getValue() == 1) if (loadScaleSlider.getValue() == 1)
loadSkeleton(skeletonFile); loadSkeleton(skeletonFile);
else else
scaleSlider.setValue(1); loadScaleSlider.setValue(1);
} }
}); });
zoomSlider.addListener(new ChangeListener() { zoomSlider.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) { public void changed (ChangeEvent event, Actor actor) {
zoomLabel.setText(Float.toString((int)(zoomSlider.getValue() * 100) / 100f)); zoomLabel.setText(Integer.toString((int)(zoomSlider.getValue() * 100)) + "%");
float newZoom = 1 / zoomSlider.getValue(); float newZoom = 1 / zoomSlider.getValue();
camera.position.x -= window.getWidth() / 2 * (newZoom - camera.zoom); camera.position.x -= window.getWidth() / 2 * (newZoom - camera.zoom);
camera.zoom = newZoom; camera.zoom = newZoom;
@ -710,9 +738,33 @@ public class SkeletonViewer extends ApplicationAdapter {
} }
}); });
xScaleSlider.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) {
if (xScaleSlider.getValue() == 0) xScaleSlider.setValue(0.01f);
xScaleLabel.setText(Integer.toString((int)(xScaleSlider.getValue() * 100)) + "%");
}
});
xScaleResetButton.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) {
xScaleSlider.setValue(1);
}
});
yScaleSlider.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) {
if (yScaleSlider.getValue() == 0) yScaleSlider.setValue(0.01f);
yScaleLabel.setText(Integer.toString((int)(yScaleSlider.getValue() * 100)) + "%");
}
});
yScaleResetButton.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) {
yScaleSlider.setValue(1);
}
});
speedSlider.addListener(new ChangeListener() { speedSlider.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) { public void changed (ChangeEvent event, Actor actor) {
speedLabel.setText(Float.toString((int)(speedSlider.getValue() * 100) / 100f)); speedLabel.setText(Float.toString((int)(speedSlider.getValue() * 100) / 100f) + "x");
} }
}); });
speedResetButton.addListener(new ChangeListener() { speedResetButton.addListener(new ChangeListener() {
@ -723,7 +775,7 @@ public class SkeletonViewer extends ApplicationAdapter {
alphaSlider.addListener(new ChangeListener() { alphaSlider.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) { public void changed (ChangeEvent event, Actor actor) {
alphaLabel.setText(Float.toString((int)(alphaSlider.getValue() * 100) / 100f)); alphaLabel.setText(Integer.toString((int)(alphaSlider.getValue() * 100)) + "%");
int track = trackButtons.getCheckedIndex(); int track = trackButtons.getCheckedIndex();
if (track > 0) { if (track > 0) {
TrackEntry current = state.getCurrent(track); TrackEntry current = state.getCurrent(track);
@ -737,7 +789,7 @@ public class SkeletonViewer extends ApplicationAdapter {
mixSlider.addListener(new ChangeListener() { mixSlider.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) { public void changed (ChangeEvent event, Actor actor) {
mixLabel.setText(Float.toString((int)(mixSlider.getValue() * 100) / 100f)); mixLabel.setText(Float.toString((int)(mixSlider.getValue() * 100) / 100f) + "s");
if (state != null) state.getData().setDefaultMix(mixSlider.getValue()); if (state != null) state.getData().setDefaultMix(mixSlider.getValue());
} }
}); });
@ -878,8 +930,8 @@ public class SkeletonViewer extends ApplicationAdapter {
speedSlider.addListener(savePrefsListener); speedSlider.addListener(savePrefsListener);
speedResetButton.addListener(savePrefsListener); speedResetButton.addListener(savePrefsListener);
mixSlider.addListener(savePrefsListener); mixSlider.addListener(savePrefsListener);
scaleSlider.addListener(savePrefsListener); loadScaleSlider.addListener(savePrefsListener);
scaleResetButton.addListener(savePrefsListener); loadScaleResetButton.addListener(savePrefsListener);
zoomSlider.addListener(savePrefsListener); zoomSlider.addListener(savePrefsListener);
zoomResetButton.addListener(savePrefsListener); zoomResetButton.addListener(savePrefsListener);
animationList.addListener(savePrefsListener); animationList.addListener(savePrefsListener);
@ -942,7 +994,7 @@ public class SkeletonViewer extends ApplicationAdapter {
prefs.putBoolean("add", addCheckbox.isChecked()); prefs.putBoolean("add", addCheckbox.isChecked());
prefs.putFloat("speed", speedSlider.getValue()); prefs.putFloat("speed", speedSlider.getValue());
prefs.putFloat("mix", mixSlider.getValue()); prefs.putFloat("mix", mixSlider.getValue());
prefs.putFloat("scale", scaleSlider.getValue()); prefs.putFloat("scale", loadScaleSlider.getValue());
prefs.putFloat("zoom", zoomSlider.getValue()); prefs.putFloat("zoom", zoomSlider.getValue());
prefs.putFloat("x", camera.position.x); prefs.putFloat("x", camera.position.x);
prefs.putFloat("y", camera.position.y); prefs.putFloat("y", camera.position.y);
@ -978,7 +1030,7 @@ public class SkeletonViewer extends ApplicationAdapter {
camera.position.x = prefs.getFloat("x", 0); camera.position.x = prefs.getFloat("x", 0);
camera.position.y = prefs.getFloat("y", 0); camera.position.y = prefs.getFloat("y", 0);
scaleSlider.setValue(prefs.getFloat("scale", 1)); loadScaleSlider.setValue(prefs.getFloat("scale", 1));
animationList.setSelected(prefs.getString("animationName", null)); animationList.setSelected(prefs.getString("animationName", null));
skinList.setSelected(prefs.getString("skinName", null)); skinList.setSelected(prefs.getString("skinName", null));
} catch (Exception ex) { } catch (Exception ex) {

View File

@ -31,6 +31,8 @@
#include "SpinePluginPrivatePCH.h" #include "SpinePluginPrivatePCH.h"
#include "spine/Extension.h" #include "spine/Extension.h"
DEFINE_LOG_CATEGORY(SpineLog);
class FSpinePlugin : public SpinePlugin { class FSpinePlugin : public SpinePlugin {
virtual void StartupModule() override; virtual void StartupModule() override;
virtual void ShutdownModule() override; virtual void ShutdownModule() override;

View File

@ -109,12 +109,14 @@ void USpineSkeletonAnimationComponent::CheckState () {
if (Atlas && SkeletonData) { if (Atlas && SkeletonData) {
spine::SkeletonData *data = SkeletonData->GetSkeletonData(Atlas->GetAtlas(false), false); spine::SkeletonData *data = SkeletonData->GetSkeletonData(Atlas->GetAtlas(false), false);
skeleton = new (__FILE__, __LINE__) Skeleton(data); if (data) {
AnimationStateData* stateData = SkeletonData->GetAnimationStateData(Atlas->GetAtlas(false)); skeleton = new (__FILE__, __LINE__) Skeleton(data);
state = new (__FILE__, __LINE__) AnimationState(stateData); AnimationStateData* stateData = SkeletonData->GetAnimationStateData(Atlas->GetAtlas(false));
state->setRendererObject((void*)this); state = new (__FILE__, __LINE__) AnimationState(stateData);
state->setListener(callback); state->setRendererObject((void*)this);
trackEntries.Empty(); state->setListener(callback);
trackEntries.Empty();
}
} }
lastAtlas = Atlas; lastAtlas = Atlas;

View File

@ -33,6 +33,7 @@
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <stdlib.h> #include <stdlib.h>
#include "Runtime/Core/Public/Misc/MessageDialog.h"
#define LOCTEXT_NAMESPACE "Spine" #define LOCTEXT_NAMESPACE "Spine"
@ -105,10 +106,22 @@ SkeletonData* USpineSkeletonDataAsset::GetSkeletonData (Atlas* Atlas, bool Force
if (skeletonDataFileName.GetPlainNameString().Contains(TEXT(".json"))) { if (skeletonDataFileName.GetPlainNameString().Contains(TEXT(".json"))) {
SkeletonJson* json = new (__FILE__, __LINE__) SkeletonJson(Atlas); SkeletonJson* json = new (__FILE__, __LINE__) SkeletonJson(Atlas);
this->skeletonData = json->readSkeletonData((const char*)rawData.GetData()); this->skeletonData = json->readSkeletonData((const char*)rawData.GetData());
if (!skeletonData) {
#if WITH_EDITORONLY_DATA
FMessageDialog::Debugf(FText::FromString(UTF8_TO_TCHAR(json->getError().buffer())));
#endif
UE_LOG(SpineLog, Error, TEXT("Couldn't load skeleton data and atlas: %s"), UTF8_TO_TCHAR(json->getError().buffer()));
}
delete json; delete json;
} else { } else {
SkeletonBinary* binary = new (__FILE__, __LINE__) SkeletonBinary(Atlas); SkeletonBinary* binary = new (__FILE__, __LINE__) SkeletonBinary(Atlas);
this->skeletonData = binary->readSkeletonData((const unsigned char*)rawData.GetData(), (int)rawData.Num()); this->skeletonData = binary->readSkeletonData((const unsigned char*)rawData.GetData(), (int)rawData.Num());
if (!skeletonData) {
#if WITH_EDITORONLY_DATA
FMessageDialog::Debugf(FText::FromString(UTF8_TO_TCHAR(binary->getError().buffer())));
#endif
UE_LOG(SpineLog, Error, TEXT("Couldn't load skeleton data and atlas: %s"), UTF8_TO_TCHAR(binary->getError().buffer()));
}
delete binary; delete binary;
} }
if (animationStateData) { if (animationStateData) {

View File

@ -32,6 +32,8 @@
#include "ModuleManager.h" #include "ModuleManager.h"
DECLARE_LOG_CATEGORY_EXTERN(SpineLog, Log, All);
class SPINEPLUGIN_API SpinePlugin : public IModuleInterface { class SPINEPLUGIN_API SpinePlugin : public IModuleInterface {
public: public:

View File

@ -211,6 +211,8 @@ namespace Spine.Unity.Modules.AttachmentTools {
internal const bool UseMipMaps = false; internal const bool UseMipMaps = false;
internal const float DefaultScale = 0.01f; internal const float DefaultScale = 0.01f;
const int NonrenderingRegion = -1;
public static AtlasRegion ToAtlasRegion (this Texture2D t, Material materialPropertySource, float scale = DefaultScale) { public static AtlasRegion ToAtlasRegion (this Texture2D t, Material materialPropertySource, float scale = DefaultScale) {
return t.ToAtlasRegion(materialPropertySource.shader, scale, materialPropertySource); return t.ToAtlasRegion(materialPropertySource.shader, scale, materialPropertySource);
} }
@ -395,7 +397,7 @@ namespace Spine.Unity.Modules.AttachmentTools {
/// <param name = "outputAttachments">The List(Attachment) to populate with the newly created Attachment objects.</param> /// <param name = "outputAttachments">The List(Attachment) to populate with the newly created Attachment objects.</param>
/// ///
/// <param name="materialPropertySource">May be null. If no Material property source is provided, no special </param> /// <param name="materialPropertySource">May be null. If no Material property source is provided, no special </param>
public static void GetRepackedAttachments (List<Attachment> sourceAttachments, List<Attachment> outputAttachments, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, string newAssetName = "Repacked Attachments", bool clearCache = false) { public static void GetRepackedAttachments (List<Attachment> sourceAttachments, List<Attachment> outputAttachments, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, string newAssetName = "Repacked Attachments", bool clearCache = false, bool useOriginalNonrenderables = true) {
if (sourceAttachments == null) throw new System.ArgumentNullException("sourceAttachments"); if (sourceAttachments == null) throw new System.ArgumentNullException("sourceAttachments");
if (outputAttachments == null) throw new System.ArgumentNullException("outputAttachments"); if (outputAttachments == null) throw new System.ArgumentNullException("outputAttachments");
@ -411,9 +413,9 @@ namespace Spine.Unity.Modules.AttachmentTools {
int newRegionIndex = 0; int newRegionIndex = 0;
for (int i = 0, n = sourceAttachments.Count; i < n; i++) { for (int i = 0, n = sourceAttachments.Count; i < n; i++) {
var originalAttachment = sourceAttachments[i]; var originalAttachment = sourceAttachments[i];
var newAttachment = originalAttachment.GetClone(true);
if (IsRenderable(newAttachment)) { if (IsRenderable(originalAttachment)) {
var newAttachment = originalAttachment.GetClone(true);
var region = newAttachment.GetRegion(); var region = newAttachment.GetRegion();
int existingIndex; int existingIndex;
if (existingRegions.TryGetValue(region, out existingIndex)) { if (existingRegions.TryGetValue(region, out existingIndex)) {
@ -427,6 +429,9 @@ namespace Spine.Unity.Modules.AttachmentTools {
} }
outputAttachments[i] = newAttachment; outputAttachments[i] = newAttachment;
} else {
outputAttachments[i] = useOriginalNonrenderables ? originalAttachment : originalAttachment.GetClone(true);
regionIndexes.Add(NonrenderingRegion); // Output attachments pairs with regionIndexes list 1:1. Pad with a sentinel if the attachment doesn't have a region.
} }
} }
@ -460,7 +465,8 @@ namespace Spine.Unity.Modules.AttachmentTools {
// Map the cloned attachments to the repacked atlas. // Map the cloned attachments to the repacked atlas.
for (int i = 0, n = outputAttachments.Count; i < n; i++) { for (int i = 0, n = outputAttachments.Count; i < n; i++) {
var a = outputAttachments[i]; var a = outputAttachments[i];
a.SetRegion(repackedRegions[regionIndexes[i]]); if (IsRenderable(a))
a.SetRegion(repackedRegions[regionIndexes[i]]);
} }
// Clean up. // Clean up.
@ -474,14 +480,14 @@ namespace Spine.Unity.Modules.AttachmentTools {
/// <summary> /// <summary>
/// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas comprised of all the regions from the original skin.</summary> /// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas comprised of all the regions from the original skin.</summary>
/// <remarks>No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them.</remarks> /// <remarks>No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them.</remarks>
public static Skin GetRepackedSkin (this Skin o, string newName, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps) { public static Skin GetRepackedSkin (this Skin o, string newName, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, bool useOriginalNonrenderables = true) {
return GetRepackedSkin(o, newName, materialPropertySource.shader, out outputMaterial, out outputTexture, maxAtlasSize, padding, textureFormat, mipmaps, materialPropertySource); return GetRepackedSkin(o, newName, materialPropertySource.shader, out outputMaterial, out outputTexture, maxAtlasSize, padding, textureFormat, mipmaps, materialPropertySource, useOriginalNonrenderables);
} }
/// <summary> /// <summary>
/// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas comprised of all the regions from the original skin.</summary> /// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas comprised of all the regions from the original skin.</summary>
/// <remarks>No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them.</remarks> /// <remarks>No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them.</remarks>
public static Skin GetRepackedSkin (this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, Material materialPropertySource = null, bool clearCache = false) { public static Skin GetRepackedSkin (this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, Material materialPropertySource = null, bool clearCache = false, bool useOriginalNonrenderables = true) {
if (o == null) throw new System.NullReferenceException("Skin was null"); if (o == null) throw new System.NullReferenceException("Skin was null");
var skinAttachments = o.Attachments; var skinAttachments = o.Attachments;
var newSkin = new Skin(newName); var newSkin = new Skin(newName);
@ -495,10 +501,13 @@ namespace Spine.Unity.Modules.AttachmentTools {
var texturesToPack = new List<Texture2D>(); var texturesToPack = new List<Texture2D>();
var originalRegions = new List<AtlasRegion>(); var originalRegions = new List<AtlasRegion>();
int newRegionIndex = 0; int newRegionIndex = 0;
foreach (var kvp in skinAttachments) { foreach (var skinEntry in skinAttachments) {
var newAttachment = kvp.Value.GetClone(true); var originalKey = skinEntry.Key;
if (IsRenderable(newAttachment)) { var originalAttachment = skinEntry.Value;
Attachment newAttachment;
if (IsRenderable(originalAttachment)) {
newAttachment = originalAttachment.GetClone(true);
var region = newAttachment.GetRegion(); var region = newAttachment.GetRegion();
int existingIndex; int existingIndex;
if (existingRegions.TryGetValue(region, out existingIndex)) { if (existingRegions.TryGetValue(region, out existingIndex)) {
@ -512,9 +521,10 @@ namespace Spine.Unity.Modules.AttachmentTools {
} }
repackedAttachments.Add(newAttachment); repackedAttachments.Add(newAttachment);
} newSkin.AddAttachment(originalKey.slotIndex, originalKey.name, newAttachment);
var key = kvp.Key; } else {
newSkin.AddAttachment(key.slotIndex, key.name, newAttachment); newSkin.AddAttachment(originalKey.slotIndex, originalKey.name, useOriginalNonrenderables ? originalAttachment : originalAttachment.GetClone(true));
}
} }
// Fill a new texture with the collected attachment textures. // Fill a new texture with the collected attachment textures.
@ -546,7 +556,8 @@ namespace Spine.Unity.Modules.AttachmentTools {
// Map the cloned attachments to the repacked atlas. // 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]]); if (IsRenderable(a))
a.SetRegion(repackedRegions[regionIndexes[i]]);
} }
// Clean up. // Clean up.