[cpp][ts] Improved test beds.

This commit is contained in:
Mario Zechner 2023-11-27 12:06:52 +01:00
parent 3dabb07561
commit 8a80baa0ac
3 changed files with 287 additions and 215 deletions

View File

@ -70,11 +70,12 @@ class NullAttachmentLoader : public AttachmentLoader {
}; };
int main(void) { int main(void) {
String atlasFile(""); String atlasFile("/Users/badlogic/Desktop/basemodel-male/basemodel-male.atlas");
String skeletonFile("/Users/badlogic/workspaces/spine-runtimes/spine-haxe/example/assets/vine-pro.json"); String skeletonFile("/Users/badlogic/Desktop/basemodel-male/basemodel-male.skel");
String animation = ""; String animation = "";
String skin = "BasicBody";
float scale = 1.0f; float scale = 0.1f;
SFMLTextureLoader textureLoader; SFMLTextureLoader textureLoader;
NullAttachmentLoader nullLoader; NullAttachmentLoader nullLoader;
Atlas *atlas = atlasFile.length() == 0 ? nullptr : new Atlas(atlasFile, &textureLoader); Atlas *atlas = atlasFile.length() == 0 ? nullptr : new Atlas(atlasFile, &textureLoader);
@ -106,6 +107,7 @@ int main(void) {
drawable.skeleton->updateWorldTransform(); drawable.skeleton->updateWorldTransform();
drawable.skeleton->setPosition(320, 590); drawable.skeleton->setPosition(320, 590);
if (animation.length() > 0) drawable.state->setAnimation(0, animation, true); if (animation.length() > 0) drawable.state->setAnimation(0, animation, true);
if (skin.length() > 0) drawable.skeleton->setSkin(skin);
sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - testbed"); sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - testbed");
window.setFramerateLimit(60); window.setFramerateLimit(60);

View File

@ -1,21 +1,27 @@
<html> <html>
<script src="../dist/iife/spine-webgl.js"></script> <script src="../dist/iife/spine-webgl.js"></script>
<style> <style>
* { * {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
</style> </style>
<body> <body>
<canvas id="canvas" style="position: absolute; width: 100%; height: 100%;"></canvas> <canvas
<div style="position: absolute; top: 1em; left: 1em; z-index: 1; color: #ccc;"> id="canvas"
<label style="margin-right: 0.5em;">Animations</label> style="position: absolute; width: 100%; height: 100%"
></canvas>
<div
style="position: absolute; top: 1em; left: 1em; z-index: 1; color: #ccc"
>
<label style="margin-right: 0.5em"> Animations</label>
<select id="animations"></select> <select id="animations"></select>
<label style="margin-right: 0.5em">Skins</label>
<select id="skins"></select>
<label>PMA</label> <label>PMA</label>
<input type="checkbox" id="pma" checked> <input type="checkbox" id="pma" checked />
</div> </div>
<script src="drag-and-drop.js"></script> <script src="drag-and-drop.js"></script>
</body> </body>
</html> </html>

View File

@ -16,22 +16,32 @@ class App {
initialize(canvas) { initialize(canvas) {
// Load the Spineboy skeleton // Load the Spineboy skeleton
this.loadSkeleton("assets/spineboy-pro.skel", "assets/spineboy-pma.atlas", "run"); this.loadSkeleton(
"assets/spineboy-pro.skel",
"assets/spineboy-pma.atlas",
"run"
);
// Setup listener for animation selection box // Setup listener for animation selection box
let animationSelectBox = document.body.querySelector("#animations"); let animationSelectBox = document.body.querySelector("#animations");
animationSelectBox.onchange = () => { animationSelectBox.onchange = () => {
this.animationState.setAnimation(0, animationSelectBox.value, true); this.animationState.setAnimation(0, animationSelectBox.value, true);
} };
// Setup listener for skin selection box
let skinSelectBox = document.body.querySelector("#skins");
skinSelectBox.onchange = () => {
this.skeleton.setSkinByName(skinSelectBox.value);
};
// Setup listener for the PMA checkbox // Setup listener for the PMA checkbox
let pmaCheckbox = document.body.querySelector("#pma"); let pmaCheckbox = document.body.querySelector("#pma");
pmaCheckbox.onchange = () => { pmaCheckbox.onchange = () => {
this.pma = pmaCheckbox.checked; this.pma = pmaCheckbox.checked;
} };
// Setup the drag and drop listener // Setup the drag and drop listener
new FileDragAndDrop(canvas.htmlCanvas, (files) => this.onDrop(files)) new FileDragAndDrop(canvas.htmlCanvas, (files) => this.onDrop(files));
// Setup a camera controller for paning and zooming // Setup a camera controller for paning and zooming
new spine.CameraController(canvas.htmlCanvas, canvas.renderer.camera); new spine.CameraController(canvas.htmlCanvas, canvas.renderer.camera);
@ -47,30 +57,43 @@ class App {
// are binary, so we have to encode them to base64 for loading // are binary, so we have to encode them to base64 for loading
// through AssetManager. // through AssetManager.
let bufferToBase64 = (buffer) => { let bufferToBase64 = (buffer) => {
var binary = ''; var binary = "";
var bytes = new Uint8Array(buffer); var bytes = new Uint8Array(buffer);
var len = bytes.byteLength; var len = bytes.byteLength;
for (var i = 0; i < len; i++) { for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]); binary += String.fromCharCode(bytes[i]);
} }
return window.btoa(binary); return window.btoa(binary);
} };
for (var file of files) { for (var file of files) {
if (file.name.endsWith(".atlas") || file.name.endsWith(".atlas.txt")) { if (file.name.endsWith(".atlas") || file.name.endsWith(".atlas.txt")) {
atlasFile = file; atlasFile = file;
assetManager.setRawDataURI(file.name, "data:text/plain;," + file.contentText); assetManager.setRawDataURI(
file.name,
"data:text/plain;," + file.contentText
);
} else if (file.name.endsWith(".skel")) { } else if (file.name.endsWith(".skel")) {
skeletonFile = file; skeletonFile = file;
assetManager.setRawDataURI(file.name, "data:application/octet-stream;base64," + bufferToBase64(file.contentBinary)); assetManager.setRawDataURI(
file.name,
"data:application/octet-stream;base64," +
bufferToBase64(file.contentBinary)
);
assetManager.loadBinary(file.name); assetManager.loadBinary(file.name);
} else if (file.name.endsWith(".json")) { } else if (file.name.endsWith(".json")) {
skeletonFile = file; skeletonFile = file;
assetManager.setRawDataURI(file.name, "data:text/plain;," + file.contentText); assetManager.setRawDataURI(
file.name,
"data:text/plain;," + file.contentText
);
assetManager.loadJson(file.name); assetManager.loadJson(file.name);
} else if (file.name.endsWith(".png")) { } else if (file.name.endsWith(".png")) {
pngs.push(file); pngs.push(file);
assetManager.setRawDataURI(file.name, "data:image/png;base64," + bufferToBase64(file.contentBinary)); assetManager.setRawDataURI(
file.name,
"data:image/png;base64," + bufferToBase64(file.contentBinary)
);
} }
} }
@ -94,7 +117,7 @@ class App {
} else { } else {
requestAnimationFrame(waitForLoad); requestAnimationFrame(waitForLoad);
} }
} };
waitForLoad(); waitForLoad();
} }
@ -104,11 +127,13 @@ class App {
var atlas = assetManager.require(atlasFile); var atlas = assetManager.require(atlasFile);
var atlasLoader = new spine.AtlasAttachmentLoader(atlas); var atlasLoader = new spine.AtlasAttachmentLoader(atlas);
var skeletonData; var skeletonData;
var skeletonBinaryOrJson = skeletonFile.endsWith(".skel") ? var skeletonBinaryOrJson = skeletonFile.endsWith(".skel")
new spine.SkeletonBinary(atlasLoader) : ? new spine.SkeletonBinary(atlasLoader)
new spine.SkeletonJson(atlasLoader); : new spine.SkeletonJson(atlasLoader);
skeletonBinaryOrJson.scale = 1; skeletonBinaryOrJson.scale = 1;
skeletonData = skeletonBinaryOrJson.readSkeletonData(assetManager.require(skeletonFile)); skeletonData = skeletonBinaryOrJson.readSkeletonData(
assetManager.require(skeletonFile)
);
this.skeleton = new spine.Skeleton(skeletonData); this.skeleton = new spine.Skeleton(skeletonData);
var animationStateData = new spine.AnimationStateData(skeletonData); var animationStateData = new spine.AnimationStateData(skeletonData);
this.animationState = new spine.AnimationState(animationStateData); this.animationState = new spine.AnimationState(animationStateData);
@ -125,6 +150,22 @@ class App {
} }
this.animationState.setAnimation(0, animationName, true); this.animationState.setAnimation(0, animationName, true);
// Fill the skin selection box.
let skinSelectBox = document.body.querySelector("#skins");
skinSelectBox.innerHTML = "";
for (var skin of this.skeleton.data.skins) {
let option = document.createElement("option");
option.value = option.innerText = skin.name;
skinSelectBox.appendChild(option);
}
if (
!this.skeleton.data.defaultSkin ||
(this.skeleton.data.defaultSkin.attachments.length == 0 &&
this.skeleton.data.skins.length > 1)
) {
this.skeleton.setSkin(this.skeleton.data.skins[0]);
}
// Center the skeleton in the viewport // Center the skeleton in the viewport
this.centerSkeleton(); this.centerSkeleton();
} }
@ -134,17 +175,34 @@ class App {
this.animationState.update(0); this.animationState.update(0);
this.animationState.apply(this.skeleton); this.animationState.apply(this.skeleton);
this.skeleton.updateWorldTransform(); this.skeleton.updateWorldTransform();
let offset = new spine.Vector2(), size = new spine.Vector2(); let offset = new spine.Vector2(),
size = new spine.Vector2();
this.skeleton.getBounds(offset, size); this.skeleton.getBounds(offset, size);
let camera = this.canvas.renderer.camera;
let renderer = this.canvas.renderer;
renderer.resize(spine.ResizeMode.Expand);
if (
!Number.isFinite(size.x) ||
!Number.isFinite(size.y) ||
!Number.isFinite(offset.x) ||
!Number.isFinite(offset.y)
) {
camera.position.x = 0;
camera.position.y = 0;
camera.zoom = 1;
camera.update();
return;
}
// Make sure the canvas is sized properly and position and zoom // Make sure the canvas is sized properly and position and zoom
// the camera so the skeleton is centered in the viewport. // the camera so the skeleton is centered in the viewport.
let renderer = this.canvas.renderer;
renderer.resize(spine.ResizeMode.Expand);
let camera = this.canvas.renderer.camera;
camera.position.x = offset.x + size.x / 2; camera.position.x = offset.x + size.x / 2;
camera.position.y = offset.y + size.y / 2; camera.position.y = offset.y + size.y / 2;
camera.zoom = size.x > size.y ? size.x / this.canvas.htmlCanvas.width * 3 : size.y / this.canvas.htmlCanvas.height * 3; camera.zoom =
size.x > size.y
? (size.x / this.canvas.htmlCanvas.width) * 3
: (size.y / this.canvas.htmlCanvas.height) * 3;
camera.update(); camera.update();
} }
@ -171,8 +229,8 @@ class App {
new spine.SpineCanvas(document.getElementById("canvas"), { new spine.SpineCanvas(document.getElementById("canvas"), {
app: new App(), app: new App(),
webglConfig: { webglConfig: {
alpha: false alpha: false,
} },
}); });
class FileDragAndDrop { class FileDragAndDrop {
@ -188,13 +246,19 @@ class FileDragAndDrop {
const items = Object.keys(event.dataTransfer.items); const items = Object.keys(event.dataTransfer.items);
let files = []; let files = [];
await Promise.all(items.map(async (key) => { await Promise.all(
items.map(async (key) => {
var file = event.dataTransfer.items[key].getAsFile(); var file = event.dataTransfer.items[key].getAsFile();
if (file.kind == "string") return; if (file.kind == "string") return;
let contentBinary = await file.arrayBuffer(); let contentBinary = await file.arrayBuffer();
let contentText = await file.text(); let contentText = await file.text();
files.push({ name: file.name, contentBinary: contentBinary, contentText: contentText }); files.push({
})); name: file.name,
contentBinary: contentBinary,
contentText: contentText,
});
})
);
this.callback(files); this.callback(files);
} }
} }
@ -208,7 +272,7 @@ class FileDragAndDrop {
resolve(fr.result); resolve(fr.result);
}; };
fr.readAsArrayBuffer(); fr.readAsArrayBuffer();
}) });
} }
function text() { function text() {
@ -218,10 +282,10 @@ class FileDragAndDrop {
resolve(fr.result); resolve(fr.result);
}; };
fr.readAsText(this); fr.readAsText(this);
}) });
} }
if ('File' in self) { if ("File" in self) {
File.prototype.arrayBuffer = File.prototype.arrayBuffer || arrayBuffer; File.prototype.arrayBuffer = File.prototype.arrayBuffer || arrayBuffer;
File.prototype.text = File.prototype.text || text; File.prototype.text = File.prototype.text || text;
} }