Skip to content

Commit 81312c8

Browse files
committed
[canvaskit] HDPI support, fix blending, physics example
1 parent cc96523 commit 81312c8

8 files changed

+150
-9
lines changed

spine-ts/index.html

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ <h1>spine-ts Examples</h1>
2626
<li><a href="/spine-canvaskit/example/animation-state-events.html">Animation State Events</a></li>
2727
<li><a href="/spine-canvaskit/example/mix-and-match.html">Skins Mix &amp; Match</a></li>
2828
<li><a href="/spine-canvaskit/example/ik-following.html">IK Following</a></li>
29+
<li><a href="/spine-canvaskit/example/physics.html">Physics</a></li>
2930
<li><a href="/spine-canvaskit/example/micro-benchmark.html">Micro Benchmark</a></li>
3031
</ul>
3132
<li>Pixi</li>

spine-ts/spine-canvaskit/example/animation-state-events.html

+7-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<body class="p-4 flex flex-col items-center">
1919
<h1>Animation State Events</h1>
2020
<p class="mb-4">Open the console in the developer tools to view events logs.</p>
21-
<canvas id=foo width=600 height=400 style="margin: 0 auto;"></canvas>
21+
<canvas id=foo style="margin: 0 auto; width: 600px; height: 400px;"></canvas>
2222
</body>
2323

2424
<script type="module">
@@ -28,8 +28,14 @@ <h1>Animation State Events</h1>
2828
return await response.arrayBuffer();
2929
}
3030

31+
const canvasElement = document.querySelector("#foo");
32+
const dpr = window.devicePixelRatio || 1;
33+
canvasElement.width = canvasElement.clientWidth * dpr;
34+
canvasElement.height = canvasElement.clientHeight * dpr;
35+
3136
const ck = await CanvasKitInit();
3237
const surface = ck.MakeCanvasSurface('foo');
38+
surface.getCanvas().scale(dpr, dpr);
3339

3440
const atlas = await spine.loadTextureAtlas(ck, "assets/spineboy.atlas", readFile);
3541
const skeletonData = await spine.loadSkeletonData("assets/spineboy-pro.skel", atlas, readFile);

spine-ts/spine-canvaskit/example/ik-following.html

+7-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<body class="p-4 flex flex-col items-center">
1919
<h1>IK Following</h1>
2020
<p class="mb-4">Click/touch to set the aim</p>
21-
<canvas id=foo width=600 height=400 style="margin: 0 auto;"></canvas>
21+
<canvas id=foo style="margin: 0 auto; width: 600px; height: 400px;"></canvas>
2222
</body>
2323

2424
<script type="module">
@@ -28,8 +28,14 @@ <h1>IK Following</h1>
2828
return await response.arrayBuffer();
2929
}
3030

31+
const canvasElement = document.querySelector("#foo");
32+
const dpr = window.devicePixelRatio || 1;
33+
canvasElement.width = canvasElement.clientWidth * dpr;
34+
canvasElement.height = canvasElement.clientHeight * dpr;
35+
3136
const ck = await CanvasKitInit();
3237
const surface = ck.MakeCanvasSurface('foo');
38+
surface.getCanvas().scale(dpr, dpr);
3339

3440
const atlas = await spine.loadTextureAtlas(ck, "assets/spineboy.atlas", readFile);
3541
const skeletonData = await spine.loadSkeletonData("assets/spineboy-pro.skel", atlas, readFile);
@@ -65,7 +71,6 @@ <h1>IK Following</h1>
6571
const clientRect = canvasElement.getBoundingClientRect();
6672
let x = touchX - clientRect.left;
6773
let y = touchY - clientRect.top;
68-
console.log(`${x}, ${y}`);
6974

7075
// Transform the touch/mouse position to the crosshair
7176
// bone's parent bone coordinate system

spine-ts/spine-canvaskit/example/index.html

+11-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
<body class="p-4 flex flex-col items-center">
1919
<h1>CanvasKit Example</h1>
20-
<canvas id=foo width=600 height=400 style="margin: 0 auto;"></canvas>
20+
<canvas id=foo style="margin: 0 auto; width: 600px; height: 400px;"></canvas>
2121
</body>
2222

2323
<script type="module">
@@ -28,11 +28,20 @@ <h1>CanvasKit Example</h1>
2828
return await response.arrayBuffer();
2929
}
3030

31+
// Ensure we render at full DPI.
32+
const canvasElement = document.querySelector("#foo");
33+
const dpr = window.devicePixelRatio || 1;
34+
canvasElement.width = canvasElement.clientWidth * dpr;
35+
canvasElement.height = canvasElement.clientHeight * dpr;
36+
3137

3238
// Initialize CanvasKit and create a surface from the Canvas element to draw to
3339
const ck = await CanvasKitInit();
3440
const surface = ck.MakeCanvasSurface('foo');
3541

42+
// Scale the CanvasKit coordinate system
43+
surface.getCanvas().scale(dpr, dpr);
44+
3645
// Load the texture atlas
3746
const atlas = await spine.loadTextureAtlas(ck, "assets/spineboy.atlas", readFile);
3847

@@ -54,6 +63,7 @@ <h1>CanvasKit Example</h1>
5463
let lastTime = performance.now();
5564
// Rendering loop
5665
function drawFrame(canvas) {
66+
// Clear the canvas
5767
canvas.clear(ck.Color(52, 52, 54, 1));
5868

5969
// Calculate the time that's passed between now and the last frame

spine-ts/spine-canvaskit/example/micro-benchmark.html

+8-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<body class="p-4 flex flex-col items-center">
1919
<h1>Micro Benchmark</h1>
2020
<div id="timing"></div>
21-
<canvas id=foo width=600 height=400 style="margin: 0 auto;"></canvas>
21+
<canvas id=foo style="margin: 0 auto; width: 600px; height: 400px;"></canvas>
2222
</body>
2323

2424
<script type="module">
@@ -28,13 +28,19 @@ <h1>Micro Benchmark</h1>
2828
return await response.arrayBuffer();
2929
}
3030

31+
const canvasElement = document.querySelector("#foo");
32+
const dpr = window.devicePixelRatio || 1;
33+
canvasElement.width = canvasElement.clientWidth * dpr;
34+
canvasElement.height = canvasElement.clientHeight * dpr;
35+
3136
const ck = await CanvasKitInit();
3237
const surface = ck.MakeCanvasSurface('foo');
38+
surface.getCanvas().scale(dpr, dpr);
3339

3440
const atlas = await spine.loadTextureAtlas(ck, "assets/spineboy.atlas", readFile);
3541
const skeletonData = await spine.loadSkeletonData("assets/spineboy-pro.skel", atlas, readFile);
3642

37-
// Instantiate 100 skeletons, randomly placed and scaled.
43+
// Instantiate 100 drawables, randomly placed and scaled.
3844
const drawables = [];
3945
for (let i = 0; i < 100; i++) {
4046
const drawable = new spine.SkeletonDrawable(skeletonData);

spine-ts/spine-canvaskit/example/mix-and-match.html

+7-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
<body class="p-4 flex flex-col items-center">
1919
<h1>Skins Mix &amp; Match Example</h1>
20-
<canvas id=foo width=600 height=400 style="margin: 0 auto;"></canvas>
20+
<canvas id=foo style="margin: 0 auto; width: 600px; height: 400px;"></canvas>
2121
</body>
2222

2323
<script type="module">
@@ -27,8 +27,14 @@ <h1>Skins Mix &amp; Match Example</h1>
2727
return await response.arrayBuffer();
2828
}
2929

30+
const canvasElement = document.querySelector("#foo");
31+
const dpr = window.devicePixelRatio || 1;
32+
canvasElement.width = canvasElement.clientWidth * dpr;
33+
canvasElement.height = canvasElement.clientHeight * dpr;
34+
3035
const ck = await CanvasKitInit();
3136
const surface = ck.MakeCanvasSurface('foo');
37+
surface.getCanvas().scale(dpr, dpr);
3238

3339
const atlas = await spine.loadTextureAtlas(ck, "assets/mix-and-match.atlas", readFile);
3440
const skeletonData = await spine.loadSkeletonData("assets/mix-and-match-pro.skel", atlas, readFile);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<!DOCTYPE html>
2+
<html>
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<link rel="stylesheet" href="../../index.css">
8+
<script src="https://unpkg.com/canvaskit-wasm@latest/bin/canvaskit.js"></script>
9+
<script src="../dist/iife/spine-canvaskit.js"></script>
10+
<style>
11+
* {
12+
margin: 0;
13+
padding: 0;
14+
}
15+
</style>
16+
</head>
17+
18+
<body class="p-4 flex flex-col items-center">
19+
<h1>IK Following</h1>
20+
<p class="mb-4">Drag anywhere</p>
21+
<canvas id=foo style="margin: 0 auto; width: 600px; height: 400px;"></canvas>
22+
</body>
23+
24+
<script type="module">
25+
async function readFile(path) {
26+
const response = await fetch(path);
27+
if (!response.ok) throw new Error("Could not load file " + path);
28+
return await response.arrayBuffer();
29+
}
30+
31+
const canvasElement = document.querySelector("#foo");
32+
const dpr = window.devicePixelRatio || 1;
33+
canvasElement.width = canvasElement.clientWidth * dpr;
34+
canvasElement.height = canvasElement.clientHeight * dpr;
35+
36+
const ck = await CanvasKitInit();
37+
const surface = ck.MakeCanvasSurface('foo');
38+
surface.getCanvas().scale(dpr, dpr);
39+
40+
const atlas = await spine.loadTextureAtlas(ck, "assets/celestial-circus.atlas", readFile);
41+
const skeletonData = await spine.loadSkeletonData("assets/celestial-circus-pro.json", atlas, readFile);
42+
const drawable = new spine.SkeletonDrawable(skeletonData);
43+
drawable.skeleton.scaleX = drawable.skeleton.scaleY = 0.15;
44+
drawable.skeleton.x = 300;
45+
drawable.skeleton.y = 300;
46+
47+
// Set the blink animation on track 0
48+
drawable.animationState.setAnimation(0, "eyeblink-long", true);
49+
50+
// Set up touch and mouse listeners on the canvas element
51+
// and set the touch/mouse coordinate on the aim bone
52+
let mouseDown = false;
53+
let lastX = -1, lastY = -1;
54+
canvasElement.addEventListener("touchmove", (ev) => drag(ev.changedTouches[0].clientX, ev.changedTouches[0].clientY));
55+
canvasElement.addEventListener("mousedown", (ev) => {
56+
mouseDown = true;
57+
drag(ev.clientX, ev.clientY);
58+
});
59+
canvasElement.addEventListener("mouseup", () => {
60+
mouseDown = false;
61+
lastX = -1; lastY = -1;
62+
})
63+
canvasElement.addEventListener("mousemove", (ev) => {
64+
if (mouseDown) drag(ev.clientX, ev.clientY);
65+
})
66+
67+
// Move the skeleton around based on the distance between
68+
// the last touch/mouse location and the current touch/mouse location.
69+
const drag = (touchX, touchY) => {
70+
const clientRect = canvasElement.getBoundingClientRect();
71+
let x = touchX - clientRect.left;
72+
let y = touchY - clientRect.top;
73+
if (lastX == -1 && lastY == -1) {
74+
lastX = x;
75+
lastY = y;
76+
return;
77+
}
78+
79+
drawable.skeleton.x += (x - lastX);
80+
drawable.skeleton.y += (y - lastY);
81+
lastX = x;
82+
lastY = y;
83+
}
84+
85+
const renderer = new spine.SkeletonRenderer(ck);
86+
let lastTime = performance.now();
87+
88+
function drawFrame(canvas) {
89+
canvas.clear(ck.Color(52, 52, 54, 1));
90+
91+
const now = performance.now();
92+
const deltaTime = (now - lastTime) / 1000;
93+
lastTime = now;
94+
95+
drawable.update(deltaTime);
96+
renderer.render(canvas, drawable);
97+
98+
surface.requestAnimationFrame(drawFrame);
99+
}
100+
surface.requestAnimationFrame(drawFrame);
101+
</script>
102+
103+
</html>

spine-ts/spine-canvaskit/src/index.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ function toCkBlendMode(ck: CanvasKit, blendMode: BlendMode) {
1212
switch(blendMode) {
1313
case BlendMode.Normal: return ck.BlendMode.SrcOver;
1414
case BlendMode.Additive: return ck.BlendMode.Plus;
15-
case BlendMode.Multiply: return ck.BlendMode.Modulate;
15+
case BlendMode.Multiply: return ck.BlendMode.SrcOver;
1616
case BlendMode.Screen: return ck.BlendMode.Screen;
1717
default: return ck.BlendMode.SrcOver;
1818
}
@@ -92,7 +92,11 @@ export async function loadTextureAtlas(ck: CanvasKit, atlasFile: string, readFil
9292
export async function loadSkeletonData(skeletonFile: string, atlas: TextureAtlas, readFile: (path: string) => Promise<Buffer>): Promise<SkeletonData> {
9393
const attachmentLoader = new AtlasAttachmentLoader(atlas);
9494
const loader = skeletonFile.endsWith(".json") ? new SkeletonJson(attachmentLoader) : new SkeletonBinary(attachmentLoader);
95-
const skeletonData = loader.readSkeletonData(await readFile(skeletonFile));
95+
let data = await readFile(skeletonFile);
96+
if (skeletonFile.endsWith(".json")) {
97+
data = bufferToUtf8String(data);
98+
}
99+
const skeletonData = loader.readSkeletonData(data);
96100
return skeletonData;
97101
}
98102

0 commit comments

Comments
 (0)