mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 01:36:02 +08:00
[ts][canvaskit] Use Uint32Array for colors to avoid canvaskit to allocate one each vertices creation.
This commit is contained in:
parent
532fdb87eb
commit
c7cf509071
@ -1,9 +1,9 @@
|
|||||||
import * as fs from "fs"
|
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
import path from 'path';
|
|
||||||
import CanvasKitInit from "canvaskit-wasm";
|
import CanvasKitInit from "canvaskit-wasm";
|
||||||
import UPNG from "@pdf-lib/upng"
|
import UPNG from "@pdf-lib/upng"
|
||||||
import {loadTextureAtlas, SkeletonRenderer, Skeleton, SkeletonBinary, AnimationState, AnimationStateData, AtlasAttachmentLoader, Physics, loadSkeletonData, SkeletonDrawable} from "../dist/index.js"
|
import path from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { readFileSync, writeFileSync } from "node:fs"
|
||||||
|
import { loadTextureAtlas, SkeletonRenderer, loadSkeletonData, SkeletonDrawable } from "../dist/index.js"
|
||||||
|
|
||||||
// Get the current directory
|
// Get the current directory
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
@ -19,10 +19,10 @@ async function main() {
|
|||||||
if (!surface) throw new Error();
|
if (!surface) throw new Error();
|
||||||
|
|
||||||
// Load atlas
|
// Load atlas
|
||||||
const atlas = await loadTextureAtlas(ck, __dirname + "/../../assets/spineboy.atlas", async (path) => fs.readFileSync(path));
|
const atlas = await loadTextureAtlas(ck, `${__dirname}/../../assets/spineboy.atlas`, async (path) => readFileSync(path));
|
||||||
|
|
||||||
// Load the skeleton data
|
// Load the skeleton data
|
||||||
const skeletonData = await loadSkeletonData(__dirname + "/../../assets/spineboy-pro.skel", atlas, async (path) => fs.readFileSync(path));
|
const skeletonData = await loadSkeletonData(`${__dirname}/../../assets/spineboy-pro.skel`, atlas, async (path) => readFileSync(path));
|
||||||
|
|
||||||
// Create a SkeletonDrawable
|
// Create a SkeletonDrawable
|
||||||
const drawable = new SkeletonDrawable(skeletonData);
|
const drawable = new SkeletonDrawable(skeletonData);
|
||||||
@ -68,7 +68,7 @@ async function main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const apng = UPNG.default.encode(frames, 600, 400, 0, frames.map(() => FRAME_TIME * 1000));
|
const apng = UPNG.default.encode(frames, 600, 400, 0, frames.map(() => FRAME_TIME * 1000));
|
||||||
fs.writeFileSync('output.png', Buffer.from(apng));
|
writeFileSync('output.png', Buffer.from(apng));
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
|||||||
@ -35,7 +35,8 @@ import {
|
|||||||
AtlasAttachmentLoader,
|
AtlasAttachmentLoader,
|
||||||
BlendMode,
|
BlendMode,
|
||||||
ClippingAttachment,
|
ClippingAttachment,
|
||||||
Color,
|
type Color,
|
||||||
|
MathUtils,
|
||||||
MeshAttachment,
|
MeshAttachment,
|
||||||
type NumberArrayLike,
|
type NumberArrayLike,
|
||||||
Physics,
|
Physics,
|
||||||
@ -224,12 +225,10 @@ export class SkeletonDrawable {
|
|||||||
*/
|
*/
|
||||||
export class SkeletonRenderer {
|
export class SkeletonRenderer {
|
||||||
private clipper = new SkeletonClipping();
|
private clipper = new SkeletonClipping();
|
||||||
private tempColor = new Color();
|
|
||||||
private tempColor2 = new Color();
|
|
||||||
private static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
|
private static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
|
||||||
private scratchPositions = Utils.newFloatArray(100);
|
private scratchPositions = Utils.newFloatArray(100);
|
||||||
private scratchColors = Utils.newFloatArray(100);
|
|
||||||
private scratchUVs = Utils.newFloatArray(100);
|
private scratchUVs = Utils.newFloatArray(100);
|
||||||
|
private scratchColors = new Uint32Array(100 / 4);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new skeleton renderer.
|
* Creates a new skeleton renderer.
|
||||||
@ -257,50 +256,40 @@ export class SkeletonRenderer {
|
|||||||
|
|
||||||
const attachment = slot.getAttachment();
|
const attachment = slot.getAttachment();
|
||||||
let positions = this.scratchPositions;
|
let positions = this.scratchPositions;
|
||||||
let colors = this.scratchColors;
|
|
||||||
let uvs: NumberArrayLike;
|
|
||||||
let texture: CanvasKitTexture;
|
|
||||||
let triangles: Array<number>;
|
let triangles: Array<number>;
|
||||||
let attachmentColor: Color;
|
let numVertices = 4;
|
||||||
let numVertices = 0;
|
|
||||||
if (attachment instanceof RegionAttachment) {
|
if (attachment instanceof RegionAttachment) {
|
||||||
const region = attachment;
|
attachment.computeWorldVertices(slot, positions, 0, 2);
|
||||||
numVertices = 4;
|
|
||||||
region.computeWorldVertices(slot, positions, 0, 2);
|
|
||||||
triangles = SkeletonRenderer.QUAD_TRIANGLES;
|
triangles = SkeletonRenderer.QUAD_TRIANGLES;
|
||||||
uvs = region.uvs as Float32Array;
|
|
||||||
texture = region.region ?.texture as CanvasKitTexture;
|
|
||||||
attachmentColor = region.color;
|
|
||||||
} else if (attachment instanceof MeshAttachment) {
|
} else if (attachment instanceof MeshAttachment) {
|
||||||
const mesh = attachment as MeshAttachment;
|
if (positions.length < attachment.worldVerticesLength) {
|
||||||
if (positions.length < mesh.worldVerticesLength) {
|
this.scratchPositions = Utils.newFloatArray(attachment.worldVerticesLength);
|
||||||
this.scratchPositions = Utils.newFloatArray(mesh.worldVerticesLength);
|
|
||||||
positions = this.scratchPositions;
|
positions = this.scratchPositions;
|
||||||
}
|
}
|
||||||
numVertices = mesh.worldVerticesLength >> 1;
|
numVertices = attachment.worldVerticesLength >> 1;
|
||||||
mesh.computeWorldVertices(
|
attachment.computeWorldVertices(
|
||||||
slot,
|
slot,
|
||||||
0,
|
0,
|
||||||
mesh.worldVerticesLength,
|
attachment.worldVerticesLength,
|
||||||
positions,
|
positions,
|
||||||
0,
|
0,
|
||||||
2
|
2
|
||||||
);
|
);
|
||||||
triangles = mesh.triangles;
|
triangles = attachment.triangles;
|
||||||
texture = mesh.region ?.texture as CanvasKitTexture;
|
|
||||||
uvs = mesh.uvs as Float32Array;
|
|
||||||
attachmentColor = mesh.color;
|
|
||||||
} else if (attachment instanceof ClippingAttachment) {
|
} else if (attachment instanceof ClippingAttachment) {
|
||||||
const clip = attachment as ClippingAttachment;
|
clipper.clipStart(slot, attachment);
|
||||||
clipper.clipStart(slot, clip);
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
clipper.clipEndWithSlot(slot);
|
clipper.clipEndWithSlot(slot);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const texture = attachment.region?.texture as CanvasKitTexture;
|
||||||
if (texture) {
|
if (texture) {
|
||||||
|
let uvs = attachment.uvs;
|
||||||
let scaledUvs: NumberArrayLike;
|
let scaledUvs: NumberArrayLike;
|
||||||
|
let colors = this.scratchColors;
|
||||||
if (clipper.isClipping()) {
|
if (clipper.isClipping()) {
|
||||||
clipper.clipTrianglesUnpacked(positions, triangles, triangles.length, uvs);
|
clipper.clipTrianglesUnpacked(positions, triangles, triangles.length, uvs);
|
||||||
if (clipper.clippedVertices.length <= 0) {
|
if (clipper.clippedVertices.length <= 0) {
|
||||||
@ -308,21 +297,16 @@ export class SkeletonRenderer {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
positions = clipper.clippedVertices;
|
positions = clipper.clippedVertices;
|
||||||
uvs = clipper.clippedUVs;
|
uvs = scaledUvs = clipper.clippedUVs;
|
||||||
scaledUvs = clipper.clippedUVs;
|
|
||||||
triangles = clipper.clippedTriangles;
|
triangles = clipper.clippedTriangles;
|
||||||
numVertices = clipper.clippedVertices.length / 2;
|
numVertices = clipper.clippedVertices.length / 2;
|
||||||
colors = Utils.newFloatArray(numVertices * 4);
|
colors = new Uint32Array(numVertices);
|
||||||
} else {
|
} else {
|
||||||
scaledUvs = this.scratchUVs;
|
scaledUvs = this.scratchUVs;
|
||||||
if (this.scratchUVs.length < uvs.length) {
|
if (this.scratchUVs.length < uvs.length)
|
||||||
this.scratchUVs = Utils.newFloatArray(uvs.length);
|
scaledUvs = this.scratchUVs = Utils.newFloatArray(uvs.length);
|
||||||
scaledUvs = this.scratchUVs;
|
if (colors.length < numVertices)
|
||||||
}
|
colors = this.scratchColors = new Uint32Array(numVertices);
|
||||||
if (colors.length / 4 < numVertices) {
|
|
||||||
this.scratchColors = Utils.newFloatArray(numVertices * 4);
|
|
||||||
colors = this.scratchColors;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ckImage = texture.getImage();
|
const ckImage = texture.getImage();
|
||||||
@ -334,19 +318,19 @@ export class SkeletonRenderer {
|
|||||||
scaledUvs[i + 1] = uvs[i + 1] * height;
|
scaledUvs[i + 1] = uvs[i + 1] * height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const attachmentColor = attachment.color;
|
||||||
const slotColor = slot.color;
|
const slotColor = slot.color;
|
||||||
const finalColor = this.tempColor;
|
|
||||||
finalColor.r = skeletonColor.r * slotColor.r * attachmentColor.r;
|
|
||||||
finalColor.g = skeletonColor.g * slotColor.g * attachmentColor.g;
|
|
||||||
finalColor.b = skeletonColor.b * slotColor.b * attachmentColor.b;
|
|
||||||
finalColor.a = skeletonColor.a * slotColor.a * attachmentColor.a;
|
|
||||||
|
|
||||||
for (let i = 0, n = numVertices * 4; i < n; i += 4) {
|
// using Uint32Array for colors allows to avoid canvaskit to allocate one each time
|
||||||
colors[i] = finalColor.r;
|
// but colors need to be in canvaskit format.
|
||||||
colors[i + 1] = finalColor.g;
|
// See: https://github.com/google/skia/blob/bb8c36fdf7b915a8c096e35e2f08109e477fe1b8/modules/canvaskit/color.js#L163
|
||||||
colors[i + 2] = finalColor.b;
|
const finalColor = (
|
||||||
colors[i + 3] = finalColor.a;
|
MathUtils.clamp(skeletonColor.a * slotColor.a * attachmentColor.a * 255, 0, 255) << 24 |
|
||||||
}
|
MathUtils.clamp(skeletonColor.r * slotColor.r * attachmentColor.r * 255, 0, 255) << 16 |
|
||||||
|
MathUtils.clamp(skeletonColor.g * slotColor.g * attachmentColor.g * 255, 0, 255) << 8 |
|
||||||
|
MathUtils.clamp(skeletonColor.b * slotColor.b * attachmentColor.b * 255, 0, 255) << 0
|
||||||
|
) >>> 0;
|
||||||
|
for (let i = 0, n = numVertices; i < n; i++) colors[i] = finalColor;
|
||||||
|
|
||||||
const vertices = this.ck.MakeVertices(
|
const vertices = this.ck.MakeVertices(
|
||||||
this.ck.VertexMode.Triangles,
|
this.ck.VertexMode.Triangles,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user