Add SetupPoseBounds and implement canvas transforms

This commit is contained in:
Denis Andrasec 2024-07-03 17:39:22 +02:00
parent 4b391379e9
commit 5cae4737b5
7 changed files with 156 additions and 11 deletions

View File

@ -46,11 +46,7 @@ fun SpineViewComposable(modifier: Modifier = Modifier.fillMaxSize()) {
"spineboy.atlas",
"spineboy-pro.json",
SpineController {
it.skeleton.scaleY = -1f
it.skeleton.setToSetupPose()
it.animationStateData.defaultMix = 0.2f
it.animationState.setAnimation(0, "hoverboard", true)
it.animationState.setAnimation(0, "walk", true)
}
)
}

View File

@ -205,15 +205,12 @@ public class SkeletonRenderer {
return commandList;
}
public void render (Canvas canvas, Skeleton skeleton, float x, float y) {
canvas.save();
canvas.translate(x, y);
public void render (Canvas canvas, Skeleton skeleton) {
Array<RenderCommand> commands = render(skeleton);
for (int i = 0; i < commands.size; i++) {
RenderCommand command = commands.get(i);
canvas.drawVertices(Canvas.VertexMode.TRIANGLES, command.vertices.size, command.vertices.items, 0, command.uvs.items, 0,
command.colors.items, 0, command.indices.items, 0, command.indices.size, command.texture.getPaint(command.blendMode));
}
canvas.restore();
}
}

View File

@ -29,6 +29,11 @@
package com.esotericsoftware.spine.android;
import com.badlogic.gdx.math.Vector2;
import com.esotericsoftware.spine.android.bounds.Alignment;
import com.esotericsoftware.spine.android.bounds.Bounds;
import com.esotericsoftware.spine.android.bounds.BoundsProvider;
import com.esotericsoftware.spine.android.bounds.SetupPoseBounds;
import com.esotericsoftware.spine.android.utils.AndroidSkeletonDrawableLoader;
import android.content.Context;
@ -47,9 +52,21 @@ import java.net.URL;
public class SpineView extends View implements Choreographer.FrameCallback {
private long lastTime = 0;
private float delta = 0;
private float offsetX = 0;
private float offsetY = 0;
private float scaleX = 1;
private float scaleY = 1;
private float x = 0;
private float y = 0;
SkeletonRenderer renderer = new SkeletonRenderer();
SpineController controller;
BoundsProvider boundsProvider = new SetupPoseBounds();
Bounds computedBounds = new Bounds();
Alignment alignment = Alignment.CENTER;
public SpineView (Context context) {
super(context);
}
@ -82,6 +99,9 @@ public class SpineView extends View implements Choreographer.FrameCallback {
Thread backgroundThread = new Thread(() -> {
final AndroidSkeletonDrawable skeletonDrawable = loader.load();
mainHandler.post(() -> {
computedBounds = boundsProvider.computeBounds(skeletonDrawable);
updateCanvasTransform();
controller.init(skeletonDrawable);
Choreographer.getInstance().postFrameCallback(SpineView.this);
});
@ -98,9 +118,31 @@ public class SpineView extends View implements Choreographer.FrameCallback {
controller.getDrawable().update(delta);
// TODO: Calculate scaling + position
canvas.save();
canvas.translate(offsetX, offsetY);
canvas.scale(scaleX, scaleY * -1);
canvas.translate(x, y);
renderer.render(canvas, controller.getSkeleton(), 500f, 1000f);
renderer.render(canvas, controller.getSkeleton());
canvas.restore();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
updateCanvasTransform();
}
private void updateCanvasTransform() {
x = (float) (-computedBounds.getX() - computedBounds.getWidth() / 2.0 - (alignment.getX() * computedBounds.getWidth() / 2.0));
y = (float) (-computedBounds.getY() - computedBounds.getHeight() / 2.0 - (alignment.getY() * computedBounds.getHeight() / 2.0));
// contain
scaleX = scaleY = (float) Math.min(getWidth() / computedBounds.getWidth(), getHeight() / computedBounds.getHeight());
offsetX = (float) (getWidth() / 2.0 + (alignment.getX() * getWidth() / 2.0));
offsetY = (float) (getHeight() / 2.0 + (alignment.getY() * getHeight() / 2.0));
}
// Choreographer.FrameCallback

View File

@ -0,0 +1,29 @@
package com.esotericsoftware.spine.android.bounds;
public enum Alignment {
TOP_LEFT(-1.0f, -1.0f),
TOP_CENTER(0.0f, -1.0f),
TOP_RIGHT(1.0f, -1.0f),
CENTER_LEFT(-1.0f, 0.0f),
CENTER(0.0f, 0.0f),
CENTER_RIGHT(1.0f, 0.0f),
BOTTOM_LEFT(-1.0f, 1.0f),
BOTTOM_CENTER(0.0f, 1.0f),
BOTTOM_RIGHT(1.0f, 1.0f);
private final float x;
private final float y;
Alignment(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
}

View File

@ -0,0 +1,54 @@
package com.esotericsoftware.spine.android.bounds;
public class Bounds {
private double x;
private double y;
private double width;
private double height;
public Bounds() {
this.x = 0;
this.y = 0;
this.width = 0;
this.height = 0;
}
public Bounds(double x, double y, double width, double height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
}

View File

@ -0,0 +1,7 @@
package com.esotericsoftware.spine.android.bounds;
import com.esotericsoftware.spine.android.AndroidSkeletonDrawable;
public interface BoundsProvider {
Bounds computeBounds(AndroidSkeletonDrawable drawable);
}

View File

@ -0,0 +1,20 @@
package com.esotericsoftware.spine.android.bounds;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.FloatArray;
import com.esotericsoftware.spine.android.AndroidSkeletonDrawable;
public class SetupPoseBounds implements BoundsProvider {
@Override
public Bounds computeBounds(AndroidSkeletonDrawable drawable) {
Vector2 offset = new Vector2(0, 0);
Vector2 size = new Vector2(0, 0);
FloatArray floatArray = new FloatArray();
drawable.getSkeleton().getBounds(offset, size, floatArray);
return new Bounds(offset.x, offset.y, size.x, size.y);
}
}