mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-12 18:18:43 +08:00
[ts] Add SkeletonRendererCore.
This commit is contained in:
parent
75421b2a41
commit
3fa97353f1
@ -34,20 +34,14 @@ import {
|
||||
AnimationStateData,
|
||||
AtlasAttachmentLoader,
|
||||
BlendMode,
|
||||
ClippingAttachment,
|
||||
MathUtils,
|
||||
MeshAttachment,
|
||||
type NumberArrayLike,
|
||||
Physics,
|
||||
RegionAttachment,
|
||||
Skeleton,
|
||||
SkeletonBinary,
|
||||
SkeletonClipping,
|
||||
type SkeletonData,
|
||||
SkeletonJson,
|
||||
SkeletonRendererCore,
|
||||
Texture,
|
||||
TextureAtlas,
|
||||
Utils,
|
||||
} from "@esotericsoftware/spine-core";
|
||||
|
||||
import type { Canvas, CanvasKit, Image, Paint, Shader } from "canvaskit-wasm";
|
||||
@ -223,11 +217,7 @@ export class SkeletonDrawable {
|
||||
* Renders a {@link Skeleton} or {@link SkeletonDrawable} to a CanvasKit {@link Canvas}.
|
||||
*/
|
||||
export class SkeletonRenderer {
|
||||
private clipper = new SkeletonClipping();
|
||||
private static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
|
||||
private scratchPositions = Utils.newFloatArray(100);
|
||||
private scratchUVs = Utils.newFloatArray(100);
|
||||
private scratchColors = new Uint32Array(100 / 4);
|
||||
private skeletonRenderer = new SkeletonRendererCore();
|
||||
|
||||
/**
|
||||
* Creates a new skeleton renderer.
|
||||
@ -235,119 +225,34 @@ export class SkeletonRenderer {
|
||||
*/
|
||||
constructor (private ck: CanvasKit) { }
|
||||
|
||||
/**
|
||||
* Renders a skeleton or skeleton drawable in its current pose to the canvas.
|
||||
* @param canvas the canvas to render to.
|
||||
* @param skeleton the skeleton or drawable to render.
|
||||
*/
|
||||
render (canvas: Canvas, skeleton: Skeleton | SkeletonDrawable) {
|
||||
if (skeleton instanceof SkeletonDrawable) skeleton = skeleton.skeleton;
|
||||
const clipper = this.clipper;
|
||||
const drawOrder = skeleton.drawOrder;
|
||||
const skeletonColor = skeleton.color;
|
||||
let command = this.skeletonRenderer.render(skeleton);
|
||||
while (command) {
|
||||
const { positions, uvs, colors, indices } = command;
|
||||
const ckImage = command.texture.getImage();
|
||||
const image = ckImage.image;
|
||||
const width = image.width();
|
||||
const height = image.height();
|
||||
|
||||
for (let i = 0, n = drawOrder.length; i < n; i++) {
|
||||
const slot = drawOrder[i];
|
||||
if (!slot.bone.active) {
|
||||
clipper.clipEnd(slot);
|
||||
continue;
|
||||
for (let i = 0; i < uvs.length; i += 2) {
|
||||
uvs[i] = uvs[i] * width;
|
||||
uvs[i + 1] = uvs[i + 1] * height;
|
||||
}
|
||||
|
||||
const pose = slot.applied;
|
||||
const attachment = pose.attachment;
|
||||
let positions = this.scratchPositions;
|
||||
let triangles: Array<number>;
|
||||
let numVertices = 4;
|
||||
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
attachment.computeWorldVertices(slot, positions, 0, 2);
|
||||
triangles = SkeletonRenderer.QUAD_TRIANGLES;
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
if (positions.length < attachment.worldVerticesLength) {
|
||||
this.scratchPositions = Utils.newFloatArray(attachment.worldVerticesLength);
|
||||
positions = this.scratchPositions;
|
||||
}
|
||||
numVertices = attachment.worldVerticesLength >> 1;
|
||||
attachment.computeWorldVertices(
|
||||
skeleton,
|
||||
slot,
|
||||
0,
|
||||
attachment.worldVerticesLength,
|
||||
positions,
|
||||
0,
|
||||
2
|
||||
);
|
||||
triangles = attachment.triangles;
|
||||
} else if (attachment instanceof ClippingAttachment) {
|
||||
clipper.clipStart(skeleton, slot, attachment);
|
||||
continue;
|
||||
} else {
|
||||
clipper.clipEnd(slot);
|
||||
continue;
|
||||
}
|
||||
|
||||
const texture = attachment.region?.texture as CanvasKitTexture;
|
||||
if (texture) {
|
||||
let uvs = attachment.uvs;
|
||||
let scaledUvs: NumberArrayLike;
|
||||
let colors = this.scratchColors;
|
||||
if (clipper.isClipping()) {
|
||||
clipper.clipTrianglesUnpacked(positions, triangles, triangles.length, uvs);
|
||||
if (clipper.clippedVertices.length <= 0) {
|
||||
clipper.clipEnd(slot);
|
||||
continue;
|
||||
}
|
||||
positions = clipper.clippedVertices;
|
||||
uvs = scaledUvs = clipper.clippedUVs;
|
||||
triangles = clipper.clippedTriangles;
|
||||
numVertices = clipper.clippedVertices.length / 2;
|
||||
colors = new Uint32Array(numVertices);
|
||||
} else {
|
||||
scaledUvs = this.scratchUVs;
|
||||
if (this.scratchUVs.length < uvs.length)
|
||||
scaledUvs = this.scratchUVs = Utils.newFloatArray(uvs.length);
|
||||
if (colors.length < numVertices)
|
||||
colors = this.scratchColors = new Uint32Array(numVertices);
|
||||
}
|
||||
|
||||
const ckImage = texture.getImage();
|
||||
const image = ckImage.image;
|
||||
const width = image.width();
|
||||
const height = image.height();
|
||||
for (let i = 0; i < uvs.length; i += 2) {
|
||||
scaledUvs[i] = uvs[i] * width;
|
||||
scaledUvs[i + 1] = uvs[i + 1] * height;
|
||||
}
|
||||
|
||||
const attachmentColor = attachment.color;
|
||||
const slotColor = pose.color;
|
||||
|
||||
// using Uint32Array for colors allows to avoid canvaskit to allocate one each time
|
||||
// but colors need to be in canvaskit format.
|
||||
// See: https://github.com/google/skia/blob/bb8c36fdf7b915a8c096e35e2f08109e477fe1b8/modules/canvaskit/color.js#L163
|
||||
const finalColor = (
|
||||
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(
|
||||
this.ck.VertexMode.Triangles,
|
||||
positions,
|
||||
scaledUvs,
|
||||
colors,
|
||||
triangles,
|
||||
false
|
||||
);
|
||||
const ckPaint = ckImage.paintPerBlendMode.get(slot.data.blendMode);
|
||||
if (ckPaint) canvas.drawVertices(vertices, this.ck.BlendMode.Modulate, ckPaint);
|
||||
vertices.delete();
|
||||
}
|
||||
|
||||
clipper.clipEnd(slot);
|
||||
const vertices = this.ck.MakeVertices(
|
||||
this.ck.VertexMode.Triangles,
|
||||
positions,
|
||||
uvs,
|
||||
colors,
|
||||
indices as any as number[],
|
||||
false
|
||||
);
|
||||
const ckPaint = ckImage.paintPerBlendMode.get(command.blendMode);
|
||||
if (ckPaint) canvas.drawVertices(vertices, this.ck.BlendMode.Modulate, ckPaint);
|
||||
vertices.delete();
|
||||
command = command.next;
|
||||
}
|
||||
clipper.clipEnd();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -43,6 +43,17 @@ export class SkeletonClipping {
|
||||
clippedUVs = new Array<number>();
|
||||
|
||||
clippedTriangles = new Array<number>();
|
||||
|
||||
_clippedVerticesTyped = new Float32Array(1024);
|
||||
_clippedUVsTyped = new Float32Array(1024);
|
||||
_clippedTrianglesTyped = new Uint32Array(1024);
|
||||
clippedVerticesTyped = new Float32Array(0);
|
||||
clippedUVsTyped = new Float32Array(0);
|
||||
clippedTrianglesTyped = new Uint32Array(0);
|
||||
clippedVerticesLength = 0;
|
||||
clippedUVsLength = 0;
|
||||
clippedTrianglesLength = 0;
|
||||
|
||||
private scratch = new Array<number>();
|
||||
|
||||
private clipAttachment: ClippingAttachment | null = null;
|
||||
@ -76,6 +87,9 @@ export class SkeletonClipping {
|
||||
this.clippedVertices.length = 0;
|
||||
this.clippedTriangles.length = 0;
|
||||
this.clippingPolygon.length = 0;
|
||||
this.clippedVerticesLength = 0;
|
||||
this.clippedUVsLength = 0;
|
||||
this.clippedTrianglesLength = 0;
|
||||
}
|
||||
|
||||
isClipping (): boolean {
|
||||
@ -308,55 +322,82 @@ export class SkeletonClipping {
|
||||
return clipOutputItems != null;
|
||||
}
|
||||
|
||||
public clipTrianglesUnpacked (vertices: NumberArrayLike, triangles: NumberArrayLike, trianglesLength: number, uvs: NumberArrayLike) {
|
||||
let clipOutput = this.clipOutput, clippedVertices = this.clippedVertices, clippedUVs = this.clippedUVs;
|
||||
let clippedTriangles = this.clippedTriangles;
|
||||
let polygons = this.clippingPolygons!;
|
||||
let polygonsCount = polygons.length;
|
||||
public clipTrianglesUnpacked (vertices: NumberArrayLike, triangles: NumberArrayLike | Uint32Array, trianglesLength: number, uvs: NumberArrayLike) {
|
||||
const clipOutput = this.clipOutput;
|
||||
let clippedVertices = this._clippedVerticesTyped, clippedUVs = this._clippedUVsTyped, clippedTriangles = this._clippedTrianglesTyped;
|
||||
const polygons = this.clippingPolygons!;
|
||||
const polygonsCount = polygons.length;
|
||||
|
||||
let index = 0;
|
||||
clippedVertices.length = 0;
|
||||
clippedUVs.length = 0;
|
||||
clippedTriangles.length = 0;
|
||||
this.clippedVerticesLength = 0;
|
||||
this.clippedUVsLength = 0;
|
||||
this.clippedTrianglesLength = 0;
|
||||
|
||||
this._clippedVerticesTyped;
|
||||
this._clippedUVsTyped;
|
||||
this._clippedTrianglesTyped;
|
||||
|
||||
let clipped = false;
|
||||
|
||||
for (let i = 0; i < trianglesLength; i += 3) {
|
||||
let v = triangles[i] << 1;
|
||||
let x1 = vertices[v], y1 = vertices[v + 1];
|
||||
let u1 = uvs[v], v1 = uvs[v + 1];
|
||||
const x1 = vertices[v], y1 = vertices[v + 1];
|
||||
const u1 = uvs[v], v1 = uvs[v + 1];
|
||||
|
||||
v = triangles[i + 1] << 1;
|
||||
let x2 = vertices[v], y2 = vertices[v + 1];
|
||||
let u2 = uvs[v], v2 = uvs[v + 1];
|
||||
const x2 = vertices[v], y2 = vertices[v + 1];
|
||||
const u2 = uvs[v], v2 = uvs[v + 1];
|
||||
|
||||
v = triangles[i + 2] << 1;
|
||||
let x3 = vertices[v], y3 = vertices[v + 1];
|
||||
let u3 = uvs[v], v3 = uvs[v + 1];
|
||||
const x3 = vertices[v], y3 = vertices[v + 1];
|
||||
const u3 = uvs[v], v3 = uvs[v + 1];
|
||||
|
||||
for (let p = 0; p < polygonsCount; p++) {
|
||||
let s = clippedVertices.length;
|
||||
let s = this.clippedVerticesLength;
|
||||
if (this.clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) {
|
||||
let clipOutputLength = clipOutput.length;
|
||||
if (clipOutputLength == 0) continue;
|
||||
let d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1;
|
||||
let d = 1 / (d0 * d2 + d1 * (y1 - y3));
|
||||
const clipOutputLength = clipOutput.length;
|
||||
if (clipOutputLength === 0) continue;
|
||||
clipped = true;
|
||||
const d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1;
|
||||
const d = 1 / (d0 * d2 + d1 * (y1 - y3));
|
||||
|
||||
let clipOutputCount = clipOutputLength >> 1;
|
||||
let clipOutputItems = this.clipOutput;
|
||||
let clippedVerticesItems = Utils.setArraySize(clippedVertices, s + clipOutputCount * 2);
|
||||
let clippedUVsItems = Utils.setArraySize(clippedUVs, s + clipOutputCount * 2);
|
||||
const clipOutputItems = this.clipOutput;
|
||||
|
||||
const newLength = s + clipOutputCount * 2;
|
||||
if (clippedVertices.length < newLength) {
|
||||
this._clippedVerticesTyped = new Float32Array(newLength * 2);
|
||||
this._clippedVerticesTyped.set(clippedVertices.subarray(0, s));
|
||||
this._clippedUVsTyped = new Float32Array(newLength * 2);
|
||||
this._clippedUVsTyped.set(clippedUVs.subarray(0, s));
|
||||
clippedVertices = this._clippedVerticesTyped;
|
||||
clippedUVs = this._clippedUVsTyped;
|
||||
}
|
||||
const clippedVerticesItems = clippedVertices;
|
||||
const clippedUVsItems = clippedUVs;
|
||||
this.clippedVerticesLength = newLength;
|
||||
this.clippedUVsLength = newLength;
|
||||
for (let ii = 0; ii < clipOutputLength; ii += 2, s += 2) {
|
||||
let x = clipOutputItems[ii], y = clipOutputItems[ii + 1];
|
||||
const x = clipOutputItems[ii], y = clipOutputItems[ii + 1];
|
||||
clippedVerticesItems[s] = x;
|
||||
clippedVerticesItems[s + 1] = y;
|
||||
let c0 = x - x3, c1 = y - y3;
|
||||
let a = (d0 * c0 + d1 * c1) * d;
|
||||
let b = (d4 * c0 + d2 * c1) * d;
|
||||
let c = 1 - a - b;
|
||||
const c0 = x - x3, c1 = y - y3;
|
||||
const a = (d0 * c0 + d1 * c1) * d;
|
||||
const b = (d4 * c0 + d2 * c1) * d;
|
||||
const c = 1 - a - b;
|
||||
clippedUVsItems[s] = u1 * a + u2 * b + u3 * c;
|
||||
clippedUVsItems[s + 1] = v1 * a + v2 * b + v3 * c;
|
||||
}
|
||||
|
||||
s = clippedTriangles.length;
|
||||
let clippedTrianglesItems = Utils.setArraySize(clippedTriangles, s + 3 * (clipOutputCount - 2));
|
||||
s = this.clippedTrianglesLength;
|
||||
const newLengthTriangles = s + 3 * (clipOutputCount - 2)
|
||||
if (clippedTriangles.length < newLengthTriangles) {
|
||||
this._clippedTrianglesTyped = new Uint32Array(newLengthTriangles * 2);
|
||||
this._clippedTrianglesTyped.set(clippedTriangles.subarray(0, s));
|
||||
clippedTriangles = this._clippedTrianglesTyped;
|
||||
}
|
||||
this.clippedTrianglesLength = newLengthTriangles;
|
||||
const clippedTrianglesItems = clippedTriangles;
|
||||
clipOutputCount--;
|
||||
for (let ii = 1; ii < clipOutputCount; ii++, s += 3) {
|
||||
clippedTrianglesItems[s] = index;
|
||||
@ -366,32 +407,58 @@ export class SkeletonClipping {
|
||||
index += clipOutputCount + 1;
|
||||
|
||||
} else {
|
||||
let clippedVerticesItems = Utils.setArraySize(clippedVertices, s + 3 * 2);
|
||||
clippedVerticesItems[s] = x1;
|
||||
clippedVerticesItems[s + 1] = y1;
|
||||
clippedVerticesItems[s + 2] = x2;
|
||||
clippedVerticesItems[s + 3] = y2;
|
||||
clippedVerticesItems[s + 4] = x3;
|
||||
clippedVerticesItems[s + 5] = y3;
|
||||
|
||||
let clippedUVSItems = Utils.setArraySize(clippedUVs, s + 3 * 2);
|
||||
clippedUVSItems[s] = u1;
|
||||
clippedUVSItems[s + 1] = v1;
|
||||
clippedUVSItems[s + 2] = u2;
|
||||
clippedUVSItems[s + 3] = v2;
|
||||
clippedUVSItems[s + 4] = u3;
|
||||
clippedUVSItems[s + 5] = v3;
|
||||
let newLength = s + 3 * 2;
|
||||
if (clippedVertices.length < newLength) {
|
||||
this._clippedVerticesTyped = new Float32Array(newLength * 2);
|
||||
this._clippedVerticesTyped.set(clippedVertices.subarray(0, s));
|
||||
clippedVertices = this._clippedVerticesTyped;
|
||||
}
|
||||
clippedVertices[s] = x1;
|
||||
clippedVertices[s + 1] = y1;
|
||||
clippedVertices[s + 2] = x2;
|
||||
clippedVertices[s + 3] = y2;
|
||||
clippedVertices[s + 4] = x3;
|
||||
clippedVertices[s + 5] = y3;
|
||||
|
||||
s = clippedTriangles.length;
|
||||
let clippedTrianglesItems = Utils.setArraySize(clippedTriangles, s + 3);
|
||||
clippedTrianglesItems[s] = index;
|
||||
clippedTrianglesItems[s + 1] = (index + 1);
|
||||
clippedTrianglesItems[s + 2] = (index + 2);
|
||||
if (clippedUVs.length < newLength) {
|
||||
this._clippedUVsTyped = new Float32Array(newLength * 2);
|
||||
this._clippedUVsTyped.set(clippedUVs.subarray(0, s));
|
||||
clippedUVs = this._clippedUVsTyped;
|
||||
}
|
||||
clippedUVs[s] = u1;
|
||||
clippedUVs[s + 1] = v1;
|
||||
clippedUVs[s + 2] = u2;
|
||||
clippedUVs[s + 3] = v2;
|
||||
clippedUVs[s + 4] = u3;
|
||||
clippedUVs[s + 5] = v3;
|
||||
|
||||
this.clippedVerticesLength = newLength;
|
||||
this.clippedUVsLength = newLength;
|
||||
|
||||
s = this.clippedTrianglesLength;
|
||||
newLength = s + 3;
|
||||
if (clippedTriangles.length < newLength) {
|
||||
this._clippedTrianglesTyped = new Uint32Array(newLength * 2);
|
||||
this._clippedTrianglesTyped.set(clippedTriangles.subarray(0, s));
|
||||
clippedTriangles = this._clippedTrianglesTyped;
|
||||
}
|
||||
|
||||
clippedTriangles[s] = index;
|
||||
clippedTriangles[s + 1] = (index + 1);
|
||||
clippedTriangles[s + 2] = (index + 2);
|
||||
index += 3;
|
||||
|
||||
this.clippedTrianglesLength = newLength;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.clippedVerticesTyped = this._clippedVerticesTyped.subarray(0, this.clippedVerticesLength)
|
||||
this.clippedUVsTyped = this._clippedUVsTyped.subarray(0, this.clippedUVsLength)
|
||||
this.clippedTrianglesTyped = this._clippedTrianglesTyped.subarray(0, this.clippedTrianglesLength)
|
||||
return clipped;
|
||||
}
|
||||
|
||||
/** Clips the input triangle against the convex, clockwise clipping area. If the triangle lies entirely within the clipping
|
||||
|
||||
@ -1,8 +1,18 @@
|
||||
export * from './Animation.js';
|
||||
export * from './AnimationState.js';
|
||||
export * from './AnimationStateData.js';
|
||||
export * from './AtlasAttachmentLoader.js';
|
||||
export * from './AssetManagerBase.js';
|
||||
export * from './AtlasAttachmentLoader.js';
|
||||
export * from './attachments/Attachment.js';
|
||||
export * from './attachments/AttachmentLoader.js';
|
||||
export * from './attachments/BoundingBoxAttachment.js';
|
||||
export * from './attachments/ClippingAttachment.js';
|
||||
export * from './attachments/HasTextureRegion.js';
|
||||
export * from './attachments/MeshAttachment.js';
|
||||
export * from './attachments/PathAttachment.js';
|
||||
export * from './attachments/PointAttachment.js';
|
||||
export * from './attachments/RegionAttachment.js';
|
||||
export * from './attachments/Sequence.js';
|
||||
export * from './Bone.js';
|
||||
export * from './BoneData.js';
|
||||
export * from './BoneLocal.js';
|
||||
@ -25,12 +35,14 @@ export * from './Pose.js';
|
||||
export * from './Posed.js';
|
||||
export * from './PosedActive.js';
|
||||
export * from './PosedData.js';
|
||||
export * from './polyfills.js';
|
||||
export * from './Skeleton.js';
|
||||
export * from './SkeletonBinary.js';
|
||||
export * from './SkeletonBounds.js';
|
||||
export * from './SkeletonClipping.js';
|
||||
export * from './SkeletonData.js';
|
||||
export * from './SkeletonJson.js';
|
||||
export * from './SkeletonRendererCore.js';
|
||||
export * from './Skin.js';
|
||||
export * from './Slider.js';
|
||||
export * from './SliderData.js';
|
||||
@ -46,14 +58,3 @@ export * from './TransformConstraintPose.js';
|
||||
export * from './Triangulator.js';
|
||||
export * from './Update.js';
|
||||
export * from './Utils.js';
|
||||
export * from './polyfills.js';
|
||||
export * from './attachments/Attachment.js';
|
||||
export * from './attachments/AttachmentLoader.js';
|
||||
export * from './attachments/BoundingBoxAttachment.js';
|
||||
export * from './attachments/ClippingAttachment.js';
|
||||
export * from './attachments/HasTextureRegion.js';
|
||||
export * from './attachments/MeshAttachment.js';
|
||||
export * from './attachments/PathAttachment.js';
|
||||
export * from './attachments/PointAttachment.js';
|
||||
export * from './attachments/RegionAttachment.js';
|
||||
export * from './attachments/Sequence.js';
|
||||
|
||||
@ -27,27 +27,12 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import {
|
||||
Assets,
|
||||
Bounds,
|
||||
Cache,
|
||||
Container,
|
||||
ContainerOptions,
|
||||
DestroyOptions,
|
||||
fastCopy,
|
||||
Graphics,
|
||||
PointData,
|
||||
Texture,
|
||||
Ticker,
|
||||
ViewContainer,
|
||||
} from 'pixi.js';
|
||||
import { ISpineDebugRenderer } from './SpineDebugRenderer.js';
|
||||
import {
|
||||
AnimationState,
|
||||
AnimationStateData,
|
||||
AtlasAttachmentLoader,
|
||||
Attachment,
|
||||
Bone,
|
||||
type Attachment,
|
||||
type Bone,
|
||||
ClippingAttachment,
|
||||
Color,
|
||||
MeshAttachment,
|
||||
@ -61,11 +46,26 @@ import {
|
||||
SkeletonData,
|
||||
SkeletonJson,
|
||||
Skin,
|
||||
Slot,
|
||||
type Slot,
|
||||
type TextureAtlas,
|
||||
TrackEntry,
|
||||
type TrackEntry,
|
||||
Vector2,
|
||||
} from '@esotericsoftware/spine-core';
|
||||
import {
|
||||
Assets,
|
||||
type Bounds,
|
||||
Cache,
|
||||
Container,
|
||||
type ContainerOptions,
|
||||
type DestroyOptions,
|
||||
fastCopy,
|
||||
Graphics,
|
||||
type PointData,
|
||||
Texture,
|
||||
Ticker,
|
||||
ViewContainer,
|
||||
} from 'pixi.js';
|
||||
import type { ISpineDebugRenderer } from './SpineDebugRenderer.js';
|
||||
|
||||
/**
|
||||
* Options to create a {@link Spine} using {@link Spine.from}.
|
||||
@ -142,7 +142,7 @@ export class SetupPoseBoundsProvider implements SpineBoundsProvider {
|
||||
skeleton.setupPose();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
const bounds = skeleton.getBoundsRect(this.clipping ? new SkeletonClipping() : undefined);
|
||||
return bounds.width == Number.NEGATIVE_INFINITY
|
||||
return bounds.width === Number.NEGATIVE_INFINITY
|
||||
? { x: 0, y: 0, width: 0, height: 0 }
|
||||
: bounds;
|
||||
}
|
||||
@ -180,7 +180,7 @@ export class SkinsAndAnimationBoundsProvider
|
||||
const clipper = this.clipping ? new SkeletonClipping() : undefined;
|
||||
const data = skeleton.data;
|
||||
if (this.skins.length > 0) {
|
||||
let customSkin = new Skin("custom-skin");
|
||||
const customSkin = new Skin("custom-skin");
|
||||
for (const skinName of this.skins) {
|
||||
const skin = data.findSkin(skinName);
|
||||
if (skin == null) continue;
|
||||
@ -190,12 +190,12 @@ export class SkinsAndAnimationBoundsProvider
|
||||
}
|
||||
skeleton.setupPose();
|
||||
|
||||
const animation = this.animation != null ? data.findAnimation(this.animation!) : null;
|
||||
const animation = this.animation != null ? data.findAnimation(this.animation) : null;
|
||||
|
||||
if (animation == null) {
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
const bounds = skeleton.getBoundsRect(clipper);
|
||||
return bounds.width == Number.NEGATIVE_INFINITY
|
||||
return bounds.width === Number.NEGATIVE_INFINITY
|
||||
? { x: 0, y: 0, width: 0, height: 0 }
|
||||
: bounds;
|
||||
} else {
|
||||
@ -225,7 +225,7 @@ export class SkinsAndAnimationBoundsProvider
|
||||
width: maxX - minX,
|
||||
height: maxY - minY,
|
||||
};
|
||||
return bounds.width == Number.NEGATIVE_INFINITY
|
||||
return bounds.width === Number.NEGATIVE_INFINITY
|
||||
? { x: 0, y: 0, width: 0, height: 0 }
|
||||
: bounds;
|
||||
}
|
||||
@ -414,10 +414,10 @@ export class Spine extends ViewContainer {
|
||||
|
||||
/** If {@link Spine.autoUpdate} is `false`, this method allows to update the AnimationState and the Skeleton with the given delta. */
|
||||
public update (dt: number): void {
|
||||
this.internalUpdate(0, dt);
|
||||
this.internalUpdate(undefined, dt);
|
||||
}
|
||||
|
||||
protected internalUpdate (_deltaFrame: any, deltaSeconds?: number): void {
|
||||
protected internalUpdate (ticker?: Ticker, deltaSeconds?: number): void {
|
||||
// Because reasons, pixi uses deltaFrames at 60fps.
|
||||
// We ignore the default deltaFrames and use the deltaSeconds from pixi ticker.
|
||||
this._updateAndApplyState(deltaSeconds ?? Ticker.shared.deltaMS / 1000);
|
||||
@ -568,18 +568,18 @@ export class Spine extends ViewContainer {
|
||||
const pose = slot.applied;
|
||||
const attachment = pose.attachment;
|
||||
if (attachment && attachment instanceof ClippingAttachment) {
|
||||
const clip = (this.clippingSlotToPixiMasks[slot.data.name] ||= { slot, vertices: new Array<number>() });
|
||||
const clip = (this.clippingSlotToPixiMasks[slot.data.name] ||= { slot, vertices: [] as number[] });
|
||||
clip.maskComputed = false;
|
||||
this.currentClippingSlot = this.clippingSlotToPixiMasks[slot.data.name];
|
||||
return;
|
||||
}
|
||||
|
||||
// assign the currentClippingSlot mask to the slot object
|
||||
let currentClippingSlot = this.currentClippingSlot;
|
||||
let slotObject = this._slotsObject[slot.data.name];
|
||||
const currentClippingSlot = this.currentClippingSlot;
|
||||
const slotObject = this._slotsObject[slot.data.name];
|
||||
if (currentClippingSlot && slotObject) {
|
||||
let slotClipping = currentClippingSlot.slot;
|
||||
let clippingAttachment = slotClipping.pose.attachment as ClippingAttachment;
|
||||
const slotClipping = currentClippingSlot.slot;
|
||||
const clippingAttachment = slotClipping.pose.attachment as ClippingAttachment;
|
||||
|
||||
// create the pixi mask, only the first time and if the clipped slot is the first one clipped by this currentClippingSlot
|
||||
let mask = currentClippingSlot.mask as Graphics;
|
||||
@ -604,7 +604,7 @@ export class Spine extends ViewContainer {
|
||||
}
|
||||
|
||||
// if current slot is the ending one of the currentClippingSlot mask, set currentClippingSlot to undefined
|
||||
if (currentClippingSlot && (currentClippingSlot.slot.applied.attachment as ClippingAttachment).endSlot == slot.data) {
|
||||
if (currentClippingSlot && (currentClippingSlot.slot.applied.attachment as ClippingAttachment).endSlot === slot.data) {
|
||||
this.currentClippingSlot = undefined;
|
||||
}
|
||||
|
||||
@ -711,10 +711,10 @@ export class Spine extends ViewContainer {
|
||||
cacheData.uvs,
|
||||
);
|
||||
|
||||
const { clippedVertices, clippedUVs, clippedTriangles } = clipper;
|
||||
const { clippedVerticesTyped, clippedUVsTyped, clippedTrianglesTyped } = clipper;
|
||||
|
||||
const verticesCount = clippedVertices.length / 2;
|
||||
const indicesCount = clippedTriangles.length;
|
||||
const verticesCount = clipper.clippedVerticesLength / 2;
|
||||
const indicesCount = clipper.clippedTrianglesLength;
|
||||
|
||||
if (!cacheData.clippedData) {
|
||||
cacheData.clippedData = {
|
||||
@ -749,24 +749,10 @@ export class Spine extends ViewContainer {
|
||||
}
|
||||
|
||||
const { vertices, uvs, indices } = clippedData;
|
||||
|
||||
for (let i = 0; i < verticesCount; i++) {
|
||||
vertices[i * 2] = clippedVertices[i * 2];
|
||||
vertices[(i * 2) + 1] = clippedVertices[(i * 2) + 1];
|
||||
|
||||
uvs[i * 2] = clippedUVs[(i * 2)];
|
||||
uvs[(i * 2) + 1] = clippedUVs[(i * 2) + 1];
|
||||
}
|
||||
|
||||
vertices.set(clippedVerticesTyped);
|
||||
uvs.set(clippedUVsTyped);
|
||||
indices.set(clippedTrianglesTyped);
|
||||
clippedData.vertexCount = verticesCount;
|
||||
|
||||
for (let i = 0; i < indicesCount; i++) {
|
||||
if (indices[i] !== clippedTriangles[i]) {
|
||||
this.spineAttachmentsDirty = true;
|
||||
indices[i] = clippedTriangles[i];
|
||||
}
|
||||
}
|
||||
|
||||
clippedData.indicesCount = indicesCount;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user