mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-06 07:14:55 +08:00
[ts] Processed spine-ts (not player) with biome.
This commit is contained in:
parent
9ea694b16f
commit
c3ac62d1dd
64
spine-ts/assets/mask_empty.json
Normal file
64
spine-ts/assets/mask_empty.json
Normal file
@ -0,0 +1,64 @@
|
||||
{
|
||||
"skeleton": {
|
||||
"hash": "kUVJGzLCHio",
|
||||
"spine": "4.2.43",
|
||||
"x": -66,
|
||||
"y": -141.5,
|
||||
"width": 142,
|
||||
"height": 232,
|
||||
"images": "./images/",
|
||||
"audio": "./audio"
|
||||
},
|
||||
"bones": [
|
||||
{ "name": "root" },
|
||||
{ "name": "empty_1", "parent": "root", "x": -44, "y": 53.5 },
|
||||
{ "name": "empty_8", "parent": "root", "x": 5, "y": -104.5 },
|
||||
{ "name": "empty_7", "parent": "root", "x": -44, "y": -104.5 },
|
||||
{ "name": "empty_6", "parent": "root", "x": 54, "y": -25.5 },
|
||||
{ "name": "empty_5", "parent": "root", "x": 5, "y": -25.5 },
|
||||
{ "name": "empty_4", "parent": "root", "x": -44, "y": -25.5 },
|
||||
{ "name": "empty_3", "parent": "root", "x": 54, "y": 53.5 },
|
||||
{ "name": "empty_2", "parent": "root", "x": 5, "y": 53.5 }
|
||||
],
|
||||
"slots": [
|
||||
{ "name": "mask", "bone": "root", "attachment": "mask" },
|
||||
{ "name": "empty_1", "bone": "empty_1", "attachment": "empty" },
|
||||
{ "name": "empty_2", "bone": "empty_2", "attachment": "empty" },
|
||||
{ "name": "empty_3", "bone": "empty_3", "attachment": "empty" },
|
||||
{ "name": "empty_4", "bone": "empty_4", "attachment": "empty" },
|
||||
{ "name": "empty_5", "bone": "empty_5", "attachment": "empty" },
|
||||
{ "name": "empty_6", "bone": "empty_6", "attachment": "empty" },
|
||||
{ "name": "empty_7", "bone": "empty_7", "attachment": "empty" },
|
||||
{ "name": "empty_8", "bone": "empty_8", "attachment": "empty" }
|
||||
],
|
||||
"skins": [
|
||||
{
|
||||
"name": "default",
|
||||
"attachments": {
|
||||
"empty_1": { "empty": { "width": 44, "height": 74 } },
|
||||
"empty_2": { "empty": { "width": 44, "height": 74 } },
|
||||
"empty_3": { "empty": { "width": 44, "height": 74 } },
|
||||
"empty_4": { "empty": { "width": 44, "height": 74 } },
|
||||
"empty_5": { "empty": { "width": 44, "height": 74 } },
|
||||
"empty_6": { "empty": { "width": 44, "height": 74 } },
|
||||
"empty_7": { "empty": { "width": 44, "height": 74 } },
|
||||
"empty_8": { "empty": { "width": 44, "height": 74 } },
|
||||
"mask": {
|
||||
"mask": {
|
||||
"type": "clipping",
|
||||
"end": "mask",
|
||||
"vertexCount": 16,
|
||||
"vertices": [
|
||||
-53.67, -27.41, -147.5, -13.5, -65, 33.5, -92.5, 70.5, -21.01,
|
||||
32.95, 12.5, 114.5, 36.79, 30.32, 129.5, 66.5, 93, 30.5, 124.5,
|
||||
-5.5, 98, -51.5, 139.5, -97.5, 38.8, -65.21, -9.5, -181.5, -26.27,
|
||||
-70.62, -106.5, -105.5
|
||||
],
|
||||
"color": "ce3a3aff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"animations": { "animation": {} }
|
||||
}
|
||||
@ -16,7 +16,8 @@
|
||||
"useExponentiationOperator": "off"
|
||||
},
|
||||
"suspicious": {
|
||||
"noAssignInExpressions": "off"
|
||||
"noAssignInExpressions": "off",
|
||||
"noPrototypeBuiltins": "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Texture, TextureFilter, TextureWrap } from "@esotericsoftware/spine-core";
|
||||
import { Texture, type TextureFilter, type TextureWrap } from "@esotericsoftware/spine-core";
|
||||
|
||||
export class CanvasTexture extends Texture {
|
||||
constructor (image: HTMLImageElement | ImageBitmap) {
|
||||
|
||||
@ -27,8 +27,8 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Utils, Color, Skeleton, RegionAttachment, BlendMode, MeshAttachment, Slot, TextureRegion, TextureAtlasRegion } from "@esotericsoftware/spine-core";
|
||||
import { CanvasTexture } from "./CanvasTexture.js";
|
||||
import { type BlendMode, Color, MeshAttachment, RegionAttachment, type Skeleton, type Slot, type TextureRegion, Utils } from "@esotericsoftware/spine-core";
|
||||
import type { CanvasTexture } from "./CanvasTexture.js";
|
||||
|
||||
const worldVertices = Utils.newFloatArray(8);
|
||||
|
||||
@ -53,28 +53,28 @@ export class SkeletonRenderer {
|
||||
}
|
||||
|
||||
private drawImages (skeleton: Skeleton) {
|
||||
let ctx = this.ctx;
|
||||
let color = this.tempColor;
|
||||
let skeletonColor = skeleton.color;
|
||||
let drawOrder = skeleton.drawOrder;
|
||||
const ctx = this.ctx;
|
||||
const color = this.tempColor;
|
||||
const skeletonColor = skeleton.color;
|
||||
const drawOrder = skeleton.drawOrder;
|
||||
|
||||
if (this.debugRendering) ctx.strokeStyle = "green";
|
||||
|
||||
for (let i = 0, n = drawOrder.length; i < n; i++) {
|
||||
const slot = drawOrder[i];
|
||||
let bone = slot.bone;
|
||||
const bone = slot.bone;
|
||||
if (!bone.active) continue;
|
||||
|
||||
let pose = slot.applied;
|
||||
let attachment = pose.attachment;
|
||||
const pose = slot.applied;
|
||||
const attachment = pose.attachment;
|
||||
if (!(attachment instanceof RegionAttachment)) continue;
|
||||
attachment.computeWorldVertices(slot, worldVertices, 0, 2);
|
||||
let region: TextureRegion = <TextureRegion>attachment.region;
|
||||
const region: TextureRegion = <TextureRegion>attachment.region;
|
||||
|
||||
let image: HTMLImageElement = (<CanvasTexture>region.texture).getImage() as HTMLImageElement;
|
||||
const image: HTMLImageElement = (<CanvasTexture>region.texture).getImage() as HTMLImageElement;
|
||||
|
||||
let slotColor = pose.color;
|
||||
let regionColor = attachment.color;
|
||||
const slotColor = pose.color;
|
||||
const regionColor = attachment.color;
|
||||
color.set(skeletonColor.r * slotColor.r * regionColor.r,
|
||||
skeletonColor.g * slotColor.g * regionColor.g,
|
||||
skeletonColor.b * slotColor.b * regionColor.b,
|
||||
@ -86,13 +86,13 @@ export class SkeletonRenderer {
|
||||
ctx.translate(attachment.offset[0], attachment.offset[1]);
|
||||
ctx.rotate(attachment.rotation * Math.PI / 180);
|
||||
|
||||
let atlasScale = attachment.width / region.originalWidth;
|
||||
const atlasScale = attachment.width / region.originalWidth;
|
||||
ctx.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY);
|
||||
|
||||
let w = region.width, h = region.height;
|
||||
ctx.translate(w / 2, h / 2);
|
||||
if (attachment.region!.degrees == 90) {
|
||||
let t = w;
|
||||
if (attachment.region?.degrees === 90) {
|
||||
const t = w;
|
||||
w = h;
|
||||
h = t;
|
||||
ctx.rotate(-Math.PI / 2);
|
||||
@ -108,10 +108,10 @@ export class SkeletonRenderer {
|
||||
}
|
||||
|
||||
private drawTriangles (skeleton: Skeleton) {
|
||||
let ctx = this.ctx;
|
||||
let color = this.tempColor;
|
||||
let skeletonColor = skeleton.color;
|
||||
let drawOrder = skeleton.drawOrder;
|
||||
const ctx = this.ctx;
|
||||
const color = this.tempColor;
|
||||
const skeletonColor = skeleton.color;
|
||||
const drawOrder = skeleton.drawOrder;
|
||||
|
||||
let blendMode: BlendMode | null = null;
|
||||
let vertices: ArrayLike<number> = this.vertices;
|
||||
@ -119,28 +119,28 @@ export class SkeletonRenderer {
|
||||
|
||||
for (let i = 0, n = drawOrder.length; i < n; i++) {
|
||||
const slot = drawOrder[i];
|
||||
let pose = slot.applied;
|
||||
let attachment = pose.attachment;
|
||||
const pose = slot.applied;
|
||||
const attachment = pose.attachment;
|
||||
|
||||
let texture: HTMLImageElement;
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
let regionAttachment = <RegionAttachment>attachment;
|
||||
const regionAttachment = <RegionAttachment>attachment;
|
||||
vertices = this.computeRegionVertices(slot, regionAttachment, false);
|
||||
triangles = SkeletonRenderer.QUAD_TRIANGLES;
|
||||
texture = (<CanvasTexture>regionAttachment.region!.texture).getImage() as HTMLImageElement;
|
||||
texture = (<CanvasTexture>regionAttachment.region?.texture).getImage() as HTMLImageElement;
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
let mesh = <MeshAttachment>attachment;
|
||||
const mesh = <MeshAttachment>attachment;
|
||||
vertices = this.computeMeshVertices(slot, mesh, false);
|
||||
triangles = mesh.triangles;
|
||||
texture = (<CanvasTexture>mesh.region!.texture).getImage() as HTMLImageElement;
|
||||
texture = (<CanvasTexture>mesh.region?.texture).getImage() as HTMLImageElement;
|
||||
} else
|
||||
continue;
|
||||
|
||||
if (texture) {
|
||||
if (slot.data.blendMode != blendMode) blendMode = slot.data.blendMode;
|
||||
if (slot.data.blendMode !== blendMode) blendMode = slot.data.blendMode;
|
||||
|
||||
let slotColor = pose.color;
|
||||
let attachmentColor = attachment.color;
|
||||
const slotColor = pose.color;
|
||||
const attachmentColor = attachment.color;
|
||||
color.set(skeletonColor.r * slotColor.r * attachmentColor.r,
|
||||
skeletonColor.g * slotColor.g * attachmentColor.g,
|
||||
skeletonColor.b * slotColor.b * attachmentColor.b,
|
||||
@ -148,12 +148,12 @@ export class SkeletonRenderer {
|
||||
|
||||
ctx.globalAlpha = color.a;
|
||||
|
||||
for (var j = 0; j < triangles.length; j += 3) {
|
||||
let t1 = triangles[j] * 8, t2 = triangles[j + 1] * 8, t3 = triangles[j + 2] * 8;
|
||||
for (let j = 0; j < triangles.length; j += 3) {
|
||||
const t1 = triangles[j] * 8, t2 = triangles[j + 1] * 8, t3 = triangles[j + 2] * 8;
|
||||
|
||||
let x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7];
|
||||
let x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7];
|
||||
let x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7];
|
||||
const x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7];
|
||||
const x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7];
|
||||
const x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7];
|
||||
|
||||
this.drawTriangle(texture, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2);
|
||||
|
||||
@ -178,7 +178,7 @@ export class SkeletonRenderer {
|
||||
private drawTriangle (img: HTMLImageElement, x0: number, y0: number, u0: number, v0: number,
|
||||
x1: number, y1: number, u1: number, v1: number,
|
||||
x2: number, y2: number, u2: number, v2: number) {
|
||||
let ctx = this.ctx;
|
||||
const ctx = this.ctx;
|
||||
|
||||
const width = img.width - 1;
|
||||
const height = img.height - 1;
|
||||
@ -206,7 +206,7 @@ export class SkeletonRenderer {
|
||||
v2 -= v0;
|
||||
|
||||
let det = u1 * v2 - u2 * v1;
|
||||
if (det == 0) return;
|
||||
if (det === 0) return;
|
||||
det = 1 / det;
|
||||
|
||||
// linear transformation
|
||||
@ -227,12 +227,12 @@ export class SkeletonRenderer {
|
||||
}
|
||||
|
||||
private computeRegionVertices (slot: Slot, region: RegionAttachment, pma: boolean) {
|
||||
let skeletonColor = slot.skeleton.color;
|
||||
let slotColor = slot.applied.color;
|
||||
let regionColor = region.color;
|
||||
let alpha = skeletonColor.a * slotColor.a * regionColor.a;
|
||||
let multiplier = pma ? alpha : 1;
|
||||
let color = this.tempColor;
|
||||
const skeletonColor = slot.skeleton.color;
|
||||
const slotColor = slot.applied.color;
|
||||
const regionColor = region.color;
|
||||
const alpha = skeletonColor.a * slotColor.a * regionColor.a;
|
||||
const multiplier = pma ? alpha : 1;
|
||||
const color = this.tempColor;
|
||||
color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier,
|
||||
skeletonColor.g * slotColor.g * regionColor.g * multiplier,
|
||||
skeletonColor.b * slotColor.b * regionColor.b * multiplier,
|
||||
@ -240,8 +240,8 @@ export class SkeletonRenderer {
|
||||
|
||||
region.computeWorldVertices(slot, this.vertices, 0, SkeletonRenderer.VERTEX_SIZE);
|
||||
|
||||
let vertices = this.vertices;
|
||||
let uvs = region.uvs;
|
||||
const vertices = this.vertices;
|
||||
const uvs = region.uvs;
|
||||
|
||||
vertices[RegionAttachment.C1R] = color.r;
|
||||
vertices[RegionAttachment.C1G] = color.g;
|
||||
@ -275,24 +275,24 @@ export class SkeletonRenderer {
|
||||
}
|
||||
|
||||
private computeMeshVertices (slot: Slot, mesh: MeshAttachment, pma: boolean) {
|
||||
let skeleton = slot.skeleton;
|
||||
let skeletonColor = skeleton.color;
|
||||
let slotColor = slot.applied.color;
|
||||
let regionColor = mesh.color;
|
||||
let alpha = skeletonColor.a * slotColor.a * regionColor.a;
|
||||
let multiplier = pma ? alpha : 1;
|
||||
let color = this.tempColor;
|
||||
const skeleton = slot.skeleton;
|
||||
const skeletonColor = skeleton.color;
|
||||
const slotColor = slot.applied.color;
|
||||
const regionColor = mesh.color;
|
||||
const alpha = skeletonColor.a * slotColor.a * regionColor.a;
|
||||
const multiplier = pma ? alpha : 1;
|
||||
const color = this.tempColor;
|
||||
color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier,
|
||||
skeletonColor.g * slotColor.g * regionColor.g * multiplier,
|
||||
skeletonColor.b * slotColor.b * regionColor.b * multiplier,
|
||||
alpha);
|
||||
|
||||
let vertexCount = mesh.worldVerticesLength / 2;
|
||||
const vertexCount = mesh.worldVerticesLength / 2;
|
||||
let vertices = this.vertices;
|
||||
if (vertices.length < mesh.worldVerticesLength) this.vertices = vertices = Utils.newFloatArray(mesh.worldVerticesLength);
|
||||
mesh.computeWorldVertices(skeleton, slot, 0, mesh.worldVerticesLength, vertices, 0, SkeletonRenderer.VERTEX_SIZE);
|
||||
|
||||
let uvs = mesh.uvs;
|
||||
const uvs = mesh.uvs;
|
||||
for (let i = 0, u = 0, v = 2; i < vertexCount; i++) {
|
||||
vertices[v++] = color.r;
|
||||
vertices[v++] = color.g;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export * from "@esotericsoftware/spine-core"
|
||||
export * from "./AssetManager.js";
|
||||
export * from "./CanvasTexture.js";
|
||||
export * from "./SkeletonRenderer.js";
|
||||
export * from "@esotericsoftware/spine-core"
|
||||
export * from "./SkeletonRenderer.js";
|
||||
@ -245,6 +245,7 @@ export class SkeletonRenderer {
|
||||
positions,
|
||||
uvs,
|
||||
colors,
|
||||
// biome-ignore lint/suspicious/noExplicitAny: canvaskit wants indices as an array of number
|
||||
indices as any as number[],
|
||||
false
|
||||
);
|
||||
|
||||
@ -27,29 +27,29 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { SPINE_GAME_OBJECT_TYPE } from "./keys.js";
|
||||
import { SpinePlugin } from "./SpinePlugin.js";
|
||||
import {
|
||||
ComputedSizeMixin,
|
||||
DepthMixin,
|
||||
FlipMixin,
|
||||
ScrollFactorMixin,
|
||||
TransformMixin,
|
||||
VisibleMixin,
|
||||
AlphaMixin,
|
||||
OriginMixin,
|
||||
} from "./mixins.js";
|
||||
import {
|
||||
AnimationState,
|
||||
AnimationStateData,
|
||||
Bone,
|
||||
type Bone,
|
||||
MathUtils,
|
||||
Physics,
|
||||
Skeleton,
|
||||
SkeletonClipping,
|
||||
Skin,
|
||||
Vector2,
|
||||
type Vector2,
|
||||
} from "@esotericsoftware/spine-core";
|
||||
import { SPINE_GAME_OBJECT_TYPE } from "./keys.js";
|
||||
import {
|
||||
AlphaMixin,
|
||||
ComputedSizeMixin,
|
||||
DepthMixin,
|
||||
FlipMixin,
|
||||
OriginMixin,
|
||||
ScrollFactorMixin,
|
||||
TransformMixin,
|
||||
VisibleMixin,
|
||||
} from "./mixins.js";
|
||||
import type { SpinePlugin } from "./SpinePlugin.js";
|
||||
|
||||
class BaseSpineGameObject extends Phaser.GameObjects.GameObject {
|
||||
constructor (scene: Phaser.Scene, type: string) {
|
||||
@ -99,7 +99,7 @@ export class SetupPoseBoundsProvider implements SpineGameObjectBoundsProvider {
|
||||
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;
|
||||
}
|
||||
@ -137,7 +137,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;
|
||||
@ -147,12 +147,11 @@ 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 {
|
||||
@ -182,7 +181,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;
|
||||
}
|
||||
@ -240,6 +239,7 @@ export class SpineGameObject extends DepthMixin(
|
||||
atlasKey: string,
|
||||
public boundsProvider: SpineGameObjectBoundsProvider = new SetupPoseBoundsProvider()
|
||||
) {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: necessary
|
||||
super(scene, (window as any).SPINE_GAME_OBJECT_TYPE ? (window as any).SPINE_GAME_OBJECT_TYPE : SPINE_GAME_OBJECT_TYPE);
|
||||
this.setPosition(x, y);
|
||||
|
||||
@ -253,7 +253,7 @@ export class SpineGameObject extends DepthMixin(
|
||||
|
||||
updateSize () {
|
||||
if (!this.skeleton) return;
|
||||
let bounds = this.boundsProvider.calculateBounds(this);
|
||||
const bounds = this.boundsProvider.calculateBounds(this);
|
||||
this.width = bounds.width;
|
||||
this.height = bounds.height;
|
||||
this.setDisplayOrigin(-bounds.x, -bounds.y);
|
||||
@ -263,15 +263,15 @@ export class SpineGameObject extends DepthMixin(
|
||||
|
||||
/** Converts a point from the skeleton coordinate system to the Phaser world coordinate system. */
|
||||
skeletonToPhaserWorldCoordinates (point: { x: number; y: number }) {
|
||||
let transform = this.getWorldTransformMatrix();
|
||||
let a = transform.a,
|
||||
const transform = this.getWorldTransformMatrix();
|
||||
const a = transform.a,
|
||||
b = transform.b,
|
||||
c = transform.c,
|
||||
d = transform.d,
|
||||
tx = transform.tx,
|
||||
ty = transform.ty;
|
||||
let x = point.x;
|
||||
let y = point.y;
|
||||
const x = point.x;
|
||||
const y = point.y;
|
||||
point.x = x * a + y * c + tx;
|
||||
point.y = x * b + y * d + ty;
|
||||
}
|
||||
@ -280,14 +280,14 @@ export class SpineGameObject extends DepthMixin(
|
||||
phaserWorldCoordinatesToSkeleton (point: { x: number; y: number }) {
|
||||
let transform = this.getWorldTransformMatrix();
|
||||
transform = transform.invert();
|
||||
let a = transform.a,
|
||||
const a = transform.a,
|
||||
b = transform.b,
|
||||
c = transform.c,
|
||||
d = transform.d,
|
||||
tx = transform.tx,
|
||||
ty = transform.ty;
|
||||
let x = point.x;
|
||||
let y = point.y;
|
||||
const x = point.x;
|
||||
const y = point.y;
|
||||
point.x = x * a + y * c + tx;
|
||||
point.y = x * b + y * d + ty;
|
||||
}
|
||||
@ -330,7 +330,7 @@ export class SpineGameObject extends DepthMixin(
|
||||
if (!this.visible) result = false;
|
||||
|
||||
if (!result && this.parentContainer && this.plugin.webGLRenderer) {
|
||||
var sceneRenderer = this.plugin.webGLRenderer;
|
||||
const sceneRenderer = this.plugin.webGLRenderer;
|
||||
|
||||
if (this.plugin.gl && this.plugin.phaserRenderer instanceof Phaser.Renderer.WebGL.WebGLRenderer && sceneRenderer.batcher.isDrawing) {
|
||||
sceneRenderer.end();
|
||||
@ -350,27 +350,27 @@ export class SpineGameObject extends DepthMixin(
|
||||
if (!this.skeleton || !this.animationState || !this.plugin.webGLRenderer)
|
||||
return;
|
||||
|
||||
let sceneRenderer = this.plugin.webGLRenderer;
|
||||
const sceneRenderer = this.plugin.webGLRenderer;
|
||||
if (renderer.newType) {
|
||||
renderer.pipelines.clear();
|
||||
sceneRenderer.begin();
|
||||
}
|
||||
|
||||
camera.addToRenderList(src);
|
||||
let transform = Phaser.GameObjects.GetCalcMatrix(
|
||||
const transform = Phaser.GameObjects.GetCalcMatrix(
|
||||
src,
|
||||
camera,
|
||||
parentMatrix
|
||||
).calc;
|
||||
let a = transform.a,
|
||||
const a = transform.a,
|
||||
b = transform.b,
|
||||
c = transform.c,
|
||||
d = transform.d,
|
||||
tx = transform.tx,
|
||||
ty = transform.ty;
|
||||
|
||||
let offsetX = src.offsetX - src.displayOriginX;
|
||||
let offsetY = src.offsetY - src.displayOriginY;
|
||||
const offsetX = src.offsetX - src.displayOriginX;
|
||||
const offsetY = src.offsetY - src.displayOriginY;
|
||||
|
||||
sceneRenderer.drawSkeleton(
|
||||
src.skeleton,
|
||||
@ -379,8 +379,8 @@ export class SpineGameObject extends DepthMixin(
|
||||
-1,
|
||||
(vertices, numVertices, stride) => {
|
||||
for (let i = 0; i < numVertices; i += stride) {
|
||||
let vx = vertices[i] + offsetX;
|
||||
let vy = vertices[i + 1] + offsetY;
|
||||
const vx = vertices[i] + offsetX;
|
||||
const vy = vertices[i + 1] + offsetY;
|
||||
vertices[i] = vx * a + vy * c + tx;
|
||||
vertices[i + 1] = vx * b + vy * d + ty;
|
||||
}
|
||||
@ -402,22 +402,23 @@ export class SpineGameObject extends DepthMixin(
|
||||
if (!this.skeleton || !this.animationState || !this.plugin.canvasRenderer)
|
||||
return;
|
||||
|
||||
let context = renderer.currentContext;
|
||||
let skeletonRenderer = this.plugin.canvasRenderer;
|
||||
const context = renderer.currentContext;
|
||||
const skeletonRenderer = this.plugin.canvasRenderer;
|
||||
// biome-ignore lint/suspicious/noExplicitAny: necessary for phaser
|
||||
(skeletonRenderer as any).ctx = context;
|
||||
|
||||
camera.addToRenderList(src);
|
||||
let transform = Phaser.GameObjects.GetCalcMatrix(
|
||||
const transform = Phaser.GameObjects.GetCalcMatrix(
|
||||
src,
|
||||
camera,
|
||||
parentMatrix
|
||||
).calc;
|
||||
let skeleton = this.skeleton;
|
||||
const skeleton = this.skeleton;
|
||||
skeleton.x = transform.tx;
|
||||
skeleton.y = transform.ty;
|
||||
skeleton.scaleX = transform.scaleX;
|
||||
skeleton.scaleY = transform.scaleY;
|
||||
let root = skeleton.getRootBone()!;
|
||||
const root = skeleton.getRootBone() as Bone;
|
||||
root.applied.rotation = -MathUtils.radiansToDegrees * transform.rotationNormalized;
|
||||
this.skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
|
||||
@ -88,7 +88,6 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
||||
|
||||
constructor (scene: Phaser.Scene, pluginManager: Phaser.Plugins.PluginManager, pluginKey: string) {
|
||||
super(scene, pluginManager, pluginKey);
|
||||
console.log(pluginKey);
|
||||
this.game = pluginManager.game;
|
||||
this.isWebGL = this.game.config.renderType === 2;
|
||||
this.gl = this.isWebGL ? (this.game.renderer as Phaser.Renderer.WebGL.WebGLRenderer).gl : null;
|
||||
|
||||
@ -27,17 +27,21 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
export * from "./require-shim.js"
|
||||
export * from "./SpinePlugin.js"
|
||||
export * from "./SpineGameObject.js"
|
||||
export * from "./mixins.js"
|
||||
export * from "@esotericsoftware/spine-core";
|
||||
export * from "@esotericsoftware/spine-webgl";
|
||||
import { SpineGameObjectConfig, SpinePlugin } from "./SpinePlugin.js";
|
||||
export * from "./mixins.js"
|
||||
export * from "./require-shim.js"
|
||||
export * from "./SpineGameObject.js"
|
||||
export * from "./SpinePlugin.js"
|
||||
|
||||
import { type SpineGameObjectConfig, SpinePlugin } from "./SpinePlugin.js";
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: need to add spine to window
|
||||
(window as any).spine = { SpinePlugin: SpinePlugin };
|
||||
// biome-ignore lint/suspicious/noExplicitAny: need to add spine to window
|
||||
(window as any)["spine.SpinePlugin"] = SpinePlugin;
|
||||
|
||||
import { SpineGameObject, SpineGameObjectBoundsProvider } from "./SpineGameObject.js";
|
||||
import type { SpineGameObject, SpineGameObjectBoundsProvider } from "./SpineGameObject.js";
|
||||
|
||||
declare global {
|
||||
namespace Phaser.Loader {
|
||||
|
||||
@ -24,7 +24,9 @@ SOFTWARE.
|
||||
|
||||
// Adapted from https://github.com/agogpixel/phaser3-ts-utils/tree/main
|
||||
|
||||
let components = (Phaser.GameObjects.Components as any);
|
||||
// biome-ignore-all lint: ignore biome for this file
|
||||
|
||||
const components = (Phaser.GameObjects.Components as any);
|
||||
export const ComputedSize = components.ComputedSize;
|
||||
export const Depth = components.Depth;
|
||||
export const Flip = components.Flip;
|
||||
|
||||
@ -27,8 +27,10 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
// biome-ignore-all lint: ignore biome for this file
|
||||
|
||||
if (typeof window !== 'undefined' && window.Phaser) {
|
||||
let prevRequire = window.require;
|
||||
const prevRequire = window.require;
|
||||
(window as any).require = (x: string) => {
|
||||
if (prevRequire) return prevRequire(x);
|
||||
else if (x === "Phaser") return window.Phaser;
|
||||
|
||||
@ -27,29 +27,29 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { SPINE_GAME_OBJECT_TYPE } from "./keys.js";
|
||||
import { SpinePlugin } from "./SpinePlugin.js";
|
||||
import {
|
||||
ComputedSizeMixin,
|
||||
DepthMixin,
|
||||
FlipMixin,
|
||||
ScrollFactorMixin,
|
||||
TransformMixin,
|
||||
VisibleMixin,
|
||||
AlphaMixin,
|
||||
OriginMixin,
|
||||
} from "./mixins.js";
|
||||
import {
|
||||
AnimationState,
|
||||
AnimationStateData,
|
||||
Bone,
|
||||
type Bone,
|
||||
MathUtils,
|
||||
Physics,
|
||||
Skeleton,
|
||||
SkeletonClipping,
|
||||
Skin,
|
||||
Vector2,
|
||||
type Vector2,
|
||||
} from "@esotericsoftware/spine-core";
|
||||
import { SPINE_GAME_OBJECT_TYPE } from "./keys.js";
|
||||
import {
|
||||
AlphaMixin,
|
||||
ComputedSizeMixin,
|
||||
DepthMixin,
|
||||
FlipMixin,
|
||||
OriginMixin,
|
||||
ScrollFactorMixin,
|
||||
TransformMixin,
|
||||
VisibleMixin,
|
||||
} from "./mixins.js";
|
||||
import type { SpinePlugin } from "./SpinePlugin.js";
|
||||
|
||||
class BaseSpineGameObject extends Phaser.GameObjects.GameObject {
|
||||
constructor (scene: Phaser.Scene, type: string) {
|
||||
@ -99,7 +99,7 @@ export class SetupPoseBoundsProvider implements SpineGameObjectBoundsProvider {
|
||||
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;
|
||||
}
|
||||
@ -137,7 +137,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;
|
||||
@ -147,12 +147,11 @@ 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 {
|
||||
@ -182,7 +181,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;
|
||||
}
|
||||
@ -240,6 +239,7 @@ export class SpineGameObject extends DepthMixin(
|
||||
atlasKey: string,
|
||||
public boundsProvider: SpineGameObjectBoundsProvider = new SetupPoseBoundsProvider()
|
||||
) {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: necessary for phaser
|
||||
super(scene, (window as any).SPINE_GAME_OBJECT_TYPE ? (window as any).SPINE_GAME_OBJECT_TYPE : SPINE_GAME_OBJECT_TYPE);
|
||||
this.setPosition(x, y);
|
||||
|
||||
@ -253,7 +253,7 @@ export class SpineGameObject extends DepthMixin(
|
||||
|
||||
updateSize () {
|
||||
if (!this.skeleton) return;
|
||||
let bounds = this.boundsProvider.calculateBounds(this);
|
||||
const bounds = this.boundsProvider.calculateBounds(this);
|
||||
this.width = bounds.width;
|
||||
this.height = bounds.height;
|
||||
this.setDisplayOrigin(-bounds.x, -bounds.y);
|
||||
@ -263,15 +263,15 @@ export class SpineGameObject extends DepthMixin(
|
||||
|
||||
/** Converts a point from the skeleton coordinate system to the Phaser world coordinate system. */
|
||||
skeletonToPhaserWorldCoordinates (point: { x: number; y: number }) {
|
||||
let transform = this.getWorldTransformMatrix();
|
||||
let a = transform.a,
|
||||
const transform = this.getWorldTransformMatrix();
|
||||
const a = transform.a,
|
||||
b = transform.b,
|
||||
c = transform.c,
|
||||
d = transform.d,
|
||||
tx = transform.tx,
|
||||
ty = transform.ty;
|
||||
let x = point.x;
|
||||
let y = point.y;
|
||||
const x = point.x;
|
||||
const y = point.y;
|
||||
point.x = x * a + y * c + tx;
|
||||
point.y = x * b + y * d + ty;
|
||||
}
|
||||
@ -280,14 +280,14 @@ export class SpineGameObject extends DepthMixin(
|
||||
phaserWorldCoordinatesToSkeleton (point: { x: number; y: number }) {
|
||||
let transform = this.getWorldTransformMatrix();
|
||||
transform = transform.invert();
|
||||
let a = transform.a,
|
||||
const a = transform.a,
|
||||
b = transform.b,
|
||||
c = transform.c,
|
||||
d = transform.d,
|
||||
tx = transform.tx,
|
||||
ty = transform.ty;
|
||||
let x = point.x;
|
||||
let y = point.y;
|
||||
const x = point.x;
|
||||
const y = point.y;
|
||||
point.x = x * a + y * c + tx;
|
||||
point.y = x * b + y * d + ty;
|
||||
}
|
||||
@ -325,12 +325,12 @@ export class SpineGameObject extends DepthMixin(
|
||||
}
|
||||
|
||||
willRender (camera: Phaser.Cameras.Scene2D.Camera) {
|
||||
var GameObjectRenderMask = 0xf;
|
||||
var result = !this.skeleton || !(GameObjectRenderMask !== this.renderFlags || (this.cameraFilter !== 0 && this.cameraFilter & camera.id));
|
||||
const GameObjectRenderMask = 0xf;
|
||||
let result = !this.skeleton || !(GameObjectRenderMask !== this.renderFlags || (this.cameraFilter !== 0 && this.cameraFilter & camera.id));
|
||||
if (!this.visible) result = false;
|
||||
|
||||
if (!result && this.parentContainer && this.plugin.webGLRenderer) {
|
||||
var sceneRenderer = this.plugin.webGLRenderer;
|
||||
const sceneRenderer = this.plugin.webGLRenderer;
|
||||
|
||||
if (this.plugin.gl && this.plugin.phaserRenderer instanceof Phaser.Renderer.WebGL.WebGLRenderer && sceneRenderer.batcher.isDrawing) {
|
||||
sceneRenderer.end();
|
||||
@ -354,7 +354,7 @@ export class SpineGameObject extends DepthMixin(
|
||||
if (!camera || !src.skeleton || !src.animationState || !src.plugin.webGLRenderer)
|
||||
return;
|
||||
|
||||
let sceneRenderer = src.plugin.webGLRenderer;
|
||||
const sceneRenderer = src.plugin.webGLRenderer;
|
||||
|
||||
// Determine object type in context.
|
||||
const previousGameObject = displayList[displayListIndex - 1];
|
||||
@ -376,20 +376,20 @@ export class SpineGameObject extends DepthMixin(
|
||||
}
|
||||
|
||||
camera.addToRenderList(src);
|
||||
let transform = Phaser.GameObjects.GetCalcMatrix(
|
||||
const transform = Phaser.GameObjects.GetCalcMatrix(
|
||||
src,
|
||||
camera,
|
||||
parentMatrix
|
||||
).calc;
|
||||
let a = transform.a,
|
||||
const a = transform.a,
|
||||
b = transform.b,
|
||||
c = transform.c,
|
||||
d = transform.d,
|
||||
tx = transform.tx,
|
||||
ty = transform.ty;
|
||||
|
||||
let offsetX = src.offsetX - src.displayOriginX;
|
||||
let offsetY = src.offsetY - src.displayOriginY;
|
||||
const offsetX = src.offsetX - src.displayOriginX;
|
||||
const offsetY = src.offsetY - src.displayOriginY;
|
||||
|
||||
sceneRenderer.drawSkeleton(
|
||||
src.skeleton,
|
||||
@ -398,8 +398,8 @@ export class SpineGameObject extends DepthMixin(
|
||||
-1,
|
||||
(vertices, numVertices, stride) => {
|
||||
for (let i = 0; i < numVertices; i += stride) {
|
||||
let vx = vertices[i] + offsetX;
|
||||
let vy = vertices[i + 1] + offsetY;
|
||||
const vx = vertices[i] + offsetX;
|
||||
const vy = vertices[i + 1] + offsetY;
|
||||
vertices[i] = vx * a + vy * c + tx;
|
||||
vertices[i + 1] = vx * b + vy * d + ty;
|
||||
}
|
||||
@ -424,22 +424,23 @@ export class SpineGameObject extends DepthMixin(
|
||||
if (!this.skeleton || !this.animationState || !this.plugin.canvasRenderer)
|
||||
return;
|
||||
|
||||
let context = renderer.currentContext;
|
||||
let skeletonRenderer = this.plugin.canvasRenderer;
|
||||
const context = renderer.currentContext;
|
||||
const skeletonRenderer = this.plugin.canvasRenderer;
|
||||
// biome-ignore lint/suspicious/noExplicitAny: necessary for phaser
|
||||
(skeletonRenderer as any).ctx = context;
|
||||
|
||||
camera.addToRenderList(src);
|
||||
let transform = Phaser.GameObjects.GetCalcMatrix(
|
||||
const transform = Phaser.GameObjects.GetCalcMatrix(
|
||||
src,
|
||||
camera,
|
||||
parentMatrix
|
||||
).calc;
|
||||
let skeleton = this.skeleton;
|
||||
const skeleton = this.skeleton;
|
||||
skeleton.x = transform.tx;
|
||||
skeleton.y = transform.ty;
|
||||
skeleton.scaleX = transform.scaleX;
|
||||
skeleton.scaleY = transform.scaleY;
|
||||
let root = skeleton.getRootBone()!;
|
||||
const root = skeleton.getRootBone() as Bone;
|
||||
root.applied.rotation = -MathUtils.radiansToDegrees * transform.rotationNormalized;
|
||||
this.skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
|
||||
@ -1,14 +1,47 @@
|
||||
export * from "./require-shim.js"
|
||||
export * from "./SpinePlugin.js"
|
||||
export * from "./SpineGameObject.js"
|
||||
export * from "./mixins.js"
|
||||
/******************************************************************************
|
||||
* Spine Runtimes License Agreement
|
||||
* Last updated July 28, 2023. Replaces all prior versions.
|
||||
*
|
||||
* Copyright (c) 2013-2023, Esoteric Software LLC
|
||||
*
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software or
|
||||
* otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
* "Products"), provided that each user of the Products must obtain their own
|
||||
* Spine Editor license and redistribution of the Products in any form must
|
||||
* include this license and copyright notice.
|
||||
*
|
||||
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
export * from "@esotericsoftware/spine-core";
|
||||
export * from "@esotericsoftware/spine-webgl";
|
||||
import { SpineGameObjectConfig, SpinePlugin } from "./SpinePlugin.js";
|
||||
export * from "./mixins.js"
|
||||
export * from "./require-shim.js"
|
||||
export * from "./SpineGameObject.js"
|
||||
export * from "./SpinePlugin.js"
|
||||
|
||||
import { type SpineGameObjectConfig, SpinePlugin } from "./SpinePlugin.js";
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: need to add spine to window
|
||||
(window as any).spine = { SpinePlugin: SpinePlugin };
|
||||
// biome-ignore lint/suspicious/noExplicitAny: need to add spine to window
|
||||
(window as any)["spine.SpinePlugin"] = SpinePlugin;
|
||||
|
||||
import { SpineGameObject, SpineGameObjectBoundsProvider } from "./SpineGameObject.js";
|
||||
import type { SpineGameObject, SpineGameObjectBoundsProvider } from "./SpineGameObject.js";
|
||||
|
||||
declare global {
|
||||
namespace Phaser.Loader {
|
||||
|
||||
@ -24,7 +24,9 @@ SOFTWARE.
|
||||
|
||||
// Adapted from https://github.com/agogpixel/phaser3-ts-utils/tree/main
|
||||
|
||||
let components = (Phaser.GameObjects.Components as any);
|
||||
// biome-ignore-all lint: ignore biome for this file
|
||||
|
||||
const components = (Phaser.GameObjects.Components as any);
|
||||
export const ComputedSize = components.ComputedSize;
|
||||
export const Depth = components.Depth;
|
||||
export const Flip = components.Flip;
|
||||
|
||||
@ -27,8 +27,10 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
// biome-ignore-all lint: ignore biome for this file
|
||||
|
||||
if (typeof window !== 'undefined' && window.Phaser) {
|
||||
let prevRequire = window.require;
|
||||
const prevRequire = window.require;
|
||||
(window as any).require = (x: string) => {
|
||||
if (prevRequire) return prevRequire(x);
|
||||
else if (x === "Phaser") return window.Phaser;
|
||||
|
||||
@ -27,10 +27,10 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { SpineTexture } from "./SpineTexture.js";
|
||||
import type { BlendMode, NumberArrayLike } from "@esotericsoftware/spine-core";
|
||||
import { DarkTintMesh } from "./darkTintMesh/DarkTintMesh.js";
|
||||
import type { ISlotMesh } from "./Spine.js";
|
||||
import { SpineTexture } from "./SpineTexture.js";
|
||||
|
||||
export class DarkSlotMesh extends DarkTintMesh implements ISlotMesh {
|
||||
public name: string = "";
|
||||
@ -66,8 +66,8 @@ export class DarkSlotMesh extends DarkTintMesh implements ISlotMesh {
|
||||
|
||||
let vertIndex = 0;
|
||||
|
||||
let textureCoordData = textureCoord.data;
|
||||
let vertexCoordData = vertexCoord.data;
|
||||
const textureCoordData = textureCoord.data;
|
||||
const vertexCoordData = vertexCoord.data;
|
||||
for (let i = 0; i < finalVerticesLength; i += darkTint ? 12 : 8) {
|
||||
let auxi = i;
|
||||
|
||||
|
||||
@ -27,11 +27,11 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { SpineTexture } from "./SpineTexture.js";
|
||||
import type { BlendMode, NumberArrayLike } from "@esotericsoftware/spine-core";
|
||||
import type { ISlotMesh } from "./Spine.js";
|
||||
import { Mesh, MeshGeometry, MeshMaterial } from "@pixi/mesh";
|
||||
import { Texture } from "@pixi/core";
|
||||
import { Mesh, MeshGeometry, MeshMaterial } from "@pixi/mesh";
|
||||
import type { ISlotMesh } from "./Spine.js";
|
||||
import { SpineTexture } from "./SpineTexture.js";
|
||||
|
||||
export class SlotMesh extends Mesh implements ISlotMesh {
|
||||
public name: string = "";
|
||||
@ -74,8 +74,8 @@ export class SlotMesh extends Mesh implements ISlotMesh {
|
||||
|
||||
let vertIndex = 0;
|
||||
|
||||
let textureCoordData = textureCoord.data;
|
||||
let vertexCoordData = vertexCoord.data;
|
||||
const textureCoordData = textureCoord.data;
|
||||
const vertexCoordData = vertexCoord.data;
|
||||
for (let i = 0; i < finalVerticesLength; i += darkTint ? 12 : 8) {
|
||||
let auxi = i;
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@ import {
|
||||
Skeleton,
|
||||
SkeletonBinary,
|
||||
SkeletonClipping,
|
||||
type SkeletonData,
|
||||
SkeletonData,
|
||||
SkeletonJson,
|
||||
Skin,
|
||||
Utils,
|
||||
@ -329,10 +329,12 @@ export class Spine extends Container {
|
||||
private _boundsSpineID = -1;
|
||||
private _boundsSpineDirty = true;
|
||||
|
||||
constructor (options: SpineOptions | SpineFromOptions) {
|
||||
constructor (options: SkeletonData | SpineOptions | SpineFromOptions) {
|
||||
super();
|
||||
|
||||
if ("skeleton" in options)
|
||||
if (options instanceof SkeletonData)
|
||||
options = { skeletonData: options };
|
||||
else if ("skeleton" in options)
|
||||
options = new.target.createOptions(options);
|
||||
|
||||
const { autoUpdate = true, boundsProvider, darkTint, skeletonData } = options;
|
||||
|
||||
@ -27,12 +27,12 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import type { AnimationStateListener } from "@esotericsoftware/spine-core";
|
||||
import { ClippingAttachment, MeshAttachment, PathAttachment, RegionAttachment, SkeletonBounds } from "@esotericsoftware/spine-core";
|
||||
import { Container } from "@pixi/display";
|
||||
import { Graphics } from "@pixi/graphics";
|
||||
import { Text } from "@pixi/text";
|
||||
import type { Spine } from "./Spine.js";
|
||||
import type { AnimationStateListener } from "@esotericsoftware/spine-core";
|
||||
import { ClippingAttachment, MeshAttachment, PathAttachment, RegionAttachment, SkeletonBounds } from "@esotericsoftware/spine-core";
|
||||
|
||||
/**
|
||||
* Make a class that extends from this interface to create your own debug renderer.
|
||||
@ -159,9 +159,10 @@ export class SpineDebugRenderer implements ISpineDebugRenderer {
|
||||
debugDisplayObjects.parentDebugContainer.zIndex = 9999999;
|
||||
|
||||
// Disable screen reader and mouse input on debug objects.
|
||||
// biome-ignore lint/suspicious/noExplicitAny: this prop is available in later versions
|
||||
(debugDisplayObjects.parentDebugContainer as any).accessibleChildren = false;
|
||||
(debugDisplayObjects.parentDebugContainer as any).eventMode = "none";
|
||||
(debugDisplayObjects.parentDebugContainer as any).interactiveChildren = false;
|
||||
(debugDisplayObjects.parentDebugContainer).eventMode = "none";
|
||||
(debugDisplayObjects.parentDebugContainer).interactiveChildren = false;
|
||||
|
||||
spine.addChild(debugDisplayObjects.parentDebugContainer);
|
||||
|
||||
|
||||
@ -28,15 +28,15 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import { BlendMode, Texture, TextureFilter, TextureWrap } from "@esotericsoftware/spine-core";
|
||||
import type { BaseTexture as PixiBaseTexture, BaseImageResource } from "@pixi/core";
|
||||
import { Texture as PixiTexture, SCALE_MODES, MIPMAP_MODES, WRAP_MODES, BLEND_MODES } from "@pixi/core";
|
||||
import type { BaseImageResource, BaseTexture as PixiBaseTexture } from "@pixi/core";
|
||||
import { BLEND_MODES, MIPMAP_MODES, Texture as PixiTexture, SCALE_MODES, WRAP_MODES } from "@pixi/core";
|
||||
|
||||
export class SpineTexture extends Texture {
|
||||
private static textureMap: Map<PixiBaseTexture, SpineTexture> = new Map<PixiBaseTexture, SpineTexture>();
|
||||
|
||||
public static from (texture: PixiBaseTexture): SpineTexture {
|
||||
if (SpineTexture.textureMap.has(texture)) {
|
||||
return SpineTexture.textureMap.get(texture)!;
|
||||
return SpineTexture.textureMap.get(texture) as SpineTexture;
|
||||
}
|
||||
return new SpineTexture(texture);
|
||||
}
|
||||
@ -45,7 +45,7 @@ export class SpineTexture extends Texture {
|
||||
|
||||
private constructor (image: PixiBaseTexture) {
|
||||
// Todo: maybe add error handling if you feed a video texture to spine?
|
||||
super((image.resource as BaseImageResource).source as any);
|
||||
super((image.resource as BaseImageResource).source);
|
||||
this.texture = PixiTexture.from(image);
|
||||
}
|
||||
|
||||
|
||||
@ -28,12 +28,11 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import { TextureAtlas } from "@esotericsoftware/spine-core";
|
||||
import { SpineTexture } from "../SpineTexture.js";
|
||||
import type { AssetExtension, Loader, ResolvedAsset, UnresolvedAsset } from "@pixi/assets";
|
||||
import { Assets, copySearchParams } from "@pixi/assets";
|
||||
import { LoaderParserPriority, checkExtension } from "@pixi/assets";
|
||||
import { Assets, checkExtension, copySearchParams, LoaderParserPriority } from "@pixi/assets";
|
||||
import type { Texture } from "@pixi/core";
|
||||
import { ALPHA_MODES, ExtensionType, settings, utils, BaseTexture, extensions } from "@pixi/core";
|
||||
import { ALPHA_MODES, BaseTexture, ExtensionType, extensions, settings, utils } from "@pixi/core";
|
||||
import { SpineTexture } from "../SpineTexture.js";
|
||||
|
||||
type RawAtlas = string;
|
||||
|
||||
@ -75,7 +74,7 @@ const spineTextureAtlasLoader: AssetExtension<RawAtlas | TextureAtlas, ISpineAtl
|
||||
},
|
||||
|
||||
testParse (asset: unknown, options: ResolvedAsset): Promise<boolean> {
|
||||
const isExtensionRight = checkExtension(options.src!, ".atlas");
|
||||
const isExtensionRight = checkExtension(options.src as string, ".atlas");
|
||||
const isString = typeof asset === "string";
|
||||
const isExplicitLoadParserSet = options.loadParser === loaderName;
|
||||
|
||||
@ -111,7 +110,7 @@ const spineTextureAtlasLoader: AssetExtension<RawAtlas | TextureAtlas, ISpineAtl
|
||||
// setting preferCreateImageBitmap to false for loadTextures loader to allow loading PMA images
|
||||
let oldPreferCreateImageBitmap = true;
|
||||
for (const parser of loader.parsers) {
|
||||
if (parser.name == "loadTextures") {
|
||||
if (parser.name === "loadTextures") {
|
||||
oldPreferCreateImageBitmap = parser.config?.preferCreateImageBitmap;
|
||||
break;
|
||||
}
|
||||
@ -149,6 +148,7 @@ extensions.add(spineTextureAtlasLoader);
|
||||
|
||||
export interface ISpineAtlasMetadata {
|
||||
// If you are downloading an .atlas file, this metadata will go to the Texture loader
|
||||
// biome-ignore lint/suspicious/noExplicitAny: user can pass any
|
||||
imageMetadata?: any;
|
||||
// If you already have atlas pages loaded as pixi textures and want to use that to create the atlas, you can pass them here
|
||||
images?: BaseTexture | string | Record<string, BaseTexture | string>;
|
||||
|
||||
@ -28,18 +28,21 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import type { AssetExtension, ResolvedAsset } from "@pixi/assets";
|
||||
import { LoaderParserPriority, checkExtension } from "@pixi/assets";
|
||||
import { ExtensionType, settings, extensions } from "@pixi/core";
|
||||
import { checkExtension, LoaderParserPriority } from "@pixi/assets";
|
||||
import { ExtensionType, extensions, settings } from "@pixi/core";
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: any until we have a schema
|
||||
type SkeletonJsonAsset = any;
|
||||
type SkeletonBinaryAsset = Uint8Array;
|
||||
|
||||
const loaderName = "spineSkeletonLoader";
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: can receive any
|
||||
function isJson (resource: any): resource is SkeletonJsonAsset {
|
||||
return resource.hasOwnProperty("bones");
|
||||
}
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: can receive any
|
||||
function isBuffer (resource: any): resource is SkeletonBinaryAsset {
|
||||
return resource instanceof Uint8Array;
|
||||
}
|
||||
@ -67,8 +70,8 @@ const spineLoaderExtension: AssetExtension<SkeletonJsonAsset | SkeletonBinaryAss
|
||||
return buffer;
|
||||
},
|
||||
testParse (asset: unknown, options: ResolvedAsset): Promise<boolean> {
|
||||
const isJsonSpineModel = checkExtension(options.src!, ".json") && isJson(asset);
|
||||
const isBinarySpineModel = checkExtension(options.src!, ".skel") && isBuffer(asset);
|
||||
const isJsonSpineModel = checkExtension(options.src as string, ".json") && isJson(asset);
|
||||
const isBinarySpineModel = checkExtension(options.src as string, ".skel") && isBuffer(asset);
|
||||
const isExplicitLoadParserSet = options.loadParser === loaderName;
|
||||
|
||||
return Promise.resolve(isJsonSpineModel || isBinarySpineModel || isExplicitLoadParserSet);
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Geometry, Buffer, TYPES } from "@pixi/core";
|
||||
import { Buffer, Geometry, TYPES } from "@pixi/core";
|
||||
|
||||
/**
|
||||
* Geometry used to batch standard PIXI content (e.g. Mesh, Sprite, Graphics objects).
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Geometry, Buffer, TYPES } from "@pixi/core";
|
||||
import { Buffer, Geometry, TYPES } from "@pixi/core";
|
||||
|
||||
/**
|
||||
* Geometry used to batch standard PIXI content (e.g. Mesh, Sprite, Graphics objects).
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import type { ColorSource } from "@pixi/core";
|
||||
import { Shader, TextureMatrix, Color, Texture, Matrix, Program } from "@pixi/core";
|
||||
import { Color, Matrix, Program, Shader, Texture, TextureMatrix } from "@pixi/core";
|
||||
|
||||
const vertex = `
|
||||
attribute vec2 aVertexPosition;
|
||||
@ -163,7 +163,7 @@ export class DarkTintMaterial extends Shader {
|
||||
this._colorDirty = true;
|
||||
}
|
||||
public get tint (): ColorSource {
|
||||
return this._tintColor.value!;
|
||||
return this._tintColor.value as ColorSource;
|
||||
}
|
||||
|
||||
public set darkTint (value: ColorSource) {
|
||||
@ -176,7 +176,7 @@ export class DarkTintMaterial extends Shader {
|
||||
this._colorDirty = true;
|
||||
}
|
||||
public get darkTint (): ColorSource {
|
||||
return this._darkTintColor.value!;
|
||||
return this._darkTintColor.value as ColorSource;
|
||||
}
|
||||
|
||||
public get tintValue (): number {
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import type { Texture, ColorSource, Renderer, BLEND_MODES } from "@pixi/core";
|
||||
import type { BLEND_MODES, ColorSource, Renderer, Texture } from "@pixi/core";
|
||||
import { Mesh } from "@pixi/mesh";
|
||||
import { DarkTintGeometry } from "./DarkTintGeom.js";
|
||||
import { DarkTintMaterial } from "./DarkTintMaterial.js";
|
||||
@ -60,11 +60,11 @@ export class DarkTintMesh extends Mesh<DarkTintMaterial> {
|
||||
}
|
||||
|
||||
public set darkTint (value: ColorSource | null) {
|
||||
(this.shader as unknown as DarkTintMaterial).darkTint = value!;
|
||||
this.shader.darkTint = value as ColorSource;
|
||||
}
|
||||
|
||||
public get darkTintValue (): number {
|
||||
return (this.shader as unknown as DarkTintMaterial).darkTintValue;
|
||||
return this.shader.darkTintValue;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
|
||||
@ -27,10 +27,10 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import type { IDarkTintElement } from "./DarkTintMesh.js";
|
||||
import { DarkTintBatchGeometry } from "./DarkTintBatchGeom.js";
|
||||
import type { ExtensionMetadata, Renderer, ViewableBuffer } from "@pixi/core";
|
||||
import { extensions, BatchRenderer, ExtensionType, BatchShaderGenerator, Color } from "@pixi/core";
|
||||
import { BatchRenderer, BatchShaderGenerator, Color, ExtensionType, extensions } from "@pixi/core";
|
||||
import { DarkTintBatchGeometry } from "./DarkTintBatchGeom.js";
|
||||
import type { IDarkTintElement } from "./DarkTintMesh.js";
|
||||
|
||||
const vertex = `
|
||||
precision highp float;
|
||||
|
||||
@ -1,18 +1,48 @@
|
||||
export * from './require-shim.js';
|
||||
export * from './Spine.js';
|
||||
export * from './SpineDebugRenderer.js';
|
||||
export * from './SpineTexture.js';
|
||||
export * from './SlotMesh.js';
|
||||
export * from './DarkSlotMesh.js';
|
||||
/******************************************************************************
|
||||
* Spine Runtimes License Agreement
|
||||
* Last updated September 24, 2021. Replaces all prior versions.
|
||||
*
|
||||
* Copyright (c) 2013-2021, Esoteric Software LLC
|
||||
*
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
* "Products"), provided that each user of the Products must obtain their own
|
||||
* Spine Editor license and redistribution of the Products in any form must
|
||||
* include this license and copyright notice.
|
||||
*
|
||||
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import './require-shim.js';
|
||||
import './assets/AtlasLoader.js'; // Side effects install the loaders into pixi
|
||||
import './assets/SkeletonLoader.js'; // Side effects install the loaders into pixi
|
||||
|
||||
export * from "@esotericsoftware/spine-core";
|
||||
export * from './assets/AtlasLoader.js';
|
||||
export * from './assets/SkeletonLoader.js';
|
||||
export * from './DarkSlotMesh.js';
|
||||
export * from './darkTintMesh/DarkTintBatchGeom.js';
|
||||
export * from './darkTintMesh/DarkTintGeom.js';
|
||||
export * from './darkTintMesh/DarkTintMaterial.js';
|
||||
export * from './darkTintMesh/DarkTintMesh.js';
|
||||
export * from './darkTintMesh/DarkTintRenderer.js';
|
||||
export * from "@esotericsoftware/spine-core";
|
||||
export * from './SlotMesh.js';
|
||||
export * from './Spine.js';
|
||||
export * from './SpineDebugRenderer.js';
|
||||
export * from './SpineTexture.js';
|
||||
|
||||
|
||||
import './assets/AtlasLoader.js'; // Side effects install the loaders into pixi
|
||||
import './assets/SkeletonLoader.js'; // Side effects install the loaders into pixi
|
||||
|
||||
@ -27,8 +27,10 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
// biome-ignore-all lint: ignore biome for this file
|
||||
|
||||
if (typeof window !== 'undefined' && (window as any).PIXI) {
|
||||
let prevRequire = window.require;
|
||||
const prevRequire = window.require;
|
||||
(window as any).require = (x: string) => {
|
||||
if (prevRequire) return prevRequire(x);
|
||||
else if (x.startsWith("@pixi/")) return (window as any).PIXI;
|
||||
|
||||
@ -27,9 +27,9 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { AttachmentCacheData, Spine } from './Spine.js';
|
||||
|
||||
import type { Batch, Batcher, BLEND_MODES, DefaultBatchableMeshElement, Matrix, Texture, Topology } from 'pixi.js';
|
||||
import type { AttachmentCacheData, ClippedData, Spine } from './Spine.js';
|
||||
|
||||
export class BatchableSpineSlot implements DefaultBatchableMeshElement {
|
||||
indexOffset = 0;
|
||||
@ -112,13 +112,13 @@ export class BatchableSpineSlot implements DefaultBatchableMeshElement {
|
||||
this.data = data;
|
||||
|
||||
if (data.clipped) {
|
||||
const clippedData = data.clippedData;
|
||||
const clippedData = data.clippedData as ClippedData;
|
||||
|
||||
this.indexSize = clippedData!.indicesCount;
|
||||
this.attributeSize = clippedData!.vertexCount;
|
||||
this.positions = clippedData!.vertices;
|
||||
this.indices = clippedData!.indices;
|
||||
this.uvs = clippedData!.uvs;
|
||||
this.indexSize = clippedData.indicesCount;
|
||||
this.attributeSize = clippedData.vertexCount;
|
||||
this.positions = clippedData.vertices;
|
||||
this.indices = clippedData.indices;
|
||||
this.uvs = clippedData.uvs;
|
||||
}
|
||||
else {
|
||||
this.indexSize = data.indices.length;
|
||||
|
||||
@ -43,7 +43,7 @@ import {
|
||||
SkeletonBinary,
|
||||
SkeletonBounds,
|
||||
SkeletonClipping,
|
||||
type SkeletonData,
|
||||
SkeletonData,
|
||||
SkeletonJson,
|
||||
Skin,
|
||||
type Slot,
|
||||
@ -261,6 +261,14 @@ export interface SpineEvents {
|
||||
start: [trackEntry: TrackEntry];
|
||||
}
|
||||
|
||||
export interface ClippedData {
|
||||
vertices: Float32Array;
|
||||
uvs: Float32Array;
|
||||
indices: Uint16Array;
|
||||
vertexCount: number;
|
||||
indicesCount: number;
|
||||
}
|
||||
|
||||
export interface AttachmentCacheData {
|
||||
id: string;
|
||||
clipped: boolean;
|
||||
@ -272,13 +280,7 @@ export interface AttachmentCacheData {
|
||||
darkTint: boolean;
|
||||
skipRender: boolean;
|
||||
texture: Texture;
|
||||
clippedData?: {
|
||||
vertices: Float32Array;
|
||||
uvs: Float32Array;
|
||||
indices: Uint16Array;
|
||||
vertexCount: number;
|
||||
indicesCount: number;
|
||||
};
|
||||
clippedData?: ClippedData;
|
||||
}
|
||||
|
||||
interface SlotsToClipping {
|
||||
@ -385,10 +387,12 @@ export class Spine extends ViewContainer {
|
||||
}
|
||||
|
||||
private hasNeverUpdated = true;
|
||||
constructor (options: SpineOptions | SpineFromOptions) {
|
||||
constructor (options: SkeletonData | SpineOptions | SpineFromOptions) {
|
||||
super({});
|
||||
|
||||
if ("skeleton" in options)
|
||||
if (options instanceof SkeletonData)
|
||||
options = { skeletonData: options };
|
||||
else if ("skeleton" in options)
|
||||
options = new.target.createOptions(options);
|
||||
|
||||
this.allowChildren = true;
|
||||
@ -579,7 +583,7 @@ export class Spine extends ViewContainer {
|
||||
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;
|
||||
let mask = currentClippingSlot.mask;
|
||||
if (!mask) {
|
||||
mask = maskPool.obtain();
|
||||
currentClippingSlot.mask = mask;
|
||||
@ -1030,11 +1034,11 @@ export class Spine extends ViewContainer {
|
||||
Ticker.shared.remove(this.internalUpdate, this);
|
||||
this.state.clearListeners();
|
||||
this.debug = undefined;
|
||||
this.skeleton = null as any;
|
||||
this.state = null as any;
|
||||
(this._slotsObject as any) = null;
|
||||
(this.skeleton as unknown) = null;
|
||||
(this.state as unknown) = null;
|
||||
(this._slotsObject as unknown) = null;
|
||||
(this.attachmentCacheData as unknown) = null;
|
||||
this._lastAttachments.length = 0;
|
||||
this.attachmentCacheData = null as any;
|
||||
}
|
||||
|
||||
/** Converts a point from the skeleton coordinate system to the Pixi world coordinate system. */
|
||||
|
||||
@ -27,8 +27,8 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Container, Graphics, Text } from 'pixi.js';
|
||||
import { Spine } from './Spine.js';
|
||||
|
||||
import type { AnimationStateListener } from '@esotericsoftware/spine-core';
|
||||
import {
|
||||
ClippingAttachment,
|
||||
MeshAttachment,
|
||||
@ -36,8 +36,8 @@ import {
|
||||
RegionAttachment,
|
||||
SkeletonBounds
|
||||
} from '@esotericsoftware/spine-core';
|
||||
|
||||
import type { AnimationStateListener } from '@esotericsoftware/spine-core';
|
||||
import { Container, Graphics, Text } from 'pixi.js';
|
||||
import type { Spine } from './Spine.js';
|
||||
|
||||
/**
|
||||
* Make a class that extends from this interface to create your own debug renderer.
|
||||
@ -171,12 +171,12 @@ export class SpineDebugRenderer implements ISpineDebugRenderer {
|
||||
debugDisplayObjects.parentDebugContainer.addChild(debugDisplayObjects.pathsLine);
|
||||
debugDisplayObjects.parentDebugContainer.addChild(debugDisplayObjects.eventText);
|
||||
|
||||
(debugDisplayObjects.parentDebugContainer as any).zIndex = 9999999;
|
||||
debugDisplayObjects.parentDebugContainer.zIndex = 9999999;
|
||||
|
||||
// Disable screen reader and mouse input on debug objects.
|
||||
(debugDisplayObjects.parentDebugContainer as any).accessibleChildren = false;
|
||||
(debugDisplayObjects.parentDebugContainer as any).eventMode = 'none';
|
||||
(debugDisplayObjects.parentDebugContainer as any).interactiveChildren = false;
|
||||
debugDisplayObjects.parentDebugContainer.accessibleChildren = false;
|
||||
debugDisplayObjects.parentDebugContainer.eventMode = 'none';
|
||||
debugDisplayObjects.parentDebugContainer.interactiveChildren = false;
|
||||
|
||||
spine.addChild(debugDisplayObjects.parentDebugContainer);
|
||||
|
||||
|
||||
@ -150,6 +150,7 @@ export class SpinePipe implements RenderPipe<Spine> {
|
||||
if (!skipRender) {
|
||||
container.includeInBuild = true;
|
||||
// See https://github.com/pixijs/pixijs/blob/b4c050a791fe65e979e467c9cba2bda0c01a1c35/src/scene/container/utils/collectAllRenderables.ts#L28
|
||||
// biome-ignore lint/style/noNonNullAssertion: it was in pixi code
|
||||
container.collectRenderables(instructionSet, this.renderer, null!);
|
||||
}
|
||||
|
||||
@ -185,13 +186,13 @@ export class SpinePipe implements RenderPipe<Spine> {
|
||||
}
|
||||
|
||||
destroyRenderable (spine: Spine) {
|
||||
this.gpuSpineData[spine.uid] = null as any;
|
||||
(this.gpuSpineData[spine.uid] as unknown) = null;
|
||||
spine.off('destroyed', this._destroyRenderableBound);
|
||||
}
|
||||
|
||||
destroy () {
|
||||
this.gpuSpineData = null as any;
|
||||
this.renderer = null as any;
|
||||
(this.gpuSpineData as unknown) = null;
|
||||
(this.renderer as unknown) = null;
|
||||
}
|
||||
|
||||
private _getSpineData (spine: Spine): GpuSpineDataElement {
|
||||
|
||||
@ -27,10 +27,9 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Texture as PixiTexture } from 'pixi.js';
|
||||
import { BlendMode, Texture, TextureFilter, TextureWrap } from '@esotericsoftware/spine-core';
|
||||
|
||||
import type { BLEND_MODES, SCALE_MODE, TextureSource, WRAP_MODE } from 'pixi.js';
|
||||
import { Texture as PixiTexture } from 'pixi.js';
|
||||
|
||||
export class SpineTexture extends Texture {
|
||||
private static readonly textureMap: Map<TextureSource, SpineTexture> = new Map<TextureSource, SpineTexture>();
|
||||
|
||||
@ -120,7 +120,7 @@ const spineTextureAtlasLoader: AssetExtension<RawAtlas | TextureAtlas, ISpineAtl
|
||||
}
|
||||
|
||||
// we will wait for all promises for the textures at the same time at the end.
|
||||
const textureLoadingPromises: Promise<any>[] = [];
|
||||
const textureLoadingPromises: Promise<void>[] = [];
|
||||
|
||||
// fill the pages
|
||||
for (const page of retval.pages) {
|
||||
@ -161,6 +161,7 @@ extensions.add(spineTextureAtlasLoader);
|
||||
|
||||
export interface ISpineAtlasMetadata {
|
||||
// If you are downloading an .atlas file, this metadata will go to the Texture loader
|
||||
// biome-ignore lint/suspicious/noExplicitAny: user can pass any
|
||||
imageMetadata?: any;
|
||||
// If you already have atlas pages loaded as pixi textures
|
||||
// and want to use that to create the atlas, you can pass them here
|
||||
|
||||
@ -37,15 +37,18 @@ import {
|
||||
type ResolvedAsset
|
||||
} from 'pixi.js';
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: can receive any
|
||||
type SkeletonJsonAsset = any;
|
||||
type SkeletonBinaryAsset = Uint8Array;
|
||||
|
||||
const loaderName = "spineSkeletonLoader";
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: can receive any
|
||||
function isJson (resource: any): resource is SkeletonJsonAsset {
|
||||
return Object.prototype.hasOwnProperty.call(resource, 'bones');
|
||||
}
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: can receive any
|
||||
function isBuffer (resource: any): resource is SkeletonBinaryAsset {
|
||||
return resource instanceof Uint8Array;
|
||||
}
|
||||
@ -74,8 +77,8 @@ const spineLoaderExtension: AssetExtension<SkeletonJsonAsset | SkeletonBinaryAss
|
||||
return buffer;
|
||||
},
|
||||
testParse (asset: unknown, options: ResolvedAsset): Promise<boolean> {
|
||||
const isJsonSpineModel = checkExtension(options.src!, '.json') && isJson(asset);
|
||||
const isBinarySpineModel = checkExtension(options.src!, '.skel') && isBuffer(asset);
|
||||
const isJsonSpineModel = checkExtension(options.src as string, '.json') && isJson(asset);
|
||||
const isBinarySpineModel = checkExtension(options.src as string, '.skel') && isBuffer(asset);
|
||||
const isExplicitLoadParserSet = options.parser === loaderName || options.loadParser === loaderName;
|
||||
|
||||
return Promise.resolve(isJsonSpineModel || isBinarySpineModel || isExplicitLoadParserSet);
|
||||
|
||||
@ -30,11 +30,11 @@
|
||||
import {
|
||||
Batcher,
|
||||
Color,
|
||||
DefaultBatchableMeshElement,
|
||||
DefaultBatchableQuadElement,
|
||||
extensions,
|
||||
type DefaultBatchableMeshElement,
|
||||
type DefaultBatchableQuadElement,
|
||||
ExtensionType,
|
||||
Shader
|
||||
extensions,
|
||||
type Shader
|
||||
} from 'pixi.js';
|
||||
import { DarkTintBatchGeometry } from './DarkTintBatchGeometry.js';
|
||||
import { DarkTintShader } from './DarkTintShader.js';
|
||||
|
||||
@ -33,6 +33,7 @@ import './assets/SkeletonLoader.js'; // Side effects install the loaders into pi
|
||||
import './darktint/DarkTintBatcher.js'; // Side effects install the batcher into pixi
|
||||
import './SpinePipe.js';
|
||||
|
||||
export * from '@esotericsoftware/spine-core';
|
||||
export * from './assets/AtlasLoader.js';
|
||||
export * from './assets/SkeletonLoader.js';
|
||||
export * from './require-shim.js';
|
||||
@ -40,4 +41,3 @@ export * from './Spine.js';
|
||||
export * from './SpineDebugRenderer.js';
|
||||
export * from './SpinePipe.js';
|
||||
export * from './SpineTexture.js';
|
||||
export * from '@esotericsoftware/spine-core';
|
||||
|
||||
@ -27,6 +27,8 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
// biome-ignore-all lint: ignore biome for this file
|
||||
|
||||
if (typeof window !== 'undefined' && (window as any).PIXI) {
|
||||
const prevRequire = window.require;
|
||||
(window as any).require = (x: string) => {
|
||||
|
||||
@ -27,22 +27,16 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Animation, AnimationState, AnimationStateData, AtlasAttachmentLoader, Bone, Color, Disposable, Downloader, MathUtils, MixBlend, MixDirection, Physics, Skeleton, SkeletonBinary, SkeletonData, SkeletonJson, StringMap, TextureAtlas, TextureFilter, TimeKeeper, TrackEntry, Vector2 } from "@esotericsoftware/spine-core"
|
||||
import { AssetManager, GLTexture, Input, LoadingScreen, ManagedWebGLRenderingContext, ResizeMode, SceneRenderer, Vector3 } from "@esotericsoftware/spine-webgl"
|
||||
import { type Animation, AnimationState, AnimationStateData, AtlasAttachmentLoader, type Bone, Color, type Disposable, type Downloader, MathUtils, MixBlend, MixDirection, Physics, Skeleton, SkeletonBinary, type SkeletonData, SkeletonJson, type StringMap, type TextureAtlas, TextureFilter, TimeKeeper, type TrackEntry, Vector2 } from "@esotericsoftware/spine-core"
|
||||
import { AssetManager, type GLTexture, Input, LoadingScreen, ManagedWebGLRenderingContext, ResizeMode, SceneRenderer, Vector3 } from "@esotericsoftware/spine-webgl"
|
||||
|
||||
export interface SpinePlayerConfig {
|
||||
/* The URL of the skeleton JSON (.json) or binary (.skel) file */
|
||||
skeleton?: string;
|
||||
|
||||
/* @deprecated Use skeleton instead. The URL of the skeleton JSON file (.json). Undefined if binaryUrl is given. */
|
||||
jsonUrl?: string
|
||||
|
||||
/* Optional: The name of a field in the JSON that holds the skeleton data. Default: none */
|
||||
jsonField?: string
|
||||
|
||||
/* @deprecated Use skeleton instead. The URL of the skeleton binary file (.skel). Undefined if jsonUrl is given. */
|
||||
binaryUrl?: string
|
||||
|
||||
/* The scale when loading the skeleton data. Default: 1 */
|
||||
scale?: number
|
||||
|
||||
@ -245,12 +239,12 @@ export class SpinePlayer implements Disposable {
|
||||
private input?: Input;
|
||||
|
||||
constructor (parent: HTMLElement | string, private config: SpinePlayerConfig) {
|
||||
let parentDom = typeof parent === "string" ? document.getElementById(parent) : parent;
|
||||
if (parentDom == null) throw new Error("SpinePlayer parent not found: " + parent);
|
||||
const parentDom = typeof parent === "string" ? document.getElementById(parent) : parent;
|
||||
if (parentDom == null) throw new Error(`SpinePlayer parent not found: ${parent}`);
|
||||
this.parent = parentDom;
|
||||
|
||||
if (config.showControls === void 0) config.showControls = true;
|
||||
let controls = config.showControls ? /*html*/`
|
||||
const controls = config.showControls ? /*html*/`
|
||||
<div class="spine-player-controls spine-player-popup-parent spine-player-controls-hidden">
|
||||
<div class="spine-player-timeline"></div>
|
||||
<div class="spine-player-buttons">
|
||||
@ -287,8 +281,8 @@ export class SpinePlayer implements Disposable {
|
||||
this.loadingScreen?.dispose();
|
||||
this.assetManager?.dispose();
|
||||
this.context?.dispose();
|
||||
for (var i = 0; i < this.eventListeners.length; i++) {
|
||||
var eventListener = this.eventListeners[i];
|
||||
for (let i = 0; i < this.eventListeners.length; i++) {
|
||||
const eventListener = this.eventListeners[i];
|
||||
eventListener.target.removeEventListener(eventListener.event, eventListener.func);
|
||||
}
|
||||
this.input?.dispose();
|
||||
@ -308,12 +302,10 @@ export class SpinePlayer implements Disposable {
|
||||
private validateConfig (config: SpinePlayerConfig) {
|
||||
if (!config) throw new Error("A configuration object must be passed to to new SpinePlayer().");
|
||||
if ((config as any).skelUrl) config.skeleton = (config as any).skelUrl;
|
||||
if (!config.skeleton && !config.jsonUrl && !config.binaryUrl) throw new Error("A URL must be specified for the skeleton JSON or binary file.");
|
||||
if (!config.skeleton) throw new Error("A URL must be specified for the skeleton JSON or binary file.");
|
||||
if (!config.scale) config.scale = 1;
|
||||
if (!config.atlas && !config.atlasUrl) throw new Error("A URL must be specified for the atlas file.");
|
||||
|
||||
if (config.jsonUrl && !config.skeleton) config.skeleton = config.jsonUrl;
|
||||
if (config.binaryUrl && !config.skeleton) config.skeleton = config.binaryUrl;
|
||||
if (config.atlasUrl && !config.atlas) config.atlas = config.atlasUrl;
|
||||
|
||||
if (!config.backgroundColor) config.backgroundColor = config.alpha ? "00000000" : "000000";
|
||||
@ -334,9 +326,9 @@ export class SpinePlayer implements Disposable {
|
||||
regions: false
|
||||
};
|
||||
if (config.animations && config.animation && config.animations.indexOf(config.animation) < 0)
|
||||
throw new Error("Animation '" + config.animation + "' is not in the config animation list: " + toString(config.animations));
|
||||
throw new Error(`Animation '${config.animation}' is not in the config animation list: ${print(config.animations)}`);
|
||||
if (config.skins && config.skin && config.skins.indexOf(config.skin) < 0)
|
||||
throw new Error("Default skin '" + config.skin + "' is not in the config skins list: " + toString(config.skins));
|
||||
throw new Error(`Default skin '${config.skin}' is not in the config skins list: ${print(config.skins)}`);
|
||||
if (!config.viewport) config.viewport = {} as any;
|
||||
if (!config.viewport!.animations) config.viewport!.animations = {};
|
||||
if (config.viewport!.debugRender === void 0) config.viewport!.debugRender = false;
|
||||
@ -347,12 +339,12 @@ export class SpinePlayer implements Disposable {
|
||||
}
|
||||
|
||||
private initialize (): HTMLElement | null {
|
||||
let config = this.config;
|
||||
let dom = this.dom;
|
||||
const config = this.config;
|
||||
const dom = this.dom;
|
||||
|
||||
if (!config.alpha) { // Prevents a flash before the first frame is drawn.
|
||||
let hex = config.backgroundColor!;
|
||||
this.dom.style.backgroundColor = (hex.charAt(0) == '#' ? hex : "#" + hex).substr(0, 7);
|
||||
const hex = config.backgroundColor!;
|
||||
this.dom.style.backgroundColor = (hex.charAt(0) === '#' ? hex : `#${hex}`).substr(0, 7);
|
||||
}
|
||||
|
||||
try {
|
||||
@ -371,7 +363,7 @@ export class SpinePlayer implements Disposable {
|
||||
// Load the assets.
|
||||
this.assetManager = new AssetManager(this.context, "", config.downloader);
|
||||
if (config.rawDataURIs) {
|
||||
for (let path in config.rawDataURIs)
|
||||
for (const path in config.rawDataURIs)
|
||||
this.assetManager.setRawDataURI(path, config.rawDataURIs[path]);
|
||||
}
|
||||
if (config.skeleton!.endsWith(".json"))
|
||||
@ -386,23 +378,23 @@ export class SpinePlayer implements Disposable {
|
||||
this.bgFullscreen.setFromString(config.fullScreenBackgroundColor!);
|
||||
if (config.showControls) {
|
||||
this.playerControls = dom.children[1] as HTMLElement;
|
||||
let controls = this.playerControls.children;
|
||||
let timeline = controls[0] as HTMLElement;
|
||||
let buttons = controls[1].children;
|
||||
const controls = this.playerControls.children;
|
||||
const timeline = controls[0] as HTMLElement;
|
||||
const buttons = controls[1].children;
|
||||
this.playButton = buttons[0] as HTMLElement;
|
||||
let speedButton = buttons[2] as HTMLElement;
|
||||
const speedButton = buttons[2] as HTMLElement;
|
||||
this.animationButton = buttons[3] as HTMLElement;
|
||||
this.skinButton = buttons[4] as HTMLElement;
|
||||
let settingsButton = buttons[5] as HTMLElement;
|
||||
let fullscreenButton = buttons[6] as HTMLElement;
|
||||
let logoButton = buttons[7] as HTMLElement;
|
||||
const settingsButton = buttons[5] as HTMLElement;
|
||||
const fullscreenButton = buttons[6] as HTMLElement;
|
||||
const logoButton = buttons[7] as HTMLElement;
|
||||
|
||||
this.timelineSlider = new Slider();
|
||||
timeline.appendChild(this.timelineSlider.create());
|
||||
this.timelineSlider.change = (percentage) => {
|
||||
this.pause();
|
||||
let animationDuration = this.animationState!.getCurrent(0)!.animation!.duration;
|
||||
let time = animationDuration * percentage;
|
||||
const animationDuration = this.animationState!.getCurrent(0)!.animation!.duration;
|
||||
const time = animationDuration * percentage;
|
||||
this.animationState!.update(time - this.playTime);
|
||||
this.animationState!.apply(this.skeleton!);
|
||||
this.skeleton!.update(time - this.playTime);
|
||||
@ -420,11 +412,11 @@ export class SpinePlayer implements Disposable {
|
||||
let oldStyleWidth = this.canvas.style.width, oldStyleHeight = this.canvas.style.height;
|
||||
let isFullscreen = false;
|
||||
fullscreenButton.onclick = () => {
|
||||
let fullscreenChanged = () => {
|
||||
const fullscreenChanged = () => {
|
||||
isFullscreen = !isFullscreen;
|
||||
if (!isFullscreen) {
|
||||
this.canvas!.style.width = oldWidth + "px";
|
||||
this.canvas!.style.height = oldHeight + "px";
|
||||
this.canvas!.style.width = `${oldWidth}px`;
|
||||
this.canvas!.style.height = `${oldHeight}px`;
|
||||
this.drawFrame(false);
|
||||
// Got to reset the style to whatever the user set after the next layouting.
|
||||
requestAnimationFrame(() => {
|
||||
@ -434,11 +426,11 @@ export class SpinePlayer implements Disposable {
|
||||
}
|
||||
};
|
||||
|
||||
let player = dom as any;
|
||||
const player = dom as any;
|
||||
player.onfullscreenchange = fullscreenChanged;
|
||||
player.onwebkitfullscreenchange = fullscreenChanged;
|
||||
|
||||
let doc = document as any;
|
||||
const doc = document as any;
|
||||
if (doc.fullscreenElement || doc.webkitFullscreenElement || doc.mozFullScreenElement || doc.msFullscreenElement) {
|
||||
if (doc.exitFullscreen) doc.exitFullscreen();
|
||||
else if (doc.mozCancelFullScreen) doc.mozCancelFullScreen();
|
||||
@ -465,18 +457,18 @@ export class SpinePlayer implements Disposable {
|
||||
if (this.error) return;
|
||||
|
||||
if (this.assetManager!.hasErrors())
|
||||
this.showError("Error: Assets could not be loaded.\n" + toString(this.assetManager!.getErrors()));
|
||||
this.showError(`Error: Assets could not be loaded.\n${print(this.assetManager!.getErrors())}`);
|
||||
|
||||
let config = this.config;
|
||||
const config = this.config;
|
||||
|
||||
// Configure filtering, don't use mipmaps in WebGL1 if the atlas page is non-POT
|
||||
let atlas = this.assetManager!.require(config.atlas!) as TextureAtlas;
|
||||
let gl = this.context!.gl, anisotropic = gl.getExtension("EXT_texture_filter_anisotropic");
|
||||
let isWebGL1 = gl.getParameter(gl.VERSION).indexOf("WebGL 1.0") != -1;
|
||||
for (let page of atlas.pages) {
|
||||
const atlas = this.assetManager!.require(config.atlas!) as TextureAtlas;
|
||||
const gl = this.context!.gl, anisotropic = gl.getExtension("EXT_texture_filter_anisotropic");
|
||||
const isWebGL1 = gl.getParameter(gl.VERSION).indexOf("WebGL 1.0") !== -1;
|
||||
for (const page of atlas.pages) {
|
||||
let minFilter = page.minFilter;
|
||||
var useMipMaps: boolean = config.mipmaps!;
|
||||
var isPOT = MathUtils.isPowerOfTwo(page.width) && MathUtils.isPowerOfTwo(page.height);
|
||||
let useMipMaps: boolean = config.mipmaps!;
|
||||
const isPOT = MathUtils.isPowerOfTwo(page.width) && MathUtils.isPowerOfTwo(page.height);
|
||||
if (isWebGL1 && !isPOT) useMipMaps = false;
|
||||
|
||||
if (useMipMaps) {
|
||||
@ -487,7 +479,7 @@ export class SpinePlayer implements Disposable {
|
||||
minFilter = TextureFilter.Linear; // Don't use mipmaps without anisotropic.
|
||||
page.texture!.setFilters(minFilter, TextureFilter.Nearest);
|
||||
}
|
||||
if (minFilter != TextureFilter.Nearest && minFilter != TextureFilter.Linear) (page.texture as GLTexture).update(true);
|
||||
if (minFilter !== TextureFilter.Nearest && minFilter !== TextureFilter.Linear) (page.texture as GLTexture).update(true);
|
||||
}
|
||||
|
||||
// Load skeleton data.
|
||||
@ -499,7 +491,7 @@ export class SpinePlayer implements Disposable {
|
||||
if (!data) throw new Error("Empty JSON data.");
|
||||
if (config.jsonField) {
|
||||
data = data[config.jsonField];
|
||||
if (!data) throw new Error("JSON field does not exist: " + config.jsonField);
|
||||
if (!data) throw new Error(`JSON field does not exist: ${config.jsonField}`);
|
||||
}
|
||||
loader = new SkeletonJson(attachmentLoader);
|
||||
} else {
|
||||
@ -513,7 +505,7 @@ export class SpinePlayer implements Disposable {
|
||||
return;
|
||||
}
|
||||
this.skeleton = new Skeleton(skeletonData);
|
||||
let stateData = new AnimationStateData(skeletonData);
|
||||
const stateData = new AnimationStateData(skeletonData);
|
||||
stateData.defaultMix = config.defaultMix!;
|
||||
this.animationState = new AnimationState(stateData);
|
||||
|
||||
@ -560,8 +552,8 @@ export class SpinePlayer implements Disposable {
|
||||
|
||||
if (config.showControls) {
|
||||
// Hide skin and animation if there's only the default skin / no animation
|
||||
if (skeletonData.skins.length == 1 || (config.skins && config.skins.length == 1)) this.skinButton!.classList.add("spine-player-hidden");
|
||||
if (skeletonData.animations.length == 1 || (config.animations && config.animations.length == 1)) this.animationButton!.classList.add("spine-player-hidden");
|
||||
if (skeletonData.skins.length === 1 || (config.skins && config.skins.length === 1)) this.skinButton!.classList.add("spine-player-hidden");
|
||||
if (skeletonData.animations.length === 1 || (config.animations && config.animations.length === 1)) this.animationButton!.classList.add("spine-player-hidden");
|
||||
}
|
||||
|
||||
if (config.success) config.success(this);
|
||||
@ -590,30 +582,30 @@ export class SpinePlayer implements Disposable {
|
||||
}
|
||||
|
||||
private setupInput () {
|
||||
let config = this.config;
|
||||
let controlBones = config.controlBones!;
|
||||
const config = this.config;
|
||||
const controlBones = config.controlBones!;
|
||||
if (!controlBones.length && !config.showControls) return;
|
||||
let selectedBones = this.selectedBones = new Array<Bone | null>(controlBones.length);
|
||||
let canvas = this.canvas!;
|
||||
const selectedBones = this.selectedBones = new Array<Bone | null>(controlBones.length);
|
||||
const canvas = this.canvas!;
|
||||
let target: Bone | null = null;
|
||||
let offset = new Vector2();
|
||||
let coords = new Vector3();
|
||||
let mouse = new Vector3();
|
||||
let position = new Vector2();
|
||||
let skeleton = this.skeleton!;
|
||||
let renderer = this.sceneRenderer!;
|
||||
const offset = new Vector2();
|
||||
const coords = new Vector3();
|
||||
const mouse = new Vector3();
|
||||
const position = new Vector2();
|
||||
const skeleton = this.skeleton!;
|
||||
const renderer = this.sceneRenderer!;
|
||||
|
||||
if (config.interactive) {
|
||||
let closest = function (x: number, y: number): Bone | null {
|
||||
const closest = (x: number, y: number): Bone | null => {
|
||||
mouse.set(x, canvas.clientHeight - y, 0)
|
||||
offset.x = offset.y = 0;
|
||||
let bestDistance = 24, index = 0;
|
||||
let best: Bone | null = null;
|
||||
for (let i = 0; i < controlBones.length; i++) {
|
||||
selectedBones[i] = null;
|
||||
let bone = skeleton.findBone(controlBones[i]);
|
||||
const bone = skeleton.findBone(controlBones[i]);
|
||||
if (!bone) continue;
|
||||
let distance = renderer.camera.worldToScreen(
|
||||
const distance = renderer.camera.worldToScreen(
|
||||
coords.set(bone.applied.worldX, bone.applied.worldY, 0),
|
||||
canvas.clientWidth, canvas.clientHeight).distance(mouse);
|
||||
if (distance < bestDistance) {
|
||||
@ -668,27 +660,27 @@ export class SpinePlayer implements Disposable {
|
||||
});
|
||||
this.addEventListener(document, "touchmove", (ev: UIEvent) => {
|
||||
if (ev instanceof TouchEvent) {
|
||||
let touches = ev.changedTouches;
|
||||
const touches = ev.changedTouches;
|
||||
if (touches.length) {
|
||||
let touch = touches[0];
|
||||
const touch = touches[0];
|
||||
handleHover(touch.clientX, touch.clientY);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
let overlap = (mouseX: number, mouseY: number, rect: DOMRect | ClientRect): boolean => {
|
||||
let x = mouseX - rect.left, y = mouseY - rect.top;
|
||||
const overlap = (mouseX: number, mouseY: number, rect: DOMRect | ClientRect): boolean => {
|
||||
const x = mouseX - rect.left, y = mouseY - rect.top;
|
||||
return x >= 0 && x <= rect.width && y >= 0 && y <= rect.height;
|
||||
}
|
||||
|
||||
let mouseOverControls = true, mouseOverCanvas = false;
|
||||
let handleHover = (mouseX: number, mouseY: number) => {
|
||||
let popup = findWithClass(this.dom, "spine-player-popup");
|
||||
const handleHover = (mouseX: number, mouseY: number) => {
|
||||
const popup = findWithClass(this.dom, "spine-player-popup");
|
||||
mouseOverControls = overlap(mouseX, mouseY, this.playerControls!.getBoundingClientRect());
|
||||
mouseOverCanvas = overlap(mouseX, mouseY, canvas.getBoundingClientRect());
|
||||
clearTimeout(this.cancelId);
|
||||
let hide = !popup && !mouseOverControls && !mouseOverCanvas && !this.paused;
|
||||
const hide = !popup && !mouseOverControls && !mouseOverCanvas && !this.paused;
|
||||
if (hide)
|
||||
this.playerControls!.classList.add("spine-player-controls-hidden");
|
||||
else
|
||||
@ -704,7 +696,7 @@ export class SpinePlayer implements Disposable {
|
||||
|
||||
play () {
|
||||
this.paused = false;
|
||||
let config = this.config;
|
||||
const config = this.config;
|
||||
if (config.showControls) {
|
||||
this.cancelId = setTimeout(() => {
|
||||
if (!this.paused) this.playerControls!.classList.add("spine-player-controls-hidden");
|
||||
@ -747,17 +739,17 @@ export class SpinePlayer implements Disposable {
|
||||
|
||||
/* Sets the viewport for the specified animation. */
|
||||
setViewport (animation: string | Animation): Animation {
|
||||
if (typeof animation == "string") {
|
||||
let foundAnimation = this.skeleton!.data.findAnimation(animation);
|
||||
if (!foundAnimation) throw new Error("Animation not found: " + animation);
|
||||
if (typeof animation === "string") {
|
||||
const foundAnimation = this.skeleton!.data.findAnimation(animation);
|
||||
if (!foundAnimation) throw new Error(`Animation not found: ${animation}`);
|
||||
animation = foundAnimation;
|
||||
}
|
||||
|
||||
this.previousViewport = this.currentViewport;
|
||||
|
||||
// Determine the base viewport.
|
||||
let globalViewport = this.config.viewport!;
|
||||
let viewport = this.currentViewport = {
|
||||
const globalViewport = this.config.viewport!;
|
||||
const viewport = this.currentViewport = {
|
||||
clip: globalViewport.clip,
|
||||
padLeft: globalViewport.padLeft !== void 0 ? globalViewport.padLeft : "10%",
|
||||
padRight: globalViewport.padRight !== void 0 ? globalViewport.padRight : "10%",
|
||||
@ -773,7 +765,7 @@ export class SpinePlayer implements Disposable {
|
||||
this.calculateAnimationViewport(animation, viewport);
|
||||
|
||||
// Override with the animation specific viewport for the final result.
|
||||
let userAnimViewport = this.config.viewport!.animations![animation.name];
|
||||
const userAnimViewport = this.config.viewport!.animations![animation.name];
|
||||
if (userAnimViewport) {
|
||||
if (userAnimViewport.x !== void 0 && userAnimViewport.y !== void 0 && userAnimViewport.width && userAnimViewport.height) {
|
||||
viewport.x = userAnimViewport.x;
|
||||
@ -809,7 +801,7 @@ export class SpinePlayer implements Disposable {
|
||||
|
||||
let steps = 100, stepTime = animation.duration ? animation.duration / steps : 0, time = 0;
|
||||
let minX = 100000000, maxX = -100000000, minY = 100000000, maxY = -100000000;
|
||||
let offset = new Vector2(), size = new Vector2();
|
||||
const offset = new Vector2(), size = new Vector2();
|
||||
|
||||
const tempArray = new Array<number>(2);
|
||||
for (let i = 0; i < steps; i++, time += stepTime) {
|
||||
@ -817,13 +809,13 @@ export class SpinePlayer implements Disposable {
|
||||
this.skeleton!.updateWorldTransform(Physics.update);
|
||||
this.skeleton!.getBounds(offset, size, tempArray, this.sceneRenderer!.skeletonRenderer.getSkeletonClipping());
|
||||
|
||||
if (!isNaN(offset.x) && !isNaN(offset.y) && !isNaN(size.x) && !isNaN(size.y)) {
|
||||
if (!Number.isNaN(offset.x) && !Number.isNaN(offset.y) && !Number.isNaN(size.x) && !Number.isNaN(size.y)) {
|
||||
minX = Math.min(offset.x, minX);
|
||||
maxX = Math.max(offset.x + size.x, maxX);
|
||||
minY = Math.min(offset.y, minY);
|
||||
maxY = Math.max(offset.y + size.y, maxY);
|
||||
} else
|
||||
this.showError("Animation bounds are invalid: " + animation.name);
|
||||
this.showError(`Animation bounds are invalid: ${animation.name}`);
|
||||
}
|
||||
|
||||
viewport.x = minX;
|
||||
@ -838,20 +830,20 @@ export class SpinePlayer implements Disposable {
|
||||
if (this.disposed) return;
|
||||
if (requestNextFrame && !this.stopRequestAnimationFrame) requestAnimationFrame(() => this.drawFrame());
|
||||
|
||||
let doc = document as any;
|
||||
let isFullscreen = doc.fullscreenElement || doc.webkitFullscreenElement || doc.mozFullScreenElement || doc.msFullscreenElement;
|
||||
let bg = isFullscreen ? this.bgFullscreen : this.bg;
|
||||
const doc = document as any;
|
||||
const isFullscreen = doc.fullscreenElement || doc.webkitFullscreenElement || doc.mozFullScreenElement || doc.msFullscreenElement;
|
||||
const bg = isFullscreen ? this.bgFullscreen : this.bg;
|
||||
|
||||
this.time.update();
|
||||
let delta = this.time.delta;
|
||||
const delta = this.time.delta;
|
||||
|
||||
// Load the skeleton if the assets are ready.
|
||||
let loading = !this.assetManager!.isLoadingComplete();
|
||||
const loading = !this.assetManager!.isLoadingComplete();
|
||||
if (!this.skeleton && !loading) this.loadSkeleton();
|
||||
let skeleton = this.skeleton!;
|
||||
let config = this.config!;
|
||||
const skeleton = this.skeleton!;
|
||||
const config = this.config!;
|
||||
if (skeleton) {
|
||||
let playDelta = this.paused ? 0 : delta * this.speed;
|
||||
const playDelta = this.paused ? 0 : delta * this.speed;
|
||||
if (config.frame) config.frame(this, playDelta);
|
||||
|
||||
// Update animation time and pose the skeleton.
|
||||
@ -866,10 +858,10 @@ export class SpinePlayer implements Disposable {
|
||||
|
||||
if (config.showControls) {
|
||||
this.playTime += playDelta;
|
||||
let entry = this.animationState!.getCurrent(0);
|
||||
const entry = this.animationState!.getCurrent(0);
|
||||
if (entry) {
|
||||
let duration = entry.animation!.duration;
|
||||
while (this.playTime >= duration && duration != 0)
|
||||
const duration = entry.animation!.duration;
|
||||
while (this.playTime >= duration && duration !== 0)
|
||||
this.playTime -= duration;
|
||||
this.playTime = Math.max(0, Math.min(this.playTime, duration));
|
||||
this.timelineSlider!.setValue(this.playTime / duration);
|
||||
@ -878,19 +870,19 @@ export class SpinePlayer implements Disposable {
|
||||
}
|
||||
|
||||
// Determine the viewport.
|
||||
let viewport = this.viewport;
|
||||
const viewport = this.viewport;
|
||||
viewport.x = this.currentViewport.x - (this.currentViewport.padLeft as number);
|
||||
viewport.y = this.currentViewport.y - (this.currentViewport.padBottom as number);
|
||||
viewport.width = this.currentViewport.width + (this.currentViewport.padLeft as number) + (this.currentViewport.padRight as number);
|
||||
viewport.height = this.currentViewport.height + (this.currentViewport.padBottom as number) + (this.currentViewport.padTop as number);
|
||||
|
||||
if (this.previousViewport) {
|
||||
let transitionAlpha = (performance.now() - this.viewportTransitionStart) / 1000 / config.viewport!.transitionTime!;
|
||||
const transitionAlpha = (performance.now() - this.viewportTransitionStart) / 1000 / config.viewport!.transitionTime!;
|
||||
if (transitionAlpha < 1) {
|
||||
let x = this.previousViewport.x - (this.previousViewport.padLeft as number);
|
||||
let y = this.previousViewport.y - (this.previousViewport.padBottom as number);
|
||||
let width = this.previousViewport.width + (this.previousViewport.padLeft as number) + (this.previousViewport.padRight as number);
|
||||
let height = this.previousViewport.height + (this.previousViewport.padBottom as number) + (this.previousViewport.padTop as number);
|
||||
const x = this.previousViewport.x - (this.previousViewport.padLeft as number);
|
||||
const y = this.previousViewport.y - (this.previousViewport.padBottom as number);
|
||||
const width = this.previousViewport.width + (this.previousViewport.padLeft as number) + (this.previousViewport.padRight as number);
|
||||
const height = this.previousViewport.height + (this.previousViewport.padBottom as number) + (this.previousViewport.padTop as number);
|
||||
viewport.x = x + (viewport.x - x) * transitionAlpha;
|
||||
viewport.y = y + (viewport.y - y) * transitionAlpha;
|
||||
viewport.width = width + (viewport.width - width) * transitionAlpha;
|
||||
@ -898,7 +890,7 @@ export class SpinePlayer implements Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
let renderer = this.sceneRenderer!;
|
||||
const renderer = this.sceneRenderer!;
|
||||
renderer.camera.zoom = this.canvas!.height / this.canvas!.width > viewport.height / viewport.width
|
||||
? viewport.width / this.canvas!.width : viewport.height / this.canvas!.height;
|
||||
renderer.camera.position.x = viewport.x + viewport.width / 2;
|
||||
@ -908,7 +900,7 @@ export class SpinePlayer implements Disposable {
|
||||
renderer.resize(this.currentViewport.clip ? ResizeMode.FitClip : ResizeMode.Fit, viewport.width, viewport.height);
|
||||
|
||||
// Clear the screen.
|
||||
let gl = this.context!.gl;
|
||||
const gl = this.context!.gl;
|
||||
gl.clearColor(bg.r, bg.g, bg.b, bg.a);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
@ -917,9 +909,9 @@ export class SpinePlayer implements Disposable {
|
||||
renderer.begin();
|
||||
|
||||
// Draw the background image.
|
||||
let bgImage = config.backgroundImage;
|
||||
const bgImage = config.backgroundImage;
|
||||
if (bgImage) {
|
||||
let texture = this.assetManager!.require(bgImage.url) as GLTexture;
|
||||
const texture = this.assetManager!.require(bgImage.url) as GLTexture;
|
||||
if (bgImage.x !== void 0 && bgImage.y !== void 0 && bgImage.width && bgImage.height)
|
||||
renderer.drawTexture(texture, bgImage.x, bgImage.y, bgImage.width, bgImage.height);
|
||||
else
|
||||
@ -940,15 +932,15 @@ export class SpinePlayer implements Disposable {
|
||||
}
|
||||
|
||||
// Draw the control bones.
|
||||
let controlBones = config.controlBones!;
|
||||
const controlBones = config.controlBones!;
|
||||
if (controlBones.length) {
|
||||
let selectedBones = this.selectedBones;
|
||||
const selectedBones = this.selectedBones;
|
||||
gl.lineWidth(2);
|
||||
for (let i = 0; i < controlBones.length; i++) {
|
||||
let bone = skeleton.findBone(controlBones[i]);
|
||||
const bone = skeleton.findBone(controlBones[i]);
|
||||
if (!bone) continue;
|
||||
let colorInner = selectedBones[i] ? BONE_INNER_OVER : BONE_INNER;
|
||||
let colorOuter = selectedBones[i] ? BONE_OUTER_OVER : BONE_OUTER;
|
||||
const colorInner = selectedBones[i] ? BONE_INNER_OVER : BONE_INNER;
|
||||
const colorOuter = selectedBones[i] ? BONE_OUTER_OVER : BONE_OUTER;
|
||||
const applied = bone.applied;
|
||||
renderer.circle(true, skeleton.x + applied.worldX, skeleton.y + applied.worldY, 20, colorInner);
|
||||
renderer.circle(false, skeleton.x + applied.worldX, skeleton.y + applied.worldY, 20, colorOuter);
|
||||
@ -992,10 +984,10 @@ export class SpinePlayer implements Disposable {
|
||||
}
|
||||
|
||||
private showSpeedDialog (speedButton: HTMLElement) {
|
||||
let id = "speed";
|
||||
const id = "speed";
|
||||
if (this.hidePopup(id)) return;
|
||||
|
||||
let popup = new Popup(id, speedButton, this, this.playerControls!, /*html*/`
|
||||
const popup = new Popup(id, speedButton, this, this.playerControls!, /*html*/`
|
||||
<div class="spine-player-popup-title">Speed</div>
|
||||
<hr>
|
||||
<div class="spine-player-row" style="align-items:center;padding:8px">
|
||||
@ -1004,7 +996,7 @@ export class SpinePlayer implements Disposable {
|
||||
<div class="spine-player-row" style="justify-content:space-between"><div>0.1x</div><div>1x</div><div>2x</div></div>
|
||||
</div>
|
||||
</div>`);
|
||||
let slider = new Slider(2, 0.1, true);
|
||||
const slider = new Slider(2, 0.1, true);
|
||||
findWithClass(popup.dom, "spine-player-speed-slider").appendChild(slider.create());
|
||||
slider.setValue(this.speed / 2);
|
||||
slider.change = (percentage) => this.speed = percentage * 2;
|
||||
@ -1012,21 +1004,21 @@ export class SpinePlayer implements Disposable {
|
||||
}
|
||||
|
||||
private showAnimationsDialog (animationsButton: HTMLElement) {
|
||||
let id = "animations";
|
||||
const id = "animations";
|
||||
if (this.hidePopup(id)) return;
|
||||
if (!this.skeleton || !this.skeleton.data.animations.length) return;
|
||||
|
||||
let popup = new Popup(id, animationsButton, this, this.playerControls!,
|
||||
const popup = new Popup(id, animationsButton, this, this.playerControls!,
|
||||
/*html*/`<div class="spine-player-popup-title">Animations</div><hr><ul class="spine-player-list"></ul>`);
|
||||
|
||||
let rows = findWithClass(popup.dom, "spine-player-list");
|
||||
const rows = findWithClass(popup.dom, "spine-player-list");
|
||||
this.skeleton.data.animations.forEach((animation) => {
|
||||
// Skip animations not whitelisted if a whitelist was given.
|
||||
if (this.config.animations && this.config.animations.indexOf(animation.name) < 0) return;
|
||||
|
||||
let row = createElement(
|
||||
const row = createElement(
|
||||
/*html*/`<li class="spine-player-list-item selectable"><div class="selectable-circle"></div><div class="selectable-text"></div></li>`);
|
||||
if (animation.name == this.config.animation) row.classList.add("selected");
|
||||
if (animation.name === this.config.animation) row.classList.add("selected");
|
||||
findWithClass(row, "selectable-text").innerText = animation.name;
|
||||
rows.appendChild(row);
|
||||
row.onclick = () => {
|
||||
@ -1042,20 +1034,20 @@ export class SpinePlayer implements Disposable {
|
||||
}
|
||||
|
||||
private showSkinsDialog (skinButton: HTMLElement) {
|
||||
let id = "skins";
|
||||
const id = "skins";
|
||||
if (this.hidePopup(id)) return;
|
||||
if (!this.skeleton || !this.skeleton.data.animations.length) return;
|
||||
|
||||
let popup = new Popup(id, skinButton, this, this.playerControls!,
|
||||
const popup = new Popup(id, skinButton, this, this.playerControls!,
|
||||
/*html*/`<div class="spine-player-popup-title">Skins</div><hr><ul class="spine-player-list"></ul>`);
|
||||
|
||||
let rows = findWithClass(popup.dom, "spine-player-list");
|
||||
const rows = findWithClass(popup.dom, "spine-player-list");
|
||||
this.skeleton.data.skins.forEach((skin) => {
|
||||
// Skip skins not whitelisted if a whitelist was given.
|
||||
if (this.config.skins && this.config.skins.indexOf(skin.name) < 0) return;
|
||||
|
||||
let row = createElement(/*html*/`<li class="spine-player-list-item selectable"><div class="selectable-circle"></div><div class="selectable-text"></div></li>`);
|
||||
if (skin.name == this.config.skin) row.classList.add("selected");
|
||||
const row = createElement(/*html*/`<li class="spine-player-list-item selectable"><div class="selectable-circle"></div><div class="selectable-text"></div></li>`);
|
||||
if (skin.name === this.config.skin) row.classList.add("selected");
|
||||
findWithClass(row, "selectable-text").innerText = skin.name;
|
||||
rows.appendChild(row);
|
||||
row.onclick = () => {
|
||||
@ -1070,18 +1062,18 @@ export class SpinePlayer implements Disposable {
|
||||
}
|
||||
|
||||
private showSettingsDialog (settingsButton: HTMLElement) {
|
||||
let id = "settings";
|
||||
const id = "settings";
|
||||
if (this.hidePopup(id)) return;
|
||||
if (!this.skeleton || !this.skeleton.data.animations.length) return;
|
||||
|
||||
let popup = new Popup(id, settingsButton, this, this.playerControls!, /*html*/`<div class="spine-player-popup-title">Debug</div><hr><ul class="spine-player-list"></li>`);
|
||||
const popup = new Popup(id, settingsButton, this, this.playerControls!, /*html*/`<div class="spine-player-popup-title">Debug</div><hr><ul class="spine-player-list"></li>`);
|
||||
|
||||
let rows = findWithClass(popup.dom, "spine-player-list");
|
||||
let makeItem = (label: string, name: string) => {
|
||||
let row = createElement(/*html*/`<li class="spine-player-list-item"></li>`);
|
||||
let s = new Switch(label);
|
||||
const rows = findWithClass(popup.dom, "spine-player-list");
|
||||
const makeItem = (label: string, name: string) => {
|
||||
const row = createElement(/*html*/`<li class="spine-player-list-item"></li>`);
|
||||
const s = new Switch(label);
|
||||
row.appendChild(s.create());
|
||||
let debug = this.config.debug as any;
|
||||
const debug = this.config.debug as any;
|
||||
s.setEnabled(debug[name]);
|
||||
s.change = (value) => debug[name] = value;
|
||||
rows.appendChild(row);
|
||||
@ -1107,7 +1099,6 @@ export class SpinePlayer implements Disposable {
|
||||
+ message.replace("\n", "<br><br>") + `</div>`));
|
||||
if (this.config.error) this.config.error(this, message);
|
||||
throw (error ? error : new Error(message));
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1121,7 +1112,7 @@ class Popup {
|
||||
this.dom = createElement(/*html*/`<div class="spine-player-popup spine-player-hidden"></div>`);
|
||||
this.dom.innerHTML = htmlContent;
|
||||
parent.appendChild(this.dom);
|
||||
this.className = "spine-player-button-icon-" + id + "-selected";
|
||||
this.className = `spine-player-button-icon-${id}-selected`;
|
||||
}
|
||||
|
||||
dispose () {
|
||||
@ -1131,7 +1122,7 @@ class Popup {
|
||||
hide (id: string): boolean {
|
||||
this.dom.remove();
|
||||
this.button.classList.remove(this.className);
|
||||
if (this.id == id) {
|
||||
if (this.id === id) {
|
||||
this.player.popup = null;
|
||||
return true;
|
||||
}
|
||||
@ -1145,19 +1136,19 @@ class Popup {
|
||||
|
||||
// Make sure the popup isn't bigger than the player.
|
||||
let dismissed = false;
|
||||
let resize = () => {
|
||||
const resize = () => {
|
||||
if (!dismissed) requestAnimationFrame(resize);
|
||||
let playerDom = this.player.dom;
|
||||
let bottomOffset = Math.abs(playerDom.getBoundingClientRect().bottom - playerDom.getBoundingClientRect().bottom);
|
||||
let rightOffset = Math.abs(playerDom.getBoundingClientRect().right - playerDom.getBoundingClientRect().right);
|
||||
this.dom.style.maxHeight = (playerDom.clientHeight - bottomOffset - rightOffset) + "px";
|
||||
const playerDom = this.player.dom;
|
||||
const bottomOffset = Math.abs(playerDom.getBoundingClientRect().bottom - playerDom.getBoundingClientRect().bottom);
|
||||
const rightOffset = Math.abs(playerDom.getBoundingClientRect().right - playerDom.getBoundingClientRect().right);
|
||||
this.dom.style.maxHeight = `${playerDom.clientHeight - bottomOffset - rightOffset}px`;
|
||||
}
|
||||
requestAnimationFrame(resize);
|
||||
|
||||
// Dismiss when clicking somewhere outside the popup.
|
||||
let justClicked = true;
|
||||
let windowClickListener = (event: any) => {
|
||||
if (justClicked || this.player.popup != this) {
|
||||
const windowClickListener = (event: any) => {
|
||||
if (justClicked || this.player.popup !== this) {
|
||||
justClicked = false;
|
||||
return;
|
||||
}
|
||||
@ -1250,8 +1241,8 @@ class Slider {
|
||||
setValue (percentage: number): number {
|
||||
percentage = Math.max(0, Math.min(1, percentage));
|
||||
if (this.snaps) {
|
||||
let snap = 1 / this.snaps;
|
||||
let modulo = percentage % snap;
|
||||
const snap = 1 / this.snaps;
|
||||
const modulo = percentage % snap;
|
||||
// floor
|
||||
if (modulo < snap * this.snapPercentage)
|
||||
percentage = percentage - modulo;
|
||||
@ -1259,7 +1250,7 @@ class Slider {
|
||||
percentage = percentage - modulo + snap;
|
||||
percentage = Math.max(0, Math.min(1, percentage));
|
||||
}
|
||||
this.value!.style.width = "" + (percentage * 100) + "%";
|
||||
this.value!.style.width = `${percentage * 100}%`;
|
||||
// this.knob.style.left = "" + (-8 + percentage * this.slider.clientWidth) + "px";
|
||||
return percentage;
|
||||
}
|
||||
@ -1270,7 +1261,7 @@ function findWithClass (element: HTMLElement, className: string): HTMLElement {
|
||||
}
|
||||
|
||||
function createElement (html: string): HTMLElement {
|
||||
let div = document.createElement("div");
|
||||
const div = document.createElement("div");
|
||||
div.innerHTML = html;
|
||||
return div.children[0] as HTMLElement;
|
||||
}
|
||||
@ -1280,7 +1271,7 @@ function removeClass (elements: HTMLCollection, clazz: string) {
|
||||
elements[i].classList.remove(clazz);
|
||||
}
|
||||
|
||||
function toString (object: any) {
|
||||
function print (object: any) {
|
||||
return JSON.stringify(object)
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
|
||||
@ -88,14 +88,14 @@ body { margin: 0px; }
|
||||
}
|
||||
|
||||
private render (parent: HTMLElement) {
|
||||
let dom = /*html*/`
|
||||
const dom = /*html*/`
|
||||
<div style="display: flex; flex-direction: column; width: 100%; height: 100%;">
|
||||
<div style="width: 100%; height: 50%"></div>
|
||||
<iframe style="width: 100%; height: 50%; outline: none; border: none;"></iframe>
|
||||
</div>
|
||||
`;
|
||||
parent.innerHTML = dom;
|
||||
let codeElement = parent.children[0].children[0];
|
||||
const codeElement = parent.children[0].children[0];
|
||||
this.player = parent.children[0].children[1] as HTMLIFrameElement;
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export * from './Player.js';
|
||||
export * from './PlayerEditor.js';
|
||||
export * from "@esotericsoftware/spine-core";
|
||||
export * from "@esotericsoftware/spine-webgl";
|
||||
export * from "@esotericsoftware/spine-webgl";
|
||||
export * from './Player.js';
|
||||
export * from './PlayerEditor.js';
|
||||
@ -27,9 +27,9 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { AssetCache, AssetManager, Color, Disposable, Input, LoadingScreen, ManagedWebGLRenderingContext, Physics, SceneRenderer, TimeKeeper, Vector2, Vector3 } from "@esotericsoftware/spine-webgl"
|
||||
import { SpineWebComponentSkeleton } from "./SpineWebComponentSkeleton.js"
|
||||
import { AttributeTypes, castValue, Point, Rectangle } from "./wcUtils.js"
|
||||
import { AssetCache, AssetManager, type Bone, Color, type Disposable, Input, LoadingScreen, ManagedWebGLRenderingContext, Physics, SceneRenderer, type Skeleton, TimeKeeper, Vector2, Vector3 } from "@esotericsoftware/spine-webgl"
|
||||
import type { SpineWebComponentSkeleton } from "./SpineWebComponentSkeleton.js"
|
||||
import { type AttributeTypes, castValue, type Point, type Rectangle } from "./wcUtils.js"
|
||||
|
||||
interface OverlayAttributes {
|
||||
overlayId?: string
|
||||
@ -41,6 +41,8 @@ interface OverlayAttributes {
|
||||
}
|
||||
|
||||
export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttributes, Disposable {
|
||||
declare parentElement: HTMLElement;
|
||||
|
||||
private static OVERLAY_ID = "spine-overlay-default-identifier";
|
||||
private static OVERLAY_LIST = new Map<string, SpineWebComponentOverlay>();
|
||||
|
||||
@ -66,7 +68,7 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
/**
|
||||
* A list holding the widgets added to this overlay.
|
||||
*/
|
||||
public widgets = new Array<SpineWebComponentSkeleton>();
|
||||
public widgets = [] as SpineWebComponentSkeleton[];
|
||||
|
||||
/**
|
||||
* The {@link SceneRenderer} used by this overlay.
|
||||
@ -256,7 +258,7 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
const { target, intersectionRatio } = elem;
|
||||
let { isIntersecting } = elem;
|
||||
for (const widget of this.widgets) {
|
||||
if (widget.getHostElement() != target) continue;
|
||||
if (widget.getHostElement() !== target) continue;
|
||||
|
||||
// old browsers do not have isIntersecting
|
||||
if (isIntersecting === undefined) {
|
||||
@ -277,13 +279,13 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
if (this.hasCssTweakOff()) {
|
||||
this.hasParentTransform = false;
|
||||
} else {
|
||||
this.parentElement!.style.transform = `translateZ(0)`;
|
||||
this.parentElement.style.transform = `translateZ(0)`;
|
||||
}
|
||||
} else {
|
||||
window.addEventListener("resize", this.windowResizeCallback);
|
||||
}
|
||||
this.resizeObserver = new ResizeObserver(() => this.resizedCallback());
|
||||
this.resizeObserver.observe(this.parentElement!);
|
||||
this.resizeObserver.observe(this.parentElement);
|
||||
|
||||
for (const widget of this.widgets) {
|
||||
this.intersectionObserver?.observe(widget.getHostElement());
|
||||
@ -308,7 +310,7 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
this.input?.dispose();
|
||||
}
|
||||
|
||||
static attributesDescription: Record<string, { propertyName: keyof OverlayAttributes, type: AttributeTypes, defaultValue?: any }> = {
|
||||
static attributesDescription: Record<string, { propertyName: keyof OverlayAttributes, type: AttributeTypes, defaultValue?: OverlayAttributes[keyof OverlayAttributes] }> = {
|
||||
"overlay-id": { propertyName: "overlayId", type: "string" },
|
||||
"no-auto-parent-transform": { propertyName: "noAutoParentTransform", type: "boolean" },
|
||||
"overflow-top": { propertyName: "overflowTop", type: "number" },
|
||||
@ -324,7 +326,7 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
attributeChangedCallback (name: string, oldValue: string | null, newValue: string | null): void {
|
||||
const { type, propertyName, defaultValue } = SpineWebComponentOverlay.attributesDescription[name];
|
||||
const val = castValue(type, newValue, defaultValue);
|
||||
(this as any)[propertyName] = val;
|
||||
(this[propertyName] as OverlayAttributes[typeof propertyName]) = val as OverlayAttributes[typeof propertyName];
|
||||
return;
|
||||
}
|
||||
|
||||
@ -360,12 +362,12 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
this.scrolledCallback();
|
||||
if (!this.loaded) {
|
||||
this.loaded = true;
|
||||
this.parentElement!.appendChild(this);
|
||||
this.parentElement.appendChild(this);
|
||||
}
|
||||
}
|
||||
|
||||
private hasCssTweakOff () {
|
||||
return this.noAutoParentTransform && getComputedStyle(this.parentElement!).transform === "none";
|
||||
return this.noAutoParentTransform && getComputedStyle(this.parentElement).transform === "none";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -393,7 +395,7 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
const comparison = this.compareDocumentPosition(widget);
|
||||
// DOCUMENT_POSITION_DISCONNECTED is needed when a widget is inside the overlay (due to followBone)
|
||||
if ((comparison & Node.DOCUMENT_POSITION_FOLLOWING) && !(comparison & Node.DOCUMENT_POSITION_DISCONNECTED)) {
|
||||
this.parentElement!.appendChild(this);
|
||||
this.parentElement.appendChild(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -448,7 +450,7 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
this.div.appendChild(this.fps);
|
||||
this.fpsAppended = true;
|
||||
}
|
||||
this.fps.innerText = this.time.framesPerSecond.toFixed(2) + " fps";
|
||||
this.fps.innerText = `${this.time.framesPerSecond.toFixed(2)} fps`;
|
||||
} else {
|
||||
if (this.fpsAppended) {
|
||||
this.div.removeChild(this.fps);
|
||||
@ -482,15 +484,15 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
|
||||
const renderWidgets = () => {
|
||||
clear(0, 0, 0, 0);
|
||||
let renderer = this.renderer;
|
||||
const renderer = this.renderer;
|
||||
renderer.begin();
|
||||
|
||||
let ref: DOMRect;
|
||||
let offsetLeftForOevrlay = 0;
|
||||
let offsetTopForOverlay = 0;
|
||||
if (!this.appendedToBody) {
|
||||
ref = this.parentElement!.getBoundingClientRect();
|
||||
const computedStyle = getComputedStyle(this.parentElement!);
|
||||
ref = this.parentElement.getBoundingClientRect();
|
||||
const computedStyle = getComputedStyle(this.parentElement);
|
||||
offsetLeftForOevrlay = ref.left + parseFloat(computedStyle.borderLeftWidth);
|
||||
offsetTopForOverlay = ref.top + parseFloat(computedStyle.borderTopWidth);
|
||||
}
|
||||
@ -532,7 +534,7 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
if (loading) {
|
||||
if (spinner) {
|
||||
if (!widget.loadingScreen) widget.loadingScreen = new LoadingScreen(renderer);
|
||||
widget.loadingScreen!.drawInCoordinates(divOriginX, divOriginY);
|
||||
widget.loadingScreen?.drawInCoordinates(divOriginX, divOriginY);
|
||||
}
|
||||
if (clip) endScissor();
|
||||
continue;
|
||||
@ -540,7 +542,7 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
|
||||
if (skeleton) {
|
||||
if (fit !== "origin") {
|
||||
let { x: ax, y: ay, width: aw, height: ah } = bounds;
|
||||
const { x: ax, y: ay, width: aw, height: ah } = bounds;
|
||||
if (aw <= 0 || ah <= 0) continue;
|
||||
|
||||
// scale ratio
|
||||
@ -622,7 +624,7 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
// drawing debug stuff
|
||||
if (debug) {
|
||||
// if (true) {
|
||||
let { x: ax, y: ay, width: aw, height: ah } = bounds;
|
||||
const { x: ax, y: ay, width: aw, height: ah } = bounds;
|
||||
|
||||
// show bounds and its center
|
||||
if (drag) {
|
||||
@ -645,7 +647,7 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
renderer.circle(true, bbCenterX, bbCenterY, 10, blue);
|
||||
|
||||
// show skeleton root
|
||||
const root = skeleton.getRootBone()!;
|
||||
const root = skeleton.getRootBone() as Bone;
|
||||
renderer.circle(true, root.applied.x + worldOffsetX, root.applied.y + worldOffsetY, 10, red);
|
||||
|
||||
// show shifted origin
|
||||
@ -720,7 +722,6 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
const red = new Color(1, 0, 0, 1);
|
||||
const green = new Color(0, 1, 0, 1);
|
||||
const blue = new Color(0, 0, 1, 1);
|
||||
const transparentWhite = new Color(1, 1, 1, .3);
|
||||
const transparentRed = new Color(1, 0, 0, .3);
|
||||
}
|
||||
|
||||
@ -735,12 +736,12 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
this.pointerCanvasY = input.y - window.scrollY;
|
||||
|
||||
if (!this.appendedToBody) {
|
||||
const ref = this.parentElement!.getBoundingClientRect();
|
||||
const ref = this.parentElement.getBoundingClientRect();
|
||||
this.pointerCanvasX -= ref.left;
|
||||
this.pointerCanvasY -= ref.top;
|
||||
}
|
||||
|
||||
let tempVector = this.tempVector;
|
||||
const tempVector = this.tempVector;
|
||||
tempVector.set(this.pointerCanvasX, this.pointerCanvasY, 0);
|
||||
this.renderer.camera.screenToWorld(tempVector, this.canvas.clientWidth, this.canvas.clientHeight);
|
||||
|
||||
@ -763,8 +764,8 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
const inputManager = new Input(document.body, false)
|
||||
const inputPointTemp: Point = new Vector2();
|
||||
|
||||
const getInput = (ev?: MouseEvent | TouchEvent): Point => {
|
||||
const originalEvent = ev instanceof MouseEvent ? ev : ev!.changedTouches[0];
|
||||
const getInput = (ev: MouseEvent | TouchEvent): Point => {
|
||||
const originalEvent = ev instanceof MouseEvent ? ev : ev.changedTouches[0];
|
||||
inputPointTemp.x = originalEvent.pageX + this.overflowLeftSize;
|
||||
inputPointTemp.y = originalEvent.pageY + this.overflowTopSize;
|
||||
return inputPointTemp;
|
||||
@ -774,7 +775,7 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
let lastY = 0;
|
||||
inputManager.addListener({
|
||||
// moved is used to pass pointer position wrt to canvas and widget position and currently is EXPERIMENTAL
|
||||
moved: (x, y, ev) => {
|
||||
moved: (x, y, ev: MouseEvent | TouchEvent) => {
|
||||
const input = getInput(ev);
|
||||
this.updatePointer(input);
|
||||
|
||||
@ -784,7 +785,7 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
widget.pointerEventUpdate("move", ev);
|
||||
}
|
||||
},
|
||||
down: (x, y, ev) => {
|
||||
down: (x, y, ev: MouseEvent | TouchEvent) => {
|
||||
const input = getInput(ev);
|
||||
|
||||
this.updatePointer(input);
|
||||
@ -805,11 +806,11 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
lastX = input.x;
|
||||
lastY = input.y;
|
||||
},
|
||||
dragged: (x, y, ev) => {
|
||||
dragged: (x, y, ev: MouseEvent | TouchEvent) => {
|
||||
const input = getInput(ev);
|
||||
|
||||
let dragX = input.x - lastX;
|
||||
let dragY = input.y - lastY;
|
||||
const dragX = input.x - lastX;
|
||||
const dragY = input.y - lastY;
|
||||
|
||||
this.updatePointer(input);
|
||||
|
||||
@ -820,7 +821,7 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
|
||||
if (!widget.dragging) continue;
|
||||
|
||||
const skeleton = widget.skeleton!;
|
||||
const skeleton = widget.skeleton as Skeleton;
|
||||
widget.dragX += this.screenToWorldLength(dragX);
|
||||
widget.dragY -= this.screenToWorldLength(dragY);
|
||||
skeleton.physicsTranslate(dragX, -dragY);
|
||||
@ -861,8 +862,8 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
const totalWidth = width * (1 + (this.overflowLeft + this.overflowRight));
|
||||
const totalHeight = height * (1 + (this.overflowTop + this.overflowBottom));
|
||||
|
||||
this.canvas.style.width = totalWidth + "px";
|
||||
this.canvas.style.height = totalHeight + "px";
|
||||
this.canvas.style.width = `${totalWidth}px`;
|
||||
this.canvas.style.height = `${totalHeight}px`;
|
||||
this.resize(totalWidth, totalHeight);
|
||||
}
|
||||
|
||||
@ -872,28 +873,28 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
// this.div?.remove(); is it better width/height to zero?
|
||||
// this.div!.style.width = 0 + "px";
|
||||
// this.div!.style.height = 0 + "px";
|
||||
this.div!.style.display = "none";
|
||||
this.div.style.display = "none";
|
||||
if (this.appendedToBody) {
|
||||
const { width, height } = this.getPageSize();
|
||||
this.div!.style.width = width + "px";
|
||||
this.div!.style.height = height + "px";
|
||||
this.div.style.width = `${width}px`;
|
||||
this.div.style.height = `${height}px`;
|
||||
} else {
|
||||
if (this.hasCssTweakOff()) {
|
||||
// this case lags if scrolls or position fixed. Users should never use tweak off
|
||||
this.div!.style.width = this.parentElement!.clientWidth + "px";
|
||||
this.div!.style.height = this.parentElement!.clientHeight + "px";
|
||||
this.div.style.width = `${this.parentElement.clientWidth}px`;
|
||||
this.div.style.height = `${this.parentElement.clientHeight}px`;
|
||||
this.canvas.style.transform = `translate(${-this.overflowLeftSize}px,${-this.overflowTopSize}px)`;
|
||||
} else {
|
||||
this.div!.style.width = this.parentElement!.scrollWidth + "px";
|
||||
this.div!.style.height = this.parentElement!.scrollHeight + "px";
|
||||
this.div.style.width = `${this.parentElement.scrollWidth}px`;
|
||||
this.div.style.height = `${this.parentElement.scrollHeight}px`;
|
||||
}
|
||||
}
|
||||
this.div!.style.display = "";
|
||||
this.div.style.display = "";
|
||||
// this.root.appendChild(this.div!);
|
||||
}
|
||||
|
||||
private resize (width: number, height: number) {
|
||||
let canvas = this.canvas;
|
||||
const canvas = this.canvas;
|
||||
canvas.width = Math.round(this.screenToWorldLength(width));
|
||||
canvas.height = Math.round(this.screenToWorldLength(height));
|
||||
this.renderer.context.gl.viewport(0, 0, canvas.width, canvas.height);
|
||||
@ -921,13 +922,13 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
private getViewportSize (): { width: number, height: number } {
|
||||
if (!this.appendedToBody) {
|
||||
return {
|
||||
width: this.parentElement!.clientWidth,
|
||||
height: this.parentElement!.clientHeight,
|
||||
width: this.parentElement.clientWidth,
|
||||
height: this.parentElement.clientHeight,
|
||||
}
|
||||
}
|
||||
|
||||
let width = window.innerWidth;
|
||||
let height = window.innerHeight;
|
||||
const width = window.innerWidth;
|
||||
const height = window.innerHeight;
|
||||
|
||||
const dpr = this.getDevicePixelRatio();
|
||||
if (dpr !== this.lastDPR) {
|
||||
@ -993,10 +994,10 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
// Ideally this should be the only appendedToBody case (no-auto-parent-transform not enabled or at least an ancestor has transform)
|
||||
// I'd like to get rid of the else case
|
||||
if (this.hasParentTransform) {
|
||||
scrollPositionX += this.parentElement!.scrollLeft;
|
||||
scrollPositionY += this.parentElement!.scrollTop;
|
||||
scrollPositionX += this.parentElement.scrollLeft;
|
||||
scrollPositionY += this.parentElement.scrollTop;
|
||||
} else {
|
||||
const { left, top } = this.parentElement!.getBoundingClientRect();
|
||||
const { left, top } = this.parentElement.getBoundingClientRect();
|
||||
scrollPositionX += left + window.scrollX;
|
||||
scrollPositionY += top + window.scrollY;
|
||||
|
||||
@ -1027,10 +1028,10 @@ export class SpineWebComponentOverlay extends HTMLElement implements OverlayAttr
|
||||
let parent: HTMLElement | null = element;
|
||||
let zIndex: undefined | number;
|
||||
do {
|
||||
let currentZIndex = parseInt(getComputedStyle(parent).zIndex);
|
||||
const currentZIndex = parseInt(getComputedStyle(parent).zIndex);
|
||||
|
||||
// searching the shallowest z-index
|
||||
if (!isNaN(currentZIndex)) zIndex = currentZIndex;
|
||||
if (!Number.isNaN(currentZIndex)) zIndex = currentZIndex;
|
||||
parent = parent.parentElement;
|
||||
} while (parent && parent !== document.body)
|
||||
|
||||
|
||||
@ -28,31 +28,32 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import {
|
||||
Animation,
|
||||
type Animation,
|
||||
AnimationState,
|
||||
AnimationStateData,
|
||||
AtlasAttachmentLoader,
|
||||
Bone,
|
||||
Disposable,
|
||||
LoadingScreen,
|
||||
type Bone,
|
||||
type Disposable,
|
||||
type LoadingScreen,
|
||||
MeshAttachment,
|
||||
MixBlend,
|
||||
MixDirection,
|
||||
NumberArrayLike,
|
||||
type NumberArrayLike,
|
||||
Physics,
|
||||
RegionAttachment,
|
||||
Skeleton,
|
||||
SkeletonBinary,
|
||||
SkeletonData,
|
||||
type SkeletonData,
|
||||
SkeletonJson,
|
||||
Skin,
|
||||
Slot,
|
||||
TextureAtlas,
|
||||
type Slot,
|
||||
type TextureAtlas,
|
||||
type TrackEntry,
|
||||
Utils,
|
||||
Vector2,
|
||||
} from "@esotericsoftware/spine-webgl";
|
||||
import { SpineWebComponentOverlay } from "./SpineWebComponentOverlay.js";
|
||||
import { AttributeTypes, castValue, isBase64, Rectangle } from "./wcUtils.js";
|
||||
import { type AttributeTypes, castValue, isBase64, type Rectangle } from "./wcUtils.js";
|
||||
|
||||
type UpdateSpineWidgetFunction = (delta: number, skeleton: Skeleton, state: AnimationState) => void;
|
||||
|
||||
@ -456,10 +457,10 @@ export class SpineWebComponentSkeleton extends HTMLElement implements Disposable
|
||||
}
|
||||
|
||||
private getSlotFromRef (slotRef: number | string | Slot): Slot {
|
||||
let slot: Slot | null;
|
||||
let slot: Slot | null | undefined;
|
||||
|
||||
if (typeof slotRef === 'number') slot = this.skeleton!.slots[slotRef];
|
||||
else if (typeof slotRef === 'string') slot = this.skeleton!.findSlot(slotRef);
|
||||
if (typeof slotRef === 'number') slot = this.skeleton?.slots[slotRef];
|
||||
else if (typeof slotRef === 'string') slot = this.skeleton?.findSlot(slotRef);
|
||||
else slot = slotRef;
|
||||
|
||||
if (!slot) throw new Error(`No slot found with the given slot reference: ${slotRef}`);
|
||||
@ -686,7 +687,7 @@ export class SpineWebComponentSkeleton extends HTMLElement implements Disposable
|
||||
// - remove appendTo that is just to avoid the user to use the overlayAssignedPromise when the widget is created using js
|
||||
private overlayAssignedPromise: Promise<void>;
|
||||
|
||||
static attributesDescription: Record<string, { propertyName: keyof WidgetAttributes, type: AttributeTypes, defaultValue?: any }> = {
|
||||
static attributesDescription: Record<string, { propertyName: keyof WidgetAttributes, type: AttributeTypes, defaultValue?: WidgetAttributes[keyof WidgetAttributes] }> = {
|
||||
atlas: { propertyName: "atlasPath", type: "string" },
|
||||
skeleton: { propertyName: "skeletonPath", type: "string" },
|
||||
"raw-data": { propertyName: "rawData", type: "object" },
|
||||
@ -776,7 +777,7 @@ export class SpineWebComponentSkeleton extends HTMLElement implements Disposable
|
||||
window.removeEventListener("DOMContentLoaded", this.DOMContentLoadedCallback);
|
||||
const index = this.overlay?.widgets.indexOf(this);
|
||||
if (index > 0) {
|
||||
this.overlay!.widgets.splice(index, 1);
|
||||
this.overlay?.widgets.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -797,7 +798,7 @@ export class SpineWebComponentSkeleton extends HTMLElement implements Disposable
|
||||
attributeChangedCallback (name: string, oldValue: string | null, newValue: string | null): void {
|
||||
const { type, propertyName, defaultValue } = SpineWebComponentSkeleton.attributesDescription[name];
|
||||
const val = castValue(type, newValue, defaultValue);
|
||||
(this as any)[propertyName] = val;
|
||||
(this[propertyName] as WidgetAttributes[typeof propertyName]) = val as WidgetAttributes[typeof propertyName];
|
||||
return;
|
||||
}
|
||||
|
||||
@ -830,12 +831,12 @@ export class SpineWebComponentSkeleton extends HTMLElement implements Disposable
|
||||
* @param atlas the `TextureAtlas` from which to get the `TextureAtlasPage`s
|
||||
* @returns The list of loaded assets
|
||||
*/
|
||||
public async loadTexturesInPagesAttribute (): Promise<Array<any>> {
|
||||
const atlas = this.overlay.assetManager.require(this.atlasPath!) as TextureAtlas;
|
||||
public async loadTexturesInPagesAttribute (): Promise<Array<string>> {
|
||||
const atlas = this.overlay.assetManager.require(this.atlasPath as string) as TextureAtlas;
|
||||
const pagesIndexToLoad = this.pages ?? atlas.pages.map((_, i) => i); // if no pages provided, loads all
|
||||
const atlasPath = this.atlasPath?.includes("/") ? this.atlasPath.substring(0, this.atlasPath.lastIndexOf("/") + 1) : "";
|
||||
const promisePageList: Array<Promise<any>> = [];
|
||||
const texturePaths = [];
|
||||
const promisePageList: Array<Promise<string>> = [];
|
||||
const texturePaths = [] as string[];
|
||||
|
||||
for (const index of pagesIndexToLoad) {
|
||||
const page = atlas.pages[index];
|
||||
@ -866,7 +867,7 @@ export class SpineWebComponentSkeleton extends HTMLElement implements Disposable
|
||||
*/
|
||||
public getHostElement (): HTMLElement {
|
||||
return (this.width <= 0 || this.width <= 0) && !this.getAttribute("style") && !this.getAttribute("class")
|
||||
? this.parentElement!
|
||||
? this.parentElement as HTMLElement
|
||||
: this;
|
||||
}
|
||||
|
||||
@ -934,7 +935,7 @@ export class SpineWebComponentSkeleton extends HTMLElement implements Disposable
|
||||
const isBinary = skeletonPath.endsWith(".skel");
|
||||
|
||||
if (rawData) {
|
||||
for (let [key, value] of Object.entries(rawData)) {
|
||||
for (const [key, value] of Object.entries(rawData)) {
|
||||
this.overlay.assetManager.setRawDataURI(key, isBase64(value) ? `data:application/octet-stream;base64,${value}` : value);
|
||||
}
|
||||
}
|
||||
@ -1032,7 +1033,7 @@ export class SpineWebComponentSkeleton extends HTMLElement implements Disposable
|
||||
const cycleFn = () => {
|
||||
const trackIndex = Number(trackIndexString);
|
||||
for (const [index, { animationName, delay, loop, mixDuration }] of animations.entries()) {
|
||||
let track;
|
||||
let track: TrackEntry;
|
||||
if (index === 0) {
|
||||
if (animationName === "#EMPTY#") {
|
||||
track = state.setEmptyAnimation(trackIndex, mixDuration);
|
||||
@ -1076,7 +1077,7 @@ export class SpineWebComponentSkeleton extends HTMLElement implements Disposable
|
||||
}
|
||||
|
||||
private render (): void {
|
||||
let noSize = (!this.getAttribute("style") && !this.getAttribute("class"));
|
||||
const noSize = (!this.getAttribute("style") && !this.getAttribute("class"));
|
||||
this.root.innerHTML = `
|
||||
<style>
|
||||
:host {
|
||||
@ -1155,24 +1156,24 @@ export class SpineWebComponentSkeleton extends HTMLElement implements Disposable
|
||||
}
|
||||
|
||||
private checkSlotInteraction (type: PointerEventTypesInput, originalEvent?: UIEvent) {
|
||||
for (let [slot, interactionState] of this.pointerSlotEventCallbacks) {
|
||||
for (const [slot, interactionState] of this.pointerSlotEventCallbacks) {
|
||||
if (!slot.bone.active) continue;
|
||||
let attachment = slot.applied.attachment;
|
||||
const attachment = slot.applied.attachment;
|
||||
|
||||
if (!(attachment instanceof RegionAttachment || attachment instanceof MeshAttachment)) continue;
|
||||
|
||||
const { slotFunction, inside } = interactionState
|
||||
|
||||
let vertices = this.verticesTemp;
|
||||
const vertices = this.verticesTemp;
|
||||
let hullLength = 8;
|
||||
|
||||
// we could probably cache the vertices from rendering if interaction with this slot is enabled
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
let regionAttachment = <RegionAttachment>attachment;
|
||||
const regionAttachment = <RegionAttachment>attachment;
|
||||
regionAttachment.computeWorldVertices(slot, vertices, 0, 2);
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
let mesh = <MeshAttachment>attachment;
|
||||
mesh.computeWorldVertices(this.skeleton!, slot, 0, mesh.worldVerticesLength, vertices, 0, 2);
|
||||
const mesh = <MeshAttachment>attachment;
|
||||
mesh.computeWorldVertices(this.skeleton as Skeleton, slot, 0, mesh.worldVerticesLength, vertices, 0, 2);
|
||||
hullLength = mesh.hullLength;
|
||||
}
|
||||
|
||||
@ -1274,7 +1275,7 @@ export class SpineWebComponentSkeleton extends HTMLElement implements Disposable
|
||||
if (!skeleton) return { x: 0, y: 0, width: 0, height: 0 };
|
||||
skeleton.setupPose();
|
||||
|
||||
let offset = new Vector2(), size = new Vector2();
|
||||
const offset = new Vector2(), size = new Vector2();
|
||||
const tempArray = new Array<number>(2);
|
||||
if (!animation) {
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
@ -1294,8 +1295,8 @@ export class SpineWebComponentSkeleton extends HTMLElement implements Disposable
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
skeleton.getBounds(offset, size, tempArray, renderer.skeletonRenderer.getSkeletonClipping());
|
||||
|
||||
if (!isNaN(offset.x) && !isNaN(offset.y) && !isNaN(size.x) && !isNaN(size.y) &&
|
||||
!isNaN(minX) && !isNaN(minY) && !isNaN(maxX) && !isNaN(maxY)) {
|
||||
if (!Number.isNaN(offset.x) && !Number.isNaN(offset.y) && !Number.isNaN(size.x) && !Number.isNaN(size.y) &&
|
||||
!Number.isNaN(minX) && !Number.isNaN(minY) && !Number.isNaN(maxX) && !Number.isNaN(maxY)) {
|
||||
minX = Math.min(offset.x, minX);
|
||||
maxX = Math.max(offset.x + size.x, maxX);
|
||||
minY = Math.min(offset.y, minY);
|
||||
@ -1345,7 +1346,7 @@ export function createSkeleton (parameters: WidgetAttributes): SpineWebComponent
|
||||
Object.entries(SpineWebComponentSkeleton.attributesDescription).forEach(entry => {
|
||||
const [key, { propertyName }] = entry;
|
||||
const value = parameters[propertyName];
|
||||
if (value) widget.setAttribute(key, value as any);
|
||||
if (value) widget.setAttribute(key, value as string);
|
||||
});
|
||||
|
||||
return widget;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export * from './SpineWebComponentSkeleton.js';
|
||||
export * from './SpineWebComponentOverlay.js';
|
||||
export * from "@esotericsoftware/spine-core";
|
||||
export * from "@esotericsoftware/spine-webgl";
|
||||
export * from './SpineWebComponentOverlay.js';
|
||||
export * from './SpineWebComponentSkeleton.js';
|
||||
|
||||
@ -28,8 +28,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
import { AssetManagerBase, Downloader } from "@esotericsoftware/spine-core"
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL.js";
|
||||
import { GLTexture } from "./GLTexture.js";
|
||||
import type { ManagedWebGLRenderingContext } from "./WebGL.js";
|
||||
|
||||
export class AssetManager extends AssetManagerBase {
|
||||
constructor (context: ManagedWebGLRenderingContext | WebGLRenderingContext, pathPrefix: string = "", downloader: Downloader = new Downloader()) {
|
||||
|
||||
@ -51,11 +51,11 @@ export class OrthoCamera {
|
||||
}
|
||||
|
||||
update () {
|
||||
let projection = this.projection;
|
||||
let view = this.view;
|
||||
let projectionView = this.projectionView;
|
||||
let inverseProjectionView = this.inverseProjectionView;
|
||||
let zoom = this.zoom, viewportWidth = this.viewportWidth, viewportHeight = this.viewportHeight;
|
||||
const projection = this.projection;
|
||||
const view = this.view;
|
||||
const projectionView = this.projectionView;
|
||||
const inverseProjectionView = this.inverseProjectionView;
|
||||
const zoom = this.zoom, viewportWidth = this.viewportWidth, viewportHeight = this.viewportHeight;
|
||||
projection.ortho(zoom * (-viewportWidth / 2), zoom * (viewportWidth / 2),
|
||||
zoom * (-viewportHeight / 2), zoom * (viewportHeight / 2),
|
||||
this.near, this.far);
|
||||
@ -66,7 +66,7 @@ export class OrthoCamera {
|
||||
}
|
||||
|
||||
screenToWorld (screenCoords: Vector3, screenWidth: number, screenHeight: number) {
|
||||
let x = screenCoords.x, y = screenHeight - screenCoords.y - 1;
|
||||
const x = screenCoords.x, y = screenHeight - screenCoords.y - 1;
|
||||
screenCoords.x = (2 * x) / screenWidth - 1;
|
||||
screenCoords.y = (2 * y) / screenHeight - 1;
|
||||
screenCoords.z = (2 * screenCoords.z) - 1;
|
||||
|
||||
@ -27,13 +27,13 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import type { OrthoCamera } from "./Camera.js";
|
||||
import { Input } from "./Input.js";
|
||||
import { OrthoCamera } from "./Camera.js";
|
||||
import { Vector3 } from "./Vector3.js";
|
||||
|
||||
export class CameraController {
|
||||
constructor (public canvas: HTMLElement, public camera: OrthoCamera) {
|
||||
let cameraX = 0, cameraY = 0, cameraZoom = 0;
|
||||
let cameraX = 0, cameraY = 0;
|
||||
let mouseX = 0, mouseY = 0;
|
||||
let lastX = 0, lastY = 0;
|
||||
let initialZoom = 0;
|
||||
@ -47,39 +47,39 @@ export class CameraController {
|
||||
initialZoom = camera.zoom;
|
||||
},
|
||||
dragged: (x: number, y: number) => {
|
||||
let deltaX = x - mouseX;
|
||||
let deltaY = y - mouseY;
|
||||
let originWorld = camera.screenToWorld(new Vector3(0, 0), canvas.clientWidth, canvas.clientHeight);
|
||||
let deltaWorld = camera.screenToWorld(new Vector3(deltaX, deltaY), canvas.clientWidth, canvas.clientHeight).sub(originWorld);
|
||||
const deltaX = x - mouseX;
|
||||
const deltaY = y - mouseY;
|
||||
const originWorld = camera.screenToWorld(new Vector3(0, 0), canvas.clientWidth, canvas.clientHeight);
|
||||
const deltaWorld = camera.screenToWorld(new Vector3(deltaX, deltaY), canvas.clientWidth, canvas.clientHeight).sub(originWorld);
|
||||
camera.position.set(cameraX - deltaWorld.x, cameraY - deltaWorld.y, 0);
|
||||
camera.update();
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
},
|
||||
wheel: (delta: number) => {
|
||||
let zoomAmount = delta / 200 * camera.zoom;
|
||||
let newZoom = camera.zoom + zoomAmount;
|
||||
const zoomAmount = delta / 200 * camera.zoom;
|
||||
const newZoom = camera.zoom + zoomAmount;
|
||||
if (newZoom > 0) {
|
||||
let x = 0, y = 0;
|
||||
if (delta < 0) {
|
||||
x = lastX; y = lastY;
|
||||
} else {
|
||||
let viewCenter = new Vector3(canvas.clientWidth / 2 + 15, canvas.clientHeight / 2);
|
||||
let mouseToCenterX = lastX - viewCenter.x;
|
||||
let mouseToCenterY = canvas.clientHeight - 1 - lastY - viewCenter.y;
|
||||
const viewCenter = new Vector3(canvas.clientWidth / 2 + 15, canvas.clientHeight / 2);
|
||||
const mouseToCenterX = lastX - viewCenter.x;
|
||||
const mouseToCenterY = canvas.clientHeight - 1 - lastY - viewCenter.y;
|
||||
x = viewCenter.x - mouseToCenterX;
|
||||
y = canvas.clientHeight - 1 - viewCenter.y + mouseToCenterY;
|
||||
}
|
||||
let oldDistance = camera.screenToWorld(new Vector3(x, y), canvas.clientWidth, canvas.clientHeight);
|
||||
const oldDistance = camera.screenToWorld(new Vector3(x, y), canvas.clientWidth, canvas.clientHeight);
|
||||
camera.zoom = newZoom;
|
||||
camera.update();
|
||||
let newDistance = camera.screenToWorld(new Vector3(x, y), canvas.clientWidth, canvas.clientHeight);
|
||||
const newDistance = camera.screenToWorld(new Vector3(x, y), canvas.clientWidth, canvas.clientHeight);
|
||||
camera.position.add(oldDistance.sub(newDistance));
|
||||
camera.update();
|
||||
}
|
||||
},
|
||||
zoom: (initialDistance, distance) => {
|
||||
let newZoom = initialDistance / distance;
|
||||
const newZoom = initialDistance / distance;
|
||||
camera.zoom = initialZoom * newZoom;
|
||||
},
|
||||
up: (x: number, y: number) => {
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Texture, Disposable, Restorable, TextureFilter, TextureWrap } from "@esotericsoftware/spine-core";
|
||||
import { type Disposable, type Restorable, Texture, TextureFilter, type TextureWrap } from "@esotericsoftware/spine-core";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL.js";
|
||||
|
||||
export class GLTexture extends Texture implements Disposable, Restorable {
|
||||
@ -47,7 +47,7 @@ export class GLTexture extends Texture implements Disposable, Restorable {
|
||||
}
|
||||
|
||||
setFilters (minFilter: TextureFilter, magFilter: TextureFilter) {
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
this.bind();
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, GLTexture.validateMagFilter(magFilter));
|
||||
@ -80,14 +80,14 @@ export class GLTexture extends Texture implements Disposable, Restorable {
|
||||
}
|
||||
|
||||
setWraps (uWrap: TextureWrap, vWrap: TextureWrap) {
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
this.bind();
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, uWrap);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, vWrap);
|
||||
}
|
||||
|
||||
update (useMipMaps: boolean) {
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
if (!this.texture) this.texture = this.context.gl.createTexture();
|
||||
this.bind();
|
||||
if (GLTexture.DISABLE_UNPACK_PREMULTIPLIED_ALPHA_WEBGL) gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
||||
@ -105,21 +105,21 @@ export class GLTexture extends Texture implements Disposable, Restorable {
|
||||
}
|
||||
|
||||
bind (unit: number = 0) {
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
this.boundUnit = unit;
|
||||
gl.activeTexture(gl.TEXTURE0 + unit);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
||||
}
|
||||
|
||||
unbind () {
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
gl.activeTexture(gl.TEXTURE0 + this.boundUnit);
|
||||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
}
|
||||
|
||||
dispose () {
|
||||
this.context.removeRestorable(this);
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
gl.deleteTexture(this.texture);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Disposable } from "./index.js"
|
||||
import type { Disposable } from "./index.js"
|
||||
export class Input implements Disposable {
|
||||
element: HTMLElement;
|
||||
mouseX = 0;
|
||||
@ -36,7 +36,7 @@ export class Input implements Disposable {
|
||||
touch0: Touch | null = null;
|
||||
touch1: Touch | null = null;
|
||||
initialPinchDistance = 0;
|
||||
private listeners = new Array<InputListener>();
|
||||
private listeners = [] as InputListener[];
|
||||
private autoPreventDefault: boolean;
|
||||
|
||||
// this is needed because browsers sends mousedown-mousemove-mousesup after a touch sequence, unless touch end preventDefault
|
||||
@ -62,7 +62,7 @@ export class Input implements Disposable {
|
||||
private setupCallbacks (element: HTMLElement) {
|
||||
const mouseDown = (ev: UIEvent) => {
|
||||
if (ev instanceof MouseEvent && !this.isTouch) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
const rect = element.getBoundingClientRect();
|
||||
this.mouseX = ev.clientX - rect.left;
|
||||
this.mouseY = ev.clientY - rect.top;
|
||||
this.buttonDown = true;
|
||||
@ -72,7 +72,7 @@ export class Input implements Disposable {
|
||||
|
||||
const mouseMove = (ev: UIEvent) => {
|
||||
if (ev instanceof MouseEvent && !this.isTouch) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
const rect = element.getBoundingClientRect();
|
||||
this.mouseX = ev.clientX - rect.left;
|
||||
this.mouseY = ev.clientY - rect.top;
|
||||
|
||||
@ -88,7 +88,7 @@ export class Input implements Disposable {
|
||||
|
||||
const mouseUp = (ev: UIEvent) => {
|
||||
if (ev instanceof MouseEvent && !this.isTouch) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
const rect = element.getBoundingClientRect();
|
||||
this.mouseX = ev.clientX - rect.left;;
|
||||
this.mouseY = ev.clientY - rect.top;
|
||||
this.buttonDown = false;
|
||||
@ -99,21 +99,21 @@ export class Input implements Disposable {
|
||||
const mouseWheel = (ev: WheelEvent) => {
|
||||
if (this.autoPreventDefault) ev.preventDefault();
|
||||
let deltaY = ev.deltaY;
|
||||
if (ev.deltaMode == WheelEvent.DOM_DELTA_LINE) deltaY *= 8;
|
||||
if (ev.deltaMode == WheelEvent.DOM_DELTA_PAGE) deltaY *= 24;
|
||||
this.listeners.map((listener) => { if (listener.wheel) listener.wheel(ev.deltaY, ev); });
|
||||
if (ev.deltaMode === WheelEvent.DOM_DELTA_LINE) deltaY *= 8;
|
||||
if (ev.deltaMode === WheelEvent.DOM_DELTA_PAGE) deltaY *= 24;
|
||||
this.listeners.map((listener) => { if (listener.wheel) listener.wheel(deltaY, ev); });
|
||||
};
|
||||
|
||||
const touchStart = (ev: TouchEvent) => {
|
||||
this.isTouch = true;
|
||||
if (!this.touch0 || !this.touch1) {
|
||||
var touches = ev.changedTouches;
|
||||
let nativeTouch = touches.item(0);
|
||||
const touches = ev.changedTouches;
|
||||
const nativeTouch = touches.item(0);
|
||||
if (!nativeTouch) return;
|
||||
let rect = element.getBoundingClientRect();
|
||||
let x = nativeTouch.clientX - rect.left;
|
||||
let y = nativeTouch.clientY - rect.top;
|
||||
let touch = new Touch(nativeTouch.identifier, x, y);
|
||||
const rect = element.getBoundingClientRect();
|
||||
const x = nativeTouch.clientX - rect.left;
|
||||
const y = nativeTouch.clientY - rect.top;
|
||||
const touch = new Touch(nativeTouch.identifier, x, y);
|
||||
this.mouseX = x;
|
||||
this.mouseY = y;
|
||||
this.buttonDown = true;
|
||||
@ -123,8 +123,8 @@ export class Input implements Disposable {
|
||||
this.listeners.map((listener) => { if (listener.down) listener.down(touch.x, touch.y, ev) })
|
||||
} else if (!this.touch1) {
|
||||
this.touch1 = touch;
|
||||
let dx = this.touch1.x - this.touch0.x;
|
||||
let dy = this.touch1.x - this.touch0.x;
|
||||
const dx = this.touch1.x - this.touch0.x;
|
||||
const dy = this.touch1.x - this.touch0.x;
|
||||
this.initialPinchDistance = Math.sqrt(dx * dx + dy * dy);
|
||||
this.listeners.map((listener) => { if (listener.zoom) listener.zoom(this.initialPinchDistance, this.initialPinchDistance, ev) });
|
||||
}
|
||||
@ -135,12 +135,12 @@ export class Input implements Disposable {
|
||||
const touchMove = (ev: TouchEvent) => {
|
||||
this.isTouch = true;
|
||||
if (this.touch0) {
|
||||
var touches = ev.changedTouches;
|
||||
let rect = element.getBoundingClientRect();
|
||||
for (var i = 0; i < touches.length; i++) {
|
||||
var nativeTouch = touches[i];
|
||||
let x = nativeTouch.clientX - rect.left;
|
||||
let y = nativeTouch.clientY - rect.top;
|
||||
const touches = ev.changedTouches;
|
||||
const rect = element.getBoundingClientRect();
|
||||
for (let i = 0; i < touches.length; i++) {
|
||||
const nativeTouch = touches[i];
|
||||
const x = nativeTouch.clientX - rect.left;
|
||||
const y = nativeTouch.clientY - rect.top;
|
||||
|
||||
if (this.touch0.identifier === nativeTouch.identifier) {
|
||||
this.touch0.x = this.mouseX = x;
|
||||
@ -153,9 +153,9 @@ export class Input implements Disposable {
|
||||
}
|
||||
}
|
||||
if (this.touch0 && this.touch1) {
|
||||
let dx = this.touch1.x - this.touch0.x;
|
||||
let dy = this.touch1.x - this.touch0.x;
|
||||
let distance = Math.sqrt(dx * dx + dy * dy);
|
||||
const dx = this.touch1.x - this.touch0.x;
|
||||
const dy = this.touch1.x - this.touch0.x;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
this.listeners.map((listener) => { if (listener.zoom) listener.zoom(this.initialPinchDistance, distance, ev) });
|
||||
}
|
||||
}
|
||||
@ -164,16 +164,17 @@ export class Input implements Disposable {
|
||||
|
||||
const touchEnd = (ev: TouchEvent) => {
|
||||
this.isTouch = true;
|
||||
if (this.touch0) {
|
||||
var touches = ev.changedTouches;
|
||||
let rect = element.getBoundingClientRect();
|
||||
const touch0 = this.touch0 as Touch;
|
||||
if (touch0) {
|
||||
const touches = ev.changedTouches;
|
||||
const rect = element.getBoundingClientRect();
|
||||
|
||||
for (var i = 0; i < touches.length; i++) {
|
||||
var nativeTouch = touches[i];
|
||||
let x = nativeTouch.clientX - rect.left;
|
||||
let y = nativeTouch.clientY - rect.top;
|
||||
for (let i = 0; i < touches.length; i++) {
|
||||
const nativeTouch = touches[i];
|
||||
const x = nativeTouch.clientX - rect.left;
|
||||
const y = nativeTouch.clientY - rect.top;
|
||||
|
||||
if (this.touch0.identifier === nativeTouch.identifier) {
|
||||
if (touch0.identifier === nativeTouch.identifier) {
|
||||
this.touch0 = null;
|
||||
this.mouseX = x;
|
||||
this.mouseY = y;
|
||||
@ -183,16 +184,16 @@ export class Input implements Disposable {
|
||||
this.buttonDown = false;
|
||||
break;
|
||||
} else {
|
||||
this.touch0 = this.touch1;
|
||||
const touch0 = this.touch0 = this.touch1;
|
||||
this.touch1 = null;
|
||||
this.mouseX = this.touch0.x;
|
||||
this.mouseX = this.touch0.x;
|
||||
this.mouseX = touch0.x;
|
||||
this.mouseY = touch0.y;
|
||||
this.buttonDown = true;
|
||||
this.listeners.map((listener) => { if (listener.down) listener.down(this.touch0!.x, this.touch0!.y, ev) });
|
||||
this.listeners.map((listener) => { if (listener.down) listener.down(touch0.x, touch0.y, ev) });
|
||||
}
|
||||
}
|
||||
|
||||
if (this.touch1 && this.touch1.identifier) {
|
||||
if (this.touch1?.identifier) {
|
||||
this.touch1 = null;
|
||||
}
|
||||
}
|
||||
@ -238,7 +239,7 @@ export class Input implements Disposable {
|
||||
}
|
||||
|
||||
removeListener (listener: InputListener) {
|
||||
let idx = this.listeners.indexOf(listener);
|
||||
const idx = this.listeners.indexOf(listener);
|
||||
if (idx > -1) {
|
||||
this.listeners.splice(idx, 1);
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -56,7 +56,7 @@ export class Matrix4 {
|
||||
private static tmpMatrix = new Matrix4();
|
||||
|
||||
constructor () {
|
||||
let v = this.values;
|
||||
const v = this.values;
|
||||
v[M00] = 1;
|
||||
v[M11] = 1;
|
||||
v[M22] = 1;
|
||||
@ -69,8 +69,8 @@ export class Matrix4 {
|
||||
}
|
||||
|
||||
transpose (): Matrix4 {
|
||||
let t = this.temp;
|
||||
let v = this.values;
|
||||
const t = this.temp;
|
||||
const v = this.values;
|
||||
t[M00] = v[M00];
|
||||
t[M01] = v[M10];
|
||||
t[M02] = v[M20];
|
||||
@ -91,7 +91,7 @@ export class Matrix4 {
|
||||
}
|
||||
|
||||
identity (): Matrix4 {
|
||||
let v = this.values;
|
||||
const v = this.values;
|
||||
v[M00] = 1;
|
||||
v[M01] = 0;
|
||||
v[M02] = 0;
|
||||
@ -112,9 +112,9 @@ export class Matrix4 {
|
||||
}
|
||||
|
||||
invert (): Matrix4 {
|
||||
let v = this.values;
|
||||
let t = this.temp;
|
||||
let l_det = v[M30] * v[M21] * v[M12] * v[M03] - v[M20] * v[M31] * v[M12] * v[M03] - v[M30] * v[M11] * v[M22] * v[M03]
|
||||
const v = this.values;
|
||||
const t = this.temp;
|
||||
const l_det = v[M30] * v[M21] * v[M12] * v[M03] - v[M20] * v[M31] * v[M12] * v[M03] - v[M30] * v[M11] * v[M22] * v[M03]
|
||||
+ v[M10] * v[M31] * v[M22] * v[M03] + v[M20] * v[M11] * v[M32] * v[M03] - v[M10] * v[M21] * v[M32] * v[M03]
|
||||
- v[M30] * v[M21] * v[M02] * v[M13] + v[M20] * v[M31] * v[M02] * v[M13] + v[M30] * v[M01] * v[M22] * v[M13]
|
||||
- v[M00] * v[M31] * v[M22] * v[M13] - v[M20] * v[M01] * v[M32] * v[M13] + v[M00] * v[M21] * v[M32] * v[M13]
|
||||
@ -122,8 +122,8 @@ export class Matrix4 {
|
||||
+ v[M00] * v[M31] * v[M12] * v[M23] + v[M10] * v[M01] * v[M32] * v[M23] - v[M00] * v[M11] * v[M32] * v[M23]
|
||||
- v[M20] * v[M11] * v[M02] * v[M33] + v[M10] * v[M21] * v[M02] * v[M33] + v[M20] * v[M01] * v[M12] * v[M33]
|
||||
- v[M00] * v[M21] * v[M12] * v[M33] - v[M10] * v[M01] * v[M22] * v[M33] + v[M00] * v[M11] * v[M22] * v[M33];
|
||||
if (l_det == 0) throw new Error("non-invertible matrix");
|
||||
let inv_det = 1.0 / l_det;
|
||||
if (l_det === 0) throw new Error("non-invertible matrix");
|
||||
const inv_det = 1.0 / l_det;
|
||||
t[M00] = v[M12] * v[M23] * v[M31] - v[M13] * v[M22] * v[M31] + v[M13] * v[M21] * v[M32]
|
||||
- v[M11] * v[M23] * v[M32] - v[M12] * v[M21] * v[M33] + v[M11] * v[M22] * v[M33];
|
||||
t[M01] = v[M03] * v[M22] * v[M31] - v[M02] * v[M23] * v[M31] - v[M03] * v[M21] * v[M32]
|
||||
@ -176,7 +176,7 @@ export class Matrix4 {
|
||||
}
|
||||
|
||||
determinant (): number {
|
||||
let v = this.values;
|
||||
const v = this.values;
|
||||
return v[M30] * v[M21] * v[M12] * v[M03] - v[M20] * v[M31] * v[M12] * v[M03] - v[M30] * v[M11] * v[M22] * v[M03]
|
||||
+ v[M10] * v[M31] * v[M22] * v[M03] + v[M20] * v[M11] * v[M32] * v[M03] - v[M10] * v[M21] * v[M32] * v[M03]
|
||||
- v[M30] * v[M21] * v[M02] * v[M13] + v[M20] * v[M31] * v[M02] * v[M13] + v[M30] * v[M01] * v[M22] * v[M13]
|
||||
@ -188,7 +188,7 @@ export class Matrix4 {
|
||||
}
|
||||
|
||||
translate (x: number, y: number, z: number): Matrix4 {
|
||||
let v = this.values;
|
||||
const v = this.values;
|
||||
v[M03] += x;
|
||||
v[M13] += y;
|
||||
v[M23] += z;
|
||||
@ -201,10 +201,10 @@ export class Matrix4 {
|
||||
|
||||
projection (near: number, far: number, fovy: number, aspectRatio: number): Matrix4 {
|
||||
this.identity();
|
||||
let l_fd = (1.0 / Math.tan((fovy * (Math.PI / 180)) / 2.0));
|
||||
let l_a1 = (far + near) / (near - far);
|
||||
let l_a2 = (2 * far * near) / (near - far);
|
||||
let v = this.values;
|
||||
const l_fd = (1.0 / Math.tan((fovy * (Math.PI / 180)) / 2.0));
|
||||
const l_a1 = (far + near) / (near - far);
|
||||
const l_a2 = (2 * far * near) / (near - far);
|
||||
const v = this.values;
|
||||
v[M00] = l_fd / aspectRatio;
|
||||
v[M10] = 0;
|
||||
v[M20] = 0;
|
||||
@ -230,15 +230,15 @@ export class Matrix4 {
|
||||
|
||||
ortho (left: number, right: number, bottom: number, top: number, near: number, far: number): Matrix4 {
|
||||
this.identity();
|
||||
let x_orth = 2 / (right - left);
|
||||
let y_orth = 2 / (top - bottom);
|
||||
let z_orth = -2 / (far - near);
|
||||
const x_orth = 2 / (right - left);
|
||||
const y_orth = 2 / (top - bottom);
|
||||
const z_orth = -2 / (far - near);
|
||||
|
||||
let tx = -(right + left) / (right - left);
|
||||
let ty = -(top + bottom) / (top - bottom);
|
||||
let tz = -(far + near) / (far - near);
|
||||
const tx = -(right + left) / (right - left);
|
||||
const ty = -(top + bottom) / (top - bottom);
|
||||
const tz = -(far + near) / (far - near);
|
||||
|
||||
let v = this.values;
|
||||
const v = this.values;
|
||||
v[M00] = x_orth;
|
||||
v[M10] = 0;
|
||||
v[M20] = 0;
|
||||
@ -259,9 +259,9 @@ export class Matrix4 {
|
||||
}
|
||||
|
||||
multiply (matrix: Matrix4): Matrix4 {
|
||||
let t = this.temp;
|
||||
let v = this.values;
|
||||
let m = matrix.values;
|
||||
const t = this.temp;
|
||||
const v = this.values;
|
||||
const m = matrix.values;
|
||||
t[M00] = v[M00] * m[M00] + v[M01] * m[M10] + v[M02] * m[M20] + v[M03] * m[M30];
|
||||
t[M01] = v[M00] * m[M01] + v[M01] * m[M11] + v[M02] * m[M21] + v[M03] * m[M31];
|
||||
t[M02] = v[M00] * m[M02] + v[M01] * m[M12] + v[M02] * m[M22] + v[M03] * m[M32];
|
||||
@ -282,9 +282,9 @@ export class Matrix4 {
|
||||
}
|
||||
|
||||
multiplyLeft (matrix: Matrix4): Matrix4 {
|
||||
let t = this.temp;
|
||||
let v = this.values;
|
||||
let m = matrix.values;
|
||||
const t = this.temp;
|
||||
const v = this.values;
|
||||
const m = matrix.values;
|
||||
t[M00] = m[M00] * v[M00] + m[M01] * v[M10] + m[M02] * v[M20] + m[M03] * v[M30];
|
||||
t[M01] = m[M00] * v[M01] + m[M01] * v[M11] + m[M02] * v[M21] + m[M03] * v[M31];
|
||||
t[M02] = m[M00] * v[M02] + m[M01] * v[M12] + m[M02] * v[M22] + m[M03] * v[M32];
|
||||
@ -305,13 +305,13 @@ export class Matrix4 {
|
||||
}
|
||||
|
||||
lookAt (position: Vector3, direction: Vector3, up: Vector3) {
|
||||
let xAxis = Matrix4.xAxis, yAxis = Matrix4.yAxis, zAxis = Matrix4.zAxis;
|
||||
const xAxis = Matrix4.xAxis, yAxis = Matrix4.yAxis, zAxis = Matrix4.zAxis;
|
||||
zAxis.setFrom(direction).normalize();
|
||||
xAxis.setFrom(direction).normalize();
|
||||
xAxis.cross(up).normalize();
|
||||
yAxis.setFrom(xAxis).cross(zAxis).normalize();
|
||||
this.identity();
|
||||
let val = this.values;
|
||||
const val = this.values;
|
||||
val[M00] = xAxis.x;
|
||||
val[M01] = xAxis.y;
|
||||
val[M02] = xAxis.z;
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Disposable, Restorable } from "@esotericsoftware/spine-core";
|
||||
import type { Disposable, Restorable } from "@esotericsoftware/spine-core";
|
||||
import { Shader } from "./Shader.js";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL.js";
|
||||
|
||||
@ -64,8 +64,8 @@ export class Mesh implements Disposable, Restorable {
|
||||
|
||||
getVertexSizeInFloats (): number {
|
||||
let size = 0;
|
||||
for (var i = 0; i < this.attributes.length; i++) {
|
||||
let attribute = this.attributes[i];
|
||||
for (let i = 0; i < this.attributes.length; i++) {
|
||||
const attribute = this.attributes[i];
|
||||
size += attribute.numElements;
|
||||
}
|
||||
return size;
|
||||
@ -84,14 +84,14 @@ export class Mesh implements Disposable, Restorable {
|
||||
|
||||
setVertices (vertices: Array<number>) {
|
||||
this.dirtyVertices = true;
|
||||
if (vertices.length > this.vertices.length) throw Error("Mesh can't store more than " + this.maxVertices() + " vertices");
|
||||
if (vertices.length > this.vertices.length) throw Error(`Mesh can't store more than ${this.maxVertices()} vertices`);
|
||||
this.vertices.set(vertices, 0);
|
||||
this.verticesLength = vertices.length;
|
||||
}
|
||||
|
||||
setIndices (indices: Array<number>) {
|
||||
this.dirtyIndices = true;
|
||||
if (indices.length > this.indices.length) throw Error("Mesh can't store more than " + this.maxIndices() + " indices");
|
||||
if (indices.length > this.indices.length) throw Error(`Mesh can't store more than ${this.maxIndices()} indices`);
|
||||
this.indices.set(indices, 0);
|
||||
this.indicesLength = indices.length;
|
||||
}
|
||||
@ -101,7 +101,7 @@ export class Mesh implements Disposable, Restorable {
|
||||
}
|
||||
|
||||
drawWithOffset (shader: Shader, primitiveType: number, offset: number, count: number) {
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
if (this.dirtyVertices || this.dirtyIndices) this.update();
|
||||
this.bind(shader);
|
||||
if (this.indicesLength > 0) {
|
||||
@ -113,12 +113,12 @@ export class Mesh implements Disposable, Restorable {
|
||||
}
|
||||
|
||||
bind (shader: Shader) {
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.verticesBuffer);
|
||||
let offset = 0;
|
||||
for (let i = 0; i < this.attributes.length; i++) {
|
||||
let attrib = this.attributes[i];
|
||||
let location = shader.getAttributeLocation(attrib.name);
|
||||
const attrib = this.attributes[i];
|
||||
const location = shader.getAttributeLocation(attrib.name);
|
||||
gl.enableVertexAttribArray(location);
|
||||
gl.vertexAttribPointer(location, attrib.numElements, gl.FLOAT, false, this.elementsPerVertex * 4, offset * 4);
|
||||
offset += attrib.numElements;
|
||||
@ -127,10 +127,10 @@ export class Mesh implements Disposable, Restorable {
|
||||
}
|
||||
|
||||
unbind (shader: Shader) {
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
for (let i = 0; i < this.attributes.length; i++) {
|
||||
let attrib = this.attributes[i];
|
||||
let location = shader.getAttributeLocation(attrib.name);
|
||||
const attrib = this.attributes[i];
|
||||
const location = shader.getAttributeLocation(attrib.name);
|
||||
gl.disableVertexAttribArray(location);
|
||||
}
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||
@ -138,7 +138,7 @@ export class Mesh implements Disposable, Restorable {
|
||||
}
|
||||
|
||||
private update () {
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
if (this.dirtyVertices) {
|
||||
if (!this.verticesBuffer) {
|
||||
this.verticesBuffer = gl.createBuffer();
|
||||
@ -166,7 +166,7 @@ export class Mesh implements Disposable, Restorable {
|
||||
|
||||
dispose () {
|
||||
this.context.removeRestorable(this);
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
gl.deleteBuffer(this.verticesBuffer);
|
||||
gl.deleteBuffer(this.indicesBuffer);
|
||||
}
|
||||
@ -190,7 +190,7 @@ export class Position3Attribute extends VertexAttribute {
|
||||
|
||||
export class TexCoordAttribute extends VertexAttribute {
|
||||
constructor (unit: number = 0) {
|
||||
super(Shader.TEXCOORDS + (unit == 0 ? "" : unit), VertexAttributeType.Float, 2);
|
||||
super(Shader.TEXCOORDS + (unit === 0 ? "" : unit), VertexAttributeType.Float, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -27,16 +27,17 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { BlendMode, Disposable } from "@esotericsoftware/spine-core";
|
||||
import { GLTexture } from "./GLTexture.js";
|
||||
import { Mesh, Position2Attribute, ColorAttribute, TexCoordAttribute, Color2Attribute } from "./Mesh.js";
|
||||
import { Shader } from "./Shader.js";
|
||||
import type { BlendMode, Disposable } from "@esotericsoftware/spine-core";
|
||||
import type { GLTexture } from "./GLTexture.js";
|
||||
import { Color2Attribute, ColorAttribute, Mesh, Position2Attribute, TexCoordAttribute } from "./Mesh.js";
|
||||
import type { Shader } from "./Shader.js";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL.js";
|
||||
|
||||
const GL_ONE = 1;
|
||||
const GL_ONE_MINUS_SRC_COLOR = 0x0301;
|
||||
const GL_SRC_ALPHA = 0x0302;
|
||||
const GL_ONE_MINUS_SRC_ALPHA = 0x0303;
|
||||
// biome-ignore lint/correctness/noUnusedVariables: intentional
|
||||
const GL_ONE_MINUS_DST_ALPHA = 0x0305;
|
||||
const GL_DST_COLOR = 0x0306;
|
||||
|
||||
@ -58,13 +59,13 @@ export class PolygonBatcher implements Disposable {
|
||||
private cullWasEnabled = false;
|
||||
|
||||
constructor (context: ManagedWebGLRenderingContext | WebGLRenderingContext, twoColorTint: boolean = true, maxVertices: number = 10920) {
|
||||
if (maxVertices > 10920) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices);
|
||||
if (maxVertices > 10920) throw new Error(`Can't have more than 10920 triangles per batch: ${maxVertices}`);
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
let attributes = twoColorTint ?
|
||||
const attributes = twoColorTint ?
|
||||
[new Position2Attribute(), new ColorAttribute(), new TexCoordAttribute(), new Color2Attribute()] :
|
||||
[new Position2Attribute(), new ColorAttribute(), new TexCoordAttribute()];
|
||||
this.mesh = new Mesh(context, attributes, maxVertices, maxVertices * 3);
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
this.srcColorBlend = gl.SRC_ALPHA;
|
||||
this.srcAlphaBlend = gl.ONE;
|
||||
this.dstBlend = gl.ONE_MINUS_SRC_ALPHA;
|
||||
@ -77,7 +78,7 @@ export class PolygonBatcher implements Disposable {
|
||||
this.lastTexture = null;
|
||||
this.isDrawing = true;
|
||||
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendFuncSeparate(this.srcColorBlend, this.dstBlend, this.srcAlphaBlend, this.dstBlend);
|
||||
|
||||
@ -100,19 +101,19 @@ export class PolygonBatcher implements Disposable {
|
||||
const srcAlphaBlend = blendModeGL.srcAlpha;
|
||||
const dstBlend = blendModeGL.dstRgb;
|
||||
|
||||
if (this.srcColorBlend == srcColorBlend && this.srcAlphaBlend == srcAlphaBlend && this.dstBlend == dstBlend) return;
|
||||
if (this.srcColorBlend === srcColorBlend && this.srcAlphaBlend === srcAlphaBlend && this.dstBlend === dstBlend) return;
|
||||
this.srcColorBlend = srcColorBlend;
|
||||
this.srcAlphaBlend = srcAlphaBlend;
|
||||
this.dstBlend = dstBlend;
|
||||
if (this.isDrawing) {
|
||||
this.flush();
|
||||
}
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
gl.blendFuncSeparate(srcColorBlend, dstBlend, srcAlphaBlend, dstBlend);
|
||||
}
|
||||
|
||||
draw (texture: GLTexture, vertices: ArrayLike<number>, indices: Array<number>) {
|
||||
if (texture != this.lastTexture) {
|
||||
if (texture !== this.lastTexture) {
|
||||
this.flush();
|
||||
this.lastTexture = texture;
|
||||
} else if (this.verticesLength + vertices.length > this.mesh.getVertices().length ||
|
||||
@ -120,12 +121,12 @@ export class PolygonBatcher implements Disposable {
|
||||
this.flush();
|
||||
}
|
||||
|
||||
let indexStart = this.mesh.numVertices();
|
||||
const indexStart = this.mesh.numVertices();
|
||||
this.mesh.getVertices().set(vertices, this.verticesLength);
|
||||
this.verticesLength += vertices.length;
|
||||
this.mesh.setVerticesLength(this.verticesLength)
|
||||
|
||||
let indicesArray = this.mesh.getIndices();
|
||||
const indicesArray = this.mesh.getIndices();
|
||||
for (let i = this.indicesLength, j = 0; j < indices.length; i++, j++)
|
||||
indicesArray[i] = indices[j] + indexStart;
|
||||
this.indicesLength += indices.length;
|
||||
@ -133,7 +134,7 @@ export class PolygonBatcher implements Disposable {
|
||||
}
|
||||
|
||||
flush () {
|
||||
if (this.verticesLength == 0) return;
|
||||
if (this.verticesLength === 0) return;
|
||||
if (!this.lastTexture) throw new Error("No texture set.");
|
||||
if (!this.shader) throw new Error("No shader set.");
|
||||
this.lastTexture.bind();
|
||||
@ -154,7 +155,7 @@ export class PolygonBatcher implements Disposable {
|
||||
this.lastTexture = null;
|
||||
this.isDrawing = false;
|
||||
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
gl.disable(gl.BLEND);
|
||||
if (PolygonBatcher.disableCulling) {
|
||||
if (this.cullWasEnabled) gl.enable(gl.CULL_FACE);
|
||||
@ -166,7 +167,7 @@ export class PolygonBatcher implements Disposable {
|
||||
}
|
||||
|
||||
static getAndResetGlobalDrawCalls () {
|
||||
let result = PolygonBatcher.globalDrawCalls;
|
||||
const result = PolygonBatcher.globalDrawCalls;
|
||||
PolygonBatcher.globalDrawCalls = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -27,15 +27,16 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Color, Disposable, Skeleton, MathUtils, TextureAtlasRegion } from "@esotericsoftware/spine-core";
|
||||
import { Color, type Disposable, MathUtils, type Skeleton, type TextureAtlasRegion } from "@esotericsoftware/spine-core";
|
||||
import { OrthoCamera } from "./Camera.js";
|
||||
import { GLTexture } from "./GLTexture.js";
|
||||
import type { GLTexture } from "./GLTexture.js";
|
||||
import { PolygonBatcher } from "./PolygonBatcher.js";
|
||||
import { Shader } from "./Shader.js";
|
||||
import { ShapeRenderer } from "./ShapeRenderer.js";
|
||||
import { SkeletonDebugRenderer } from "./SkeletonDebugRenderer.js";
|
||||
import { SkeletonRenderer, VertexTransformer } from "./SkeletonRenderer.js";
|
||||
import { SkeletonRenderer, type VertexTransformer } from "./SkeletonRenderer.js";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL.js";
|
||||
|
||||
;
|
||||
|
||||
const quad = [
|
||||
@ -229,22 +230,22 @@ export class SceneRenderer implements Disposable {
|
||||
if (!color) color = WHITE;
|
||||
|
||||
// bottom left and top right corner points relative to origin
|
||||
let worldOriginX = x + pivotX;
|
||||
let worldOriginY = y + pivotY;
|
||||
let fx = -pivotX;
|
||||
let fy = -pivotY;
|
||||
let fx2 = width - pivotX;
|
||||
let fy2 = height - pivotY;
|
||||
const worldOriginX = x + pivotX;
|
||||
const worldOriginY = y + pivotY;
|
||||
const fx = -pivotX;
|
||||
const fy = -pivotY;
|
||||
const fx2 = width - pivotX;
|
||||
const fy2 = height - pivotY;
|
||||
|
||||
// construct corner points, start from top left and go counter clockwise
|
||||
let p1x = fx;
|
||||
let p1y = fy;
|
||||
let p2x = fx;
|
||||
let p2y = fy2;
|
||||
let p3x = fx2;
|
||||
let p3y = fy2;
|
||||
let p4x = fx2;
|
||||
let p4y = fy;
|
||||
const p1x = fx;
|
||||
const p1y = fy;
|
||||
const p2x = fx;
|
||||
const p2y = fy2;
|
||||
const p3x = fx2;
|
||||
const p3y = fy2;
|
||||
const p4x = fx2;
|
||||
const p4y = fy;
|
||||
|
||||
let x1 = 0;
|
||||
let y1 = 0;
|
||||
@ -256,9 +257,9 @@ export class SceneRenderer implements Disposable {
|
||||
let y4 = 0;
|
||||
|
||||
// rotate
|
||||
if (angle != 0) {
|
||||
let cos = MathUtils.cosDeg(angle);
|
||||
let sin = MathUtils.sinDeg(angle);
|
||||
if (angle !== 0) {
|
||||
const cos = MathUtils.cosDeg(angle);
|
||||
const sin = MathUtils.sinDeg(angle);
|
||||
|
||||
x1 = cos * p1x - sin * p1y;
|
||||
y1 = sin * p1x + cos * p1y;
|
||||
@ -464,27 +465,27 @@ export class SceneRenderer implements Disposable {
|
||||
}
|
||||
|
||||
resize (resizeMode: ResizeMode, worldWidth?: number, worldHeight?: number) {
|
||||
let canvas = this.canvas;
|
||||
const canvas = this.canvas;
|
||||
var dpr = window.devicePixelRatio || 1;
|
||||
var w = Math.round(canvas.clientWidth * dpr);
|
||||
var h = Math.round(canvas.clientHeight * dpr);
|
||||
if (canvas.width != w || canvas.height != h) {
|
||||
if (canvas.width !== w || canvas.height !== h) {
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
}
|
||||
|
||||
if (resizeMode === ResizeMode.FitClip && worldWidth !== undefined && worldHeight !== undefined) {
|
||||
let targetRatio = h / w, sourceRatio = worldHeight / worldWidth;
|
||||
let scale = targetRatio > sourceRatio ? w / worldWidth : h / worldHeight;
|
||||
const targetRatio = h / w, sourceRatio = worldHeight / worldWidth;
|
||||
const scale = targetRatio > sourceRatio ? w / worldWidth : h / worldHeight;
|
||||
worldWidth *= scale;
|
||||
worldHeight *= scale;
|
||||
this.camera.setViewport(worldWidth, worldHeight);
|
||||
this.context.gl.viewport((w - worldWidth) / 2, (h - worldHeight) / 2, worldWidth, worldHeight);
|
||||
} else {
|
||||
if (resizeMode === ResizeMode.Fit) {
|
||||
let targetWidth = this.camera.viewportWidth, targetHeight = this.camera.viewportHeight;
|
||||
let targetRatio = targetHeight / targetWidth, sourceRatio = h / w;
|
||||
let scale = targetRatio < sourceRatio ? targetWidth / w : targetHeight / h;
|
||||
const targetWidth = this.camera.viewportWidth, targetHeight = this.camera.viewportHeight;
|
||||
const targetRatio = targetHeight / targetWidth, sourceRatio = h / w;
|
||||
const scale = targetRatio < sourceRatio ? targetWidth / w : targetHeight / h;
|
||||
this.camera.setViewport(w * scale, h * scale);
|
||||
} else if (resizeMode === ResizeMode.Expand)
|
||||
this.camera.setViewport(w, h);
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Disposable, Restorable } from "@esotericsoftware/spine-core";
|
||||
import type { Disposable, Restorable } from "@esotericsoftware/spine-core";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL.js";
|
||||
|
||||
export class Shader implements Disposable, Restorable {
|
||||
@ -63,7 +63,7 @@ export class Shader implements Disposable, Restorable {
|
||||
}
|
||||
|
||||
private compile () {
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
try {
|
||||
this.vs = this.compileShader(gl.VERTEX_SHADER, this.vertexShader);
|
||||
if (!this.vs) throw new Error("Couldn't compile vertex shader.");
|
||||
@ -77,13 +77,13 @@ export class Shader implements Disposable, Restorable {
|
||||
}
|
||||
|
||||
private compileShader (type: number, source: string) {
|
||||
let gl = this.context.gl;
|
||||
let shader = gl.createShader(type);
|
||||
const gl = this.context.gl;
|
||||
const shader = gl.createShader(type);
|
||||
if (!shader) throw new Error("Couldn't create shader.");
|
||||
gl.shaderSource(shader, source);
|
||||
gl.compileShader(shader);
|
||||
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
||||
let error = "Couldn't compile shader: " + gl.getShaderInfoLog(shader);
|
||||
const error = `Couldn't compile shader: ${gl.getShaderInfoLog(shader)}`;
|
||||
gl.deleteShader(shader);
|
||||
if (!gl.isContextLost()) throw new Error(error);
|
||||
}
|
||||
@ -91,15 +91,15 @@ export class Shader implements Disposable, Restorable {
|
||||
}
|
||||
|
||||
private compileProgram (vs: WebGLShader, fs: WebGLShader) {
|
||||
let gl = this.context.gl;
|
||||
let program = gl.createProgram();
|
||||
const gl = this.context.gl;
|
||||
const program = gl.createProgram();
|
||||
if (!program) throw new Error("Couldn't compile program.");
|
||||
gl.attachShader(program, vs);
|
||||
gl.attachShader(program, fs);
|
||||
gl.linkProgram(program);
|
||||
|
||||
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
||||
let error = "Couldn't compile shader program: " + gl.getProgramInfoLog(program);
|
||||
const error = `Couldn't compile shader program: ${gl.getProgramInfoLog(program)}`;
|
||||
gl.deleteProgram(program);
|
||||
if (!gl.isContextLost()) throw new Error(error);
|
||||
}
|
||||
@ -139,43 +139,43 @@ export class Shader implements Disposable, Restorable {
|
||||
}
|
||||
|
||||
public setUniform2x2f (uniform: string, value: ArrayLike<number>) {
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
this.tmp2x2.set(value);
|
||||
gl.uniformMatrix2fv(this.getUniformLocation(uniform), false, this.tmp2x2);
|
||||
}
|
||||
|
||||
public setUniform3x3f (uniform: string, value: ArrayLike<number>) {
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
this.tmp3x3.set(value);
|
||||
gl.uniformMatrix3fv(this.getUniformLocation(uniform), false, this.tmp3x3);
|
||||
}
|
||||
|
||||
public setUniform4x4f (uniform: string, value: ArrayLike<number>) {
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
this.tmp4x4.set(value);
|
||||
gl.uniformMatrix4fv(this.getUniformLocation(uniform), false, this.tmp4x4);
|
||||
}
|
||||
|
||||
public getUniformLocation (uniform: string): WebGLUniformLocation | null {
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
if (!this.program) throw new Error("Shader not compiled.");
|
||||
let location = gl.getUniformLocation(this.program, uniform);
|
||||
const location = gl.getUniformLocation(this.program, uniform);
|
||||
if (!location && !gl.isContextLost()) throw new Error(`Couldn't find location for uniform ${uniform}`);
|
||||
return location;
|
||||
}
|
||||
|
||||
public getAttributeLocation (attribute: string): number {
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
if (!this.program) throw new Error("Shader not compiled.");
|
||||
let location = gl.getAttribLocation(this.program, attribute);
|
||||
if (location == -1 && !gl.isContextLost()) throw new Error(`Couldn't find location for attribute ${attribute}`);
|
||||
const location = gl.getAttribLocation(this.program, attribute);
|
||||
if (location === -1 && !gl.isContextLost()) throw new Error(`Couldn't find location for attribute ${attribute}`);
|
||||
return location;
|
||||
}
|
||||
|
||||
public dispose () {
|
||||
this.context.removeRestorable(this);
|
||||
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
if (this.vs) {
|
||||
gl.deleteShader(this.vs);
|
||||
this.vs = null;
|
||||
@ -193,7 +193,7 @@ export class Shader implements Disposable, Restorable {
|
||||
}
|
||||
|
||||
public static newColoredTextured (context: ManagedWebGLRenderingContext | WebGLRenderingContext): Shader {
|
||||
let vs = `
|
||||
const vs = `
|
||||
attribute vec4 ${Shader.POSITION};
|
||||
attribute vec4 ${Shader.COLOR};
|
||||
attribute vec2 ${Shader.TEXCOORDS};
|
||||
@ -208,7 +208,7 @@ void main () {
|
||||
}
|
||||
`;
|
||||
|
||||
let fs = `
|
||||
const fs = `
|
||||
#ifdef GL_ES
|
||||
#define LOWP lowp
|
||||
precision mediump float;
|
||||
@ -228,7 +228,7 @@ void main () {
|
||||
}
|
||||
|
||||
public static newTwoColoredTextured (context: ManagedWebGLRenderingContext | WebGLRenderingContext): Shader {
|
||||
let vs = `
|
||||
const vs = `
|
||||
attribute vec4 ${Shader.POSITION};
|
||||
attribute vec4 ${Shader.COLOR};
|
||||
attribute vec4 ${Shader.COLOR2};
|
||||
@ -246,7 +246,7 @@ void main () {
|
||||
}
|
||||
`;
|
||||
|
||||
let fs = `
|
||||
const fs = `
|
||||
#ifdef GL_ES
|
||||
#define LOWP lowp
|
||||
precision mediump float;
|
||||
@ -269,7 +269,7 @@ void main () {
|
||||
}
|
||||
|
||||
public static newColored (context: ManagedWebGLRenderingContext | WebGLRenderingContext): Shader {
|
||||
let vs = `
|
||||
const vs = `
|
||||
attribute vec4 ${Shader.POSITION};
|
||||
attribute vec4 ${Shader.COLOR};
|
||||
uniform mat4 ${Shader.MVP_MATRIX};
|
||||
@ -281,7 +281,7 @@ void main () {
|
||||
}
|
||||
`;
|
||||
|
||||
let fs = `
|
||||
const fs = `
|
||||
#ifdef GL_ES
|
||||
#define LOWP lowp
|
||||
precision mediump float;
|
||||
|
||||
@ -27,9 +27,9 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Disposable, Color, Vector2, MathUtils } from "@esotericsoftware/spine-core";
|
||||
import { Mesh, Position2Attribute, ColorAttribute } from "./Mesh.js";
|
||||
import { Shader } from "./Shader.js";
|
||||
import { Color, type Disposable, MathUtils, Vector2 } from "@esotericsoftware/spine-core";
|
||||
import { ColorAttribute, Mesh, Position2Attribute } from "./Mesh.js";
|
||||
import type { Shader } from "./Shader.js";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL.js";
|
||||
|
||||
export class ShapeRenderer implements Disposable {
|
||||
@ -46,10 +46,10 @@ export class ShapeRenderer implements Disposable {
|
||||
private dstBlend: number;
|
||||
|
||||
constructor (context: ManagedWebGLRenderingContext | WebGLRenderingContext, maxVertices: number = 10920) {
|
||||
if (maxVertices > 10920) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices);
|
||||
if (maxVertices > 10920) throw new Error(`Can't have more than 10920 triangles per batch: ${maxVertices}`);
|
||||
this.context = context instanceof ManagedWebGLRenderingContext ? context : new ManagedWebGLRenderingContext(context);
|
||||
this.mesh = new Mesh(context, [new Position2Attribute(), new ColorAttribute()], maxVertices, 0);
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
this.srcColorBlend = gl.SRC_ALPHA;
|
||||
this.srcAlphaBlend = gl.ONE;
|
||||
this.dstBlend = gl.ONE_MINUS_SRC_ALPHA;
|
||||
@ -61,7 +61,7 @@ export class ShapeRenderer implements Disposable {
|
||||
this.vertexIndex = 0;
|
||||
this.isDrawing = true;
|
||||
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendFuncSeparate(this.srcColorBlend, this.dstBlend, this.srcAlphaBlend, this.dstBlend);
|
||||
}
|
||||
@ -72,7 +72,7 @@ export class ShapeRenderer implements Disposable {
|
||||
this.dstBlend = dstBlend;
|
||||
if (this.isDrawing) {
|
||||
this.flush();
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
gl.blendFuncSeparate(srcColorBlend, dstBlend, srcAlphaBlend, dstBlend);
|
||||
}
|
||||
}
|
||||
@ -93,8 +93,6 @@ export class ShapeRenderer implements Disposable {
|
||||
|
||||
line (x: number, y: number, x2: number, y2: number, color?: Color) {
|
||||
this.check(ShapeType.Line, 2);
|
||||
let vertices = this.mesh.getVertices();
|
||||
let idx = this.vertexIndex;
|
||||
if (!color) color = this.color;
|
||||
this.vertex(x, y, color);
|
||||
this.vertex(x2, y2, color);
|
||||
@ -102,8 +100,6 @@ export class ShapeRenderer implements Disposable {
|
||||
|
||||
triangle (filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, color?: Color, color2?: Color, color3?: Color) {
|
||||
this.check(filled ? ShapeType.Filled : ShapeType.Line, 3);
|
||||
let vertices = this.mesh.getVertices();
|
||||
let idx = this.vertexIndex;
|
||||
if (!color) color = this.color;
|
||||
if (!color2) color2 = this.color;
|
||||
if (!color3) color3 = this.color;
|
||||
@ -125,8 +121,6 @@ export class ShapeRenderer implements Disposable {
|
||||
|
||||
quad (filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, color?: Color, color2?: Color, color3?: Color, color4?: Color) {
|
||||
this.check(filled ? ShapeType.Filled : ShapeType.Line, 3);
|
||||
let vertices = this.mesh.getVertices();
|
||||
let idx = this.vertexIndex;
|
||||
if (!color) color = this.color;
|
||||
if (!color2) color2 = this.color;
|
||||
if (!color3) color3 = this.color;
|
||||
@ -149,11 +143,11 @@ export class ShapeRenderer implements Disposable {
|
||||
rectLine (filled: boolean, x1: number, y1: number, x2: number, y2: number, width: number, color?: Color) {
|
||||
this.check(filled ? ShapeType.Filled : ShapeType.Line, 8);
|
||||
if (!color) color = this.color;
|
||||
let t = this.tmp.set(y2 - y1, x1 - x2);
|
||||
const t = this.tmp.set(y2 - y1, x1 - x2);
|
||||
t.normalize();
|
||||
width *= 0.5;
|
||||
let tx = t.x * width;
|
||||
let ty = t.y * width;
|
||||
const tx = t.x * width;
|
||||
const ty = t.y * width;
|
||||
if (!filled) {
|
||||
this.vertex(x1 + tx, y1 + ty, color);
|
||||
this.vertex(x1 - tx, y1 - ty, color);
|
||||
@ -185,19 +179,17 @@ export class ShapeRenderer implements Disposable {
|
||||
if (count < 3) throw new Error("Polygon must contain at least 3 vertices");
|
||||
this.check(ShapeType.Line, count * 2);
|
||||
if (!color) color = this.color;
|
||||
let vertices = this.mesh.getVertices();
|
||||
let idx = this.vertexIndex;
|
||||
|
||||
offset <<= 1;
|
||||
count <<= 1;
|
||||
|
||||
let firstX = polygonVertices[offset];
|
||||
let firstY = polygonVertices[offset + 1];
|
||||
let last = offset + count;
|
||||
const firstX = polygonVertices[offset];
|
||||
const firstY = polygonVertices[offset + 1];
|
||||
const last = offset + count;
|
||||
|
||||
for (let i = offset, n = offset + count - 2; i < n; i += 2) {
|
||||
let x1 = polygonVertices[i];
|
||||
let y1 = polygonVertices[i + 1];
|
||||
const x1 = polygonVertices[i];
|
||||
const y1 = polygonVertices[i + 1];
|
||||
|
||||
let x2 = 0;
|
||||
let y2 = 0;
|
||||
@ -210,24 +202,24 @@ export class ShapeRenderer implements Disposable {
|
||||
y2 = polygonVertices[i + 3];
|
||||
}
|
||||
|
||||
this.vertex(x1, y1, color!);
|
||||
this.vertex(x2, y2, color!);
|
||||
this.vertex(x1, y1, color);
|
||||
this.vertex(x2, y2, color);
|
||||
}
|
||||
}
|
||||
|
||||
circle (filled: boolean, x: number, y: number, radius: number, color?: Color, segments: number = 0) {
|
||||
if (segments == 0) segments = Math.max(1, (6 * MathUtils.cbrt(radius)) | 0);
|
||||
if (segments === 0) segments = Math.max(1, (6 * MathUtils.cbrt(radius)) | 0);
|
||||
if (segments <= 0) throw new Error("segments must be > 0.");
|
||||
if (!color) color = this.color;
|
||||
let angle = 2 * MathUtils.PI / segments;
|
||||
let cos = Math.cos(angle);
|
||||
let sin = Math.sin(angle);
|
||||
const angle = 2 * MathUtils.PI / segments;
|
||||
const cos = Math.cos(angle);
|
||||
const sin = Math.sin(angle);
|
||||
let cx = radius, cy = 0;
|
||||
if (!filled) {
|
||||
this.check(ShapeType.Line, segments * 2 + 2);
|
||||
for (let i = 0; i < segments; i++) {
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
let temp = cx;
|
||||
const temp = cx;
|
||||
cx = cos * cx - sin * cy;
|
||||
cy = sin * temp + cos * cy;
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
@ -240,7 +232,7 @@ export class ShapeRenderer implements Disposable {
|
||||
for (let i = 0; i < segments; i++) {
|
||||
this.vertex(x, y, color);
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
let temp = cx;
|
||||
const temp = cx;
|
||||
cx = cos * cx - sin * cy;
|
||||
cy = sin * temp + cos * cy;
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
@ -250,7 +242,6 @@ export class ShapeRenderer implements Disposable {
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
}
|
||||
|
||||
let temp = cx;
|
||||
cx = radius;
|
||||
cy = 0;
|
||||
this.vertex(x + cx, y + cy, color);
|
||||
@ -261,20 +252,20 @@ export class ShapeRenderer implements Disposable {
|
||||
if (!color) color = this.color;
|
||||
|
||||
// Algorithm from: http://www.antigrain.com/research/bezier_interpolation/index.html#PAGE_BEZIER_INTERPOLATION
|
||||
let subdiv_step = 1 / segments;
|
||||
let subdiv_step2 = subdiv_step * subdiv_step;
|
||||
let subdiv_step3 = subdiv_step * subdiv_step * subdiv_step;
|
||||
const subdiv_step = 1 / segments;
|
||||
const subdiv_step2 = subdiv_step * subdiv_step;
|
||||
const subdiv_step3 = subdiv_step * subdiv_step * subdiv_step;
|
||||
|
||||
let pre1 = 3 * subdiv_step;
|
||||
let pre2 = 3 * subdiv_step2;
|
||||
let pre4 = 6 * subdiv_step2;
|
||||
let pre5 = 6 * subdiv_step3;
|
||||
const pre1 = 3 * subdiv_step;
|
||||
const pre2 = 3 * subdiv_step2;
|
||||
const pre4 = 6 * subdiv_step2;
|
||||
const pre5 = 6 * subdiv_step3;
|
||||
|
||||
let tmp1x = x1 - cx1 * 2 + cx2;
|
||||
let tmp1y = y1 - cy1 * 2 + cy2;
|
||||
const tmp1x = x1 - cx1 * 2 + cx2;
|
||||
const tmp1y = y1 - cy1 * 2 + cy2;
|
||||
|
||||
let tmp2x = (cx1 - cx2) * 3 - x1 + x2;
|
||||
let tmp2y = (cy1 - cy2) * 3 - y1 + y2;
|
||||
const tmp2x = (cx1 - cx2) * 3 - x1 + x2;
|
||||
const tmp2y = (cy1 - cy2) * 3 - y1 + y2;
|
||||
|
||||
let fx = x1;
|
||||
let fy = y1;
|
||||
@ -285,26 +276,26 @@ export class ShapeRenderer implements Disposable {
|
||||
let ddfx = tmp1x * pre4 + tmp2x * pre5;
|
||||
let ddfy = tmp1y * pre4 + tmp2y * pre5;
|
||||
|
||||
let dddfx = tmp2x * pre5;
|
||||
let dddfy = tmp2y * pre5;
|
||||
const dddfx = tmp2x * pre5;
|
||||
const dddfy = tmp2y * pre5;
|
||||
|
||||
while (segments-- > 0) {
|
||||
this.vertex(fx, fy, color!);
|
||||
this.vertex(fx, fy, color);
|
||||
fx += dfx;
|
||||
fy += dfy;
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
ddfx += dddfx;
|
||||
ddfy += dddfy;
|
||||
this.vertex(fx, fy, color!);
|
||||
this.vertex(fx, fy, color);
|
||||
}
|
||||
this.vertex(fx, fy, color!);
|
||||
this.vertex(x2, y2, color!);
|
||||
this.vertex(fx, fy, color);
|
||||
this.vertex(x2, y2, color);
|
||||
}
|
||||
|
||||
private vertex (x: number, y: number, color: Color) {
|
||||
let idx = this.vertexIndex;
|
||||
let vertices = this.mesh.getVertices();
|
||||
const vertices = this.mesh.getVertices();
|
||||
vertices[idx++] = x;
|
||||
vertices[idx++] = y;
|
||||
vertices[idx++] = color.r;
|
||||
@ -317,13 +308,13 @@ export class ShapeRenderer implements Disposable {
|
||||
end () {
|
||||
if (!this.isDrawing) throw new Error("ShapeRenderer.begin() has not been called");
|
||||
this.flush();
|
||||
let gl = this.context.gl;
|
||||
const gl = this.context.gl;
|
||||
gl.disable(gl.BLEND);
|
||||
this.isDrawing = false;
|
||||
}
|
||||
|
||||
private flush () {
|
||||
if (this.vertexIndex == 0) return;
|
||||
if (this.vertexIndex === 0) return;
|
||||
if (!this.shader) throw new Error("No shader set.");
|
||||
this.mesh.setVerticesLength(this.vertexIndex);
|
||||
this.mesh.draw(this.shader, this.shapeType);
|
||||
@ -332,7 +323,7 @@ export class ShapeRenderer implements Disposable {
|
||||
|
||||
private check (shapeType: ShapeType, numVertices: number) {
|
||||
if (!this.isDrawing) throw new Error("ShapeRenderer.begin() has not been called");
|
||||
if (this.shapeType == shapeType) {
|
||||
if (this.shapeType === shapeType) {
|
||||
if (this.mesh.maxVertices() - this.mesh.numVertices() < numVertices) this.flush();
|
||||
else return;
|
||||
} else {
|
||||
|
||||
@ -27,8 +27,8 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Disposable, Color, SkeletonBounds, Utils, Skeleton, RegionAttachment, MeshAttachment, PathAttachment, ClippingAttachment } from "@esotericsoftware/spine-core";
|
||||
import { ShapeRenderer } from "./ShapeRenderer.js";
|
||||
import { ClippingAttachment, Color, type Disposable, MeshAttachment, PathAttachment, RegionAttachment, type Skeleton, SkeletonBounds, Utils } from "@esotericsoftware/spine-core";
|
||||
import type { ShapeRenderer } from "./ShapeRenderer.js";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL.js";
|
||||
|
||||
export class SkeletonDebugRenderer implements Disposable {
|
||||
@ -53,7 +53,7 @@ export class SkeletonDebugRenderer implements Disposable {
|
||||
|
||||
private context: ManagedWebGLRenderingContext;
|
||||
private bounds = new SkeletonBounds();
|
||||
private temp = new Array<number>();
|
||||
private temp = [] as number[];
|
||||
private vertices = Utils.newFloatArray(2 * 1024);
|
||||
private static LIGHT_GRAY = new Color(192 / 255, 192 / 255, 192 / 255, 1);
|
||||
private static GREEN = new Color(0, 1, 0, 1);
|
||||
@ -63,22 +63,22 @@ export class SkeletonDebugRenderer implements Disposable {
|
||||
}
|
||||
|
||||
draw (shapes: ShapeRenderer, skeleton: Skeleton, ignoredBones?: Array<string>) {
|
||||
let skeletonX = skeleton.x;
|
||||
let skeletonY = skeleton.y;
|
||||
let gl = this.context.gl;
|
||||
let srcFunc = this.premultipliedAlpha ? gl.ONE : gl.SRC_ALPHA;
|
||||
const skeletonX = skeleton.x;
|
||||
const skeletonY = skeleton.y;
|
||||
const gl = this.context.gl;
|
||||
const srcFunc = this.premultipliedAlpha ? gl.ONE : gl.SRC_ALPHA;
|
||||
shapes.setBlendMode(srcFunc, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
let bones = skeleton.bones;
|
||||
const bones = skeleton.bones;
|
||||
if (this.drawBones) {
|
||||
shapes.setColor(this.boneLineColor);
|
||||
for (let i = 0, n = bones.length; i < n; i++) {
|
||||
let bone = bones[i];
|
||||
const bone = bones[i];
|
||||
if (ignoredBones && ignoredBones.indexOf(bone.data.name) > -1) continue;
|
||||
if (!bone.parent) continue;
|
||||
const boneApplied = bone.applied;
|
||||
let x = bone.data.length * boneApplied.a + boneApplied.worldX;
|
||||
let y = bone.data.length * boneApplied.c + boneApplied.worldY;
|
||||
const x = bone.data.length * boneApplied.a + boneApplied.worldX;
|
||||
const y = bone.data.length * boneApplied.c + boneApplied.worldY;
|
||||
shapes.rectLine(true, boneApplied.worldX, boneApplied.worldY, x, y, this.boneWidth * this.scale);
|
||||
}
|
||||
if (this.drawSkeletonXY) shapes.x(skeletonX, skeletonY, 4 * this.scale);
|
||||
@ -86,13 +86,13 @@ export class SkeletonDebugRenderer implements Disposable {
|
||||
|
||||
if (this.drawRegionAttachments) {
|
||||
shapes.setColor(this.attachmentLineColor);
|
||||
let slots = skeleton.slots;
|
||||
const slots = skeleton.slots;
|
||||
for (let i = 0, n = slots.length; i < n; i++) {
|
||||
let slot = slots[i];
|
||||
const slot = slots[i];
|
||||
if (!slot.bone.active) continue;
|
||||
let attachment = slot.applied.attachment;
|
||||
const attachment = slot.applied.attachment;
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
let vertices = this.vertices;
|
||||
const vertices = this.vertices;
|
||||
attachment.computeWorldVertices(slot, vertices, 0, 2);
|
||||
shapes.line(vertices[0], vertices[1], vertices[2], vertices[3]);
|
||||
shapes.line(vertices[2], vertices[3], vertices[4], vertices[5]);
|
||||
@ -103,20 +103,20 @@ export class SkeletonDebugRenderer implements Disposable {
|
||||
}
|
||||
|
||||
if (this.drawMeshHull || this.drawMeshTriangles) {
|
||||
let slots = skeleton.slots;
|
||||
const slots = skeleton.slots;
|
||||
for (let i = 0, n = slots.length; i < n; i++) {
|
||||
let slot = slots[i];
|
||||
const slot = slots[i];
|
||||
if (!slot.bone.active) continue;
|
||||
let attachment = slot.applied.attachment;
|
||||
const attachment = slot.applied.attachment;
|
||||
if (!(attachment instanceof MeshAttachment)) continue;
|
||||
let vertices = this.vertices;
|
||||
const vertices = this.vertices;
|
||||
attachment.computeWorldVertices(skeleton, slot, 0, attachment.worldVerticesLength, vertices, 0, 2);
|
||||
let triangles = attachment.triangles;
|
||||
const triangles = attachment.triangles;
|
||||
let hullLength = attachment.hullLength;
|
||||
if (this.drawMeshTriangles) {
|
||||
shapes.setColor(this.triangleLineColor);
|
||||
for (let ii = 0, nn = triangles.length; ii < nn; ii += 3) {
|
||||
let v1 = triangles[ii] * 2, v2 = triangles[ii + 1] * 2, v3 = triangles[ii + 2] * 2;
|
||||
const v1 = triangles[ii] * 2, v2 = triangles[ii + 1] * 2, v3 = triangles[ii + 2] * 2;
|
||||
shapes.triangle(false, vertices[v1], vertices[v1 + 1], //
|
||||
vertices[v2], vertices[v2 + 1], //
|
||||
vertices[v3], vertices[v3 + 1] //
|
||||
@ -128,7 +128,7 @@ export class SkeletonDebugRenderer implements Disposable {
|
||||
hullLength = (hullLength >> 1) * 2;
|
||||
let lastX = vertices[hullLength - 2], lastY = vertices[hullLength - 1];
|
||||
for (let ii = 0, nn = hullLength; ii < nn; ii += 2) {
|
||||
let x = vertices[ii], y = vertices[ii + 1];
|
||||
const x = vertices[ii], y = vertices[ii + 1];
|
||||
shapes.line(x, y, lastX, lastY);
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
@ -138,34 +138,34 @@ export class SkeletonDebugRenderer implements Disposable {
|
||||
}
|
||||
|
||||
if (this.drawBoundingBoxes) {
|
||||
let bounds = this.bounds;
|
||||
const bounds = this.bounds;
|
||||
bounds.update(skeleton, true);
|
||||
shapes.setColor(this.aabbColor);
|
||||
shapes.rect(false, bounds.minX, bounds.minY, bounds.getWidth(), bounds.getHeight());
|
||||
let polygons = bounds.polygons;
|
||||
let boxes = bounds.boundingBoxes;
|
||||
const polygons = bounds.polygons;
|
||||
const boxes = bounds.boundingBoxes;
|
||||
for (let i = 0, n = polygons.length; i < n; i++) {
|
||||
let polygon = polygons[i];
|
||||
const polygon = polygons[i];
|
||||
shapes.setColor(boxes[i].color);
|
||||
shapes.polygon(polygon, 0, polygon.length);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.drawPaths) {
|
||||
let slots = skeleton.slots;
|
||||
const slots = skeleton.slots;
|
||||
for (let i = 0, n = slots.length; i < n; i++) {
|
||||
let slot = slots[i];
|
||||
const slot = slots[i];
|
||||
if (!slot.bone.active) continue;
|
||||
let attachment = slot.applied.attachment;
|
||||
const attachment = slot.applied.attachment;
|
||||
if (!(attachment instanceof PathAttachment)) continue;
|
||||
let nn = attachment.worldVerticesLength;
|
||||
let world = this.temp = Utils.setArraySize(this.temp, nn, 0);
|
||||
const world = this.temp = Utils.setArraySize(this.temp, nn, 0);
|
||||
attachment.computeWorldVertices(skeleton, slot, 0, nn, world, 0, 2);
|
||||
let color = this.pathColor;
|
||||
const color = this.pathColor;
|
||||
let x1 = world[2], y1 = world[3], x2 = 0, y2 = 0;
|
||||
if (attachment.closed) {
|
||||
shapes.setColor(color);
|
||||
let cx1 = world[0], cy1 = world[1], cx2 = world[nn - 2], cy2 = world[nn - 1];
|
||||
const cx1 = world[0], cy1 = world[1], cx2 = world[nn - 2], cy2 = world[nn - 1];
|
||||
x2 = world[nn - 4];
|
||||
y2 = world[nn - 3];
|
||||
shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, 32);
|
||||
@ -175,7 +175,7 @@ export class SkeletonDebugRenderer implements Disposable {
|
||||
}
|
||||
nn -= 4;
|
||||
for (let ii = 4; ii < nn; ii += 6) {
|
||||
let cx1 = world[ii], cy1 = world[ii + 1], cx2 = world[ii + 2], cy2 = world[ii + 3];
|
||||
const cx1 = world[ii], cy1 = world[ii + 1], cx2 = world[ii + 2], cy2 = world[ii + 3];
|
||||
x2 = world[ii + 4];
|
||||
y2 = world[ii + 5];
|
||||
shapes.setColor(color);
|
||||
@ -192,29 +192,29 @@ export class SkeletonDebugRenderer implements Disposable {
|
||||
if (this.drawBones) {
|
||||
shapes.setColor(this.boneOriginColor);
|
||||
for (let i = 0, n = bones.length; i < n; i++) {
|
||||
let bone = bones[i];
|
||||
const bone = bones[i];
|
||||
if (ignoredBones && ignoredBones.indexOf(bone.data.name) > -1) continue;
|
||||
let boneApplied = bone.applied;
|
||||
const boneApplied = bone.applied;
|
||||
shapes.circle(true, boneApplied.worldX, boneApplied.worldY, 3 * this.scale, this.boneOriginColor, 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.drawClipping) {
|
||||
let slots = skeleton.slots;
|
||||
const slots = skeleton.slots;
|
||||
shapes.setColor(this.clipColor)
|
||||
for (let i = 0, n = slots.length; i < n; i++) {
|
||||
let slot = slots[i];
|
||||
const slot = slots[i];
|
||||
if (!slot.bone.active) continue;
|
||||
let attachment = slot.applied.attachment;
|
||||
const attachment = slot.applied.attachment;
|
||||
if (!(attachment instanceof ClippingAttachment)) continue;
|
||||
let nn = attachment.worldVerticesLength;
|
||||
let world = this.temp = Utils.setArraySize(this.temp, nn, 0);
|
||||
const nn = attachment.worldVerticesLength;
|
||||
const world = this.temp = Utils.setArraySize(this.temp, nn, 0);
|
||||
attachment.computeWorldVertices(skeleton, slot, 0, nn, world, 0, 2);
|
||||
for (let i = 0, n = world.length; i < n; i += 2) {
|
||||
let x = world[i];
|
||||
let y = world[i + 1];
|
||||
let x2 = world[(i + 2) % world.length];
|
||||
let y2 = world[(i + 3) % world.length];
|
||||
const x = world[i];
|
||||
const y = world[i + 1];
|
||||
const x2 = world[(i + 2) % world.length];
|
||||
const y2 = world[(i + 3) % world.length];
|
||||
shapes.line(x, y, x2, y2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,10 +27,10 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { NumberArrayLike, Color, SkeletonClipping, Vector2, Utils, Skeleton, BlendMode, RegionAttachment, TextureAtlasRegion, MeshAttachment, ClippingAttachment } from "@esotericsoftware/spine-core";
|
||||
import { GLTexture } from "./GLTexture.js";
|
||||
import { PolygonBatcher } from "./PolygonBatcher.js";
|
||||
import { ManagedWebGLRenderingContext } from "./WebGL.js";
|
||||
import { type BlendMode, ClippingAttachment, Color, MeshAttachment, type NumberArrayLike, RegionAttachment, type Skeleton, SkeletonClipping, type TextureRegion, Utils, Vector2 } from "@esotericsoftware/spine-core";
|
||||
import type { GLTexture } from "./GLTexture.js";
|
||||
import type { PolygonBatcher } from "./PolygonBatcher.js";
|
||||
import type { ManagedWebGLRenderingContext } from "./WebGL.js";
|
||||
|
||||
|
||||
class Renderable {
|
||||
@ -63,28 +63,28 @@ export class SkeletonRenderer {
|
||||
}
|
||||
|
||||
draw (batcher: PolygonBatcher, skeleton: Skeleton, slotRangeStart: number = -1, slotRangeEnd: number = -1, transformer: VertexTransformer | null = null) {
|
||||
let clipper = this.clipper;
|
||||
let premultipliedAlpha = this.premultipliedAlpha;
|
||||
let twoColorTint = this.twoColorTint;
|
||||
const clipper = this.clipper;
|
||||
const premultipliedAlpha = this.premultipliedAlpha;
|
||||
const twoColorTint = this.twoColorTint;
|
||||
let blendMode: BlendMode | null = null;
|
||||
|
||||
let renderable: Renderable = this.renderable;
|
||||
const renderable: Renderable = this.renderable;
|
||||
let uvs: NumberArrayLike;
|
||||
let triangles: Array<number>;
|
||||
let drawOrder = skeleton.drawOrder;
|
||||
const drawOrder = skeleton.drawOrder;
|
||||
let attachmentColor: Color;
|
||||
let skeletonColor = skeleton.color;
|
||||
let vertexSize = twoColorTint ? 12 : 8;
|
||||
const skeletonColor = skeleton.color;
|
||||
const vertexSize = twoColorTint ? 12 : 8;
|
||||
let inRange = false;
|
||||
if (slotRangeStart == -1) inRange = true;
|
||||
if (slotRangeStart === -1) inRange = true;
|
||||
for (let i = 0, n = drawOrder.length; i < n; i++) {
|
||||
let slot = drawOrder[i];
|
||||
const slot = drawOrder[i];
|
||||
if (!slot.bone.active) {
|
||||
clipper.clipEnd(slot);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (slotRangeStart >= 0 && slotRangeStart == slot.data.index) {
|
||||
if (slotRangeStart >= 0 && slotRangeStart === slot.data.index) {
|
||||
inRange = true;
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ export class SkeletonRenderer {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (slotRangeEnd >= 0 && slotRangeEnd == slot.data.index) {
|
||||
if (slotRangeEnd >= 0 && slotRangeEnd === slot.data.index) {
|
||||
inRange = false;
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ export class SkeletonRenderer {
|
||||
attachment.computeWorldVertices(slot, renderable.vertices, 0, vertexSize);
|
||||
triangles = SkeletonRenderer.QUAD_TRIANGLES;
|
||||
uvs = attachment.uvs;
|
||||
texture = <GLTexture>attachment.region!.texture;
|
||||
texture = (attachment.region as TextureRegion).texture as GLTexture;
|
||||
attachmentColor = attachment.color;
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
renderable.vertices = this.vertices;
|
||||
@ -119,7 +119,7 @@ export class SkeletonRenderer {
|
||||
}
|
||||
attachment.computeWorldVertices(skeleton, slot, 0, attachment.worldVerticesLength, renderable.vertices, 0, vertexSize);
|
||||
triangles = attachment.triangles;
|
||||
texture = <GLTexture>attachment.region!.texture;
|
||||
texture = (attachment.region as TextureRegion).texture as GLTexture;
|
||||
uvs = attachment.uvs;
|
||||
attachmentColor = attachment.color;
|
||||
} else if (attachment instanceof ClippingAttachment) {
|
||||
@ -132,8 +132,8 @@ export class SkeletonRenderer {
|
||||
}
|
||||
|
||||
if (texture) {
|
||||
let slotColor = pose.color;
|
||||
let finalColor = this.tempColor;
|
||||
const slotColor = pose.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;
|
||||
@ -143,7 +143,7 @@ export class SkeletonRenderer {
|
||||
finalColor.g *= finalColor.a;
|
||||
finalColor.b *= finalColor.a;
|
||||
}
|
||||
let darkColor = this.tempColor2;
|
||||
const darkColor = this.tempColor2;
|
||||
if (!pose.darkColor)
|
||||
darkColor.set(0, 0, 0, 1.0);
|
||||
else {
|
||||
@ -157,19 +157,19 @@ export class SkeletonRenderer {
|
||||
darkColor.a = premultipliedAlpha ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
let slotBlendMode = slot.data.blendMode;
|
||||
if (slotBlendMode != blendMode) {
|
||||
const slotBlendMode = slot.data.blendMode;
|
||||
if (slotBlendMode !== blendMode) {
|
||||
blendMode = slotBlendMode;
|
||||
batcher.setBlendMode(blendMode, premultipliedAlpha);
|
||||
}
|
||||
|
||||
if (clipper.isClipping() && clipper.clipTriangles(renderable.vertices, triangles, triangles.length, uvs, finalColor, darkColor, twoColorTint, vertexSize)) {
|
||||
let clippedVertices = new Float32Array(clipper.clippedVertices);
|
||||
let clippedTriangles = clipper.clippedTriangles;
|
||||
const clippedVertices = new Float32Array(clipper.clippedVertices);
|
||||
const clippedTriangles = clipper.clippedTriangles;
|
||||
if (transformer) transformer(clippedVertices, clippedVertices.length, vertexSize);
|
||||
batcher.draw(texture, clippedVertices, clippedTriangles);
|
||||
} else {
|
||||
let verts = renderable.vertices;
|
||||
const verts = renderable.vertices;
|
||||
if (!twoColorTint) {
|
||||
for (let v = 2, u = 0, n = renderable.numFloats; v < n; v += vertexSize, u += 2) {
|
||||
verts[v] = finalColor.r;
|
||||
@ -193,7 +193,7 @@ export class SkeletonRenderer {
|
||||
verts[v + 9] = darkColor.a;
|
||||
}
|
||||
}
|
||||
let view = (renderable.vertices as Float32Array).subarray(0, renderable.numFloats);
|
||||
const view = (renderable.vertices as Float32Array).subarray(0, renderable.numFloats);
|
||||
if (transformer) transformer(renderable.vertices, renderable.numFloats, vertexSize);
|
||||
batcher.draw(texture, view, triangles);
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { TimeKeeper, AssetManager, ManagedWebGLRenderingContext, SceneRenderer, Input, StringMap } from "./index.js";
|
||||
import { AssetManager, Input, ManagedWebGLRenderingContext, SceneRenderer, type StringMap, TimeKeeper } from "./index.js";
|
||||
|
||||
/** An app running inside a {@link SpineCanvas}. The app life-cycle
|
||||
* is as follows:
|
||||
@ -55,7 +55,7 @@ export interface SpineCanvasConfig {
|
||||
/* The path prefix to be used by the {@link AssetManager}. */
|
||||
pathPrefix?: string;
|
||||
/* The WebGL context configuration */
|
||||
webglConfig?: any;
|
||||
webglConfig?: WebGLContextAttributes;
|
||||
}
|
||||
|
||||
/** Manages the life-cycle and WebGL context of a {@link SpineCanvasApp}. The app loads
|
||||
@ -100,7 +100,7 @@ export class SpineCanvas {
|
||||
|
||||
if (config.app.loadAssets) config.app.loadAssets(this);
|
||||
|
||||
let loop = () => {
|
||||
const loop = () => {
|
||||
if (this.disposed) return;
|
||||
requestAnimationFrame(loop);
|
||||
this.time.update();
|
||||
@ -108,7 +108,7 @@ export class SpineCanvas {
|
||||
if (config.app.render) config.app.render(this);
|
||||
}
|
||||
|
||||
let waitForAssets = () => {
|
||||
const waitForAssets = () => {
|
||||
if (this.disposed) return;
|
||||
if (this.assetManager.isLoadingComplete()) {
|
||||
if (this.assetManager.hasErrors()) {
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { Matrix4, M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23, M30, M31, M32, M33 } from "./Matrix4.js";
|
||||
import { M00, M01, M02, M03, M10, M11, M12, M13, M20, M21, M22, M23, M30, M31, M32, M33, type Matrix4 } from "./Matrix4.js";
|
||||
|
||||
export class Vector3 {
|
||||
x = 0;
|
||||
@ -77,7 +77,7 @@ export class Vector3 {
|
||||
|
||||
normalize (): Vector3 {
|
||||
let len = this.length();
|
||||
if (len == 0) return this;
|
||||
if (len === 0) return this;
|
||||
len = 1 / len;
|
||||
this.x *= len;
|
||||
this.y *= len;
|
||||
@ -90,15 +90,15 @@ export class Vector3 {
|
||||
}
|
||||
|
||||
multiply (matrix: Matrix4): Vector3 {
|
||||
let l_mat = matrix.values;
|
||||
const l_mat = matrix.values;
|
||||
return this.set(this.x * l_mat[M00] + this.y * l_mat[M01] + this.z * l_mat[M02] + l_mat[M03],
|
||||
this.x * l_mat[M10] + this.y * l_mat[M11] + this.z * l_mat[M12] + l_mat[M13],
|
||||
this.x * l_mat[M20] + this.y * l_mat[M21] + this.z * l_mat[M22] + l_mat[M23]);
|
||||
}
|
||||
|
||||
project (matrix: Matrix4): Vector3 {
|
||||
let l_mat = matrix.values;
|
||||
let l_w = 1 / (this.x * l_mat[M30] + this.y * l_mat[M31] + this.z * l_mat[M32] + l_mat[M33]);
|
||||
const l_mat = matrix.values;
|
||||
const l_w = 1 / (this.x * l_mat[M30] + this.y * l_mat[M31] + this.z * l_mat[M32] + l_mat[M33]);
|
||||
return this.set((this.x * l_mat[M00] + this.y * l_mat[M01] + this.z * l_mat[M02] + l_mat[M03]) * l_w,
|
||||
(this.x * l_mat[M10] + this.y * l_mat[M11] + this.z * l_mat[M12] + l_mat[M13]) * l_w,
|
||||
(this.x * l_mat[M20] + this.y * l_mat[M21] + this.z * l_mat[M22] + l_mat[M23]) * l_w);
|
||||
@ -113,9 +113,9 @@ export class Vector3 {
|
||||
}
|
||||
|
||||
distance (v: Vector3): number {
|
||||
let a = v.x - this.x;
|
||||
let b = v.y - this.y;
|
||||
let c = v.z - this.z;
|
||||
const a = v.x - this.x;
|
||||
const b = v.y - this.y;
|
||||
const c = v.z - this.z;
|
||||
return Math.sqrt(a * a + b * b + c * c);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
export * from "@esotericsoftware/spine-core";
|
||||
export * from "./AssetManager.js";
|
||||
export * from "./Camera.js";
|
||||
export * from "./CameraController.js";
|
||||
@ -14,5 +15,4 @@ export * from "./SkeletonDebugRenderer.js";
|
||||
export * from "./SkeletonRenderer.js";
|
||||
export * from "./SpineCanvas.js";
|
||||
export * from "./Vector3.js";
|
||||
export * from "./WebGL.js";
|
||||
export * from "@esotericsoftware/spine-core";
|
||||
export * from "./WebGL.js";
|
||||
Loading…
x
Reference in New Issue
Block a user