mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
Removed SpineCanvasApp dependency.
This commit is contained in:
parent
847c152f2a
commit
e67aa324fe
@ -3,8 +3,8 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!-- <script src="../dist/iife/spine-webgl.js"></script> -->
|
||||
<script src="./spine-webgl.min.js"></script>
|
||||
<script src="../dist/iife/spine-webgl.js"></script>
|
||||
<!-- <script src="./spine-webgl.min.js"></script> -->
|
||||
<title>JS Library Showcase</title>
|
||||
<style>
|
||||
body {
|
||||
@ -12,9 +12,6 @@
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html {
|
||||
/* scroll-behavior: smooth; */
|
||||
}
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
@ -1502,7 +1499,7 @@ skins.forEach((skin, i) => {
|
||||
|
||||
<script>
|
||||
const stretchyman = spine.getSpineWidget("stretchyman");
|
||||
stretchyman.update = (canvas, delta, skeleton, state) => {
|
||||
stretchyman.update = (delta, skeleton, state) => {
|
||||
// skin logiv if widget is off screen
|
||||
if (!stretchyman.onScreen) return;
|
||||
|
||||
@ -1602,7 +1599,7 @@ stretchyman.update = (canvas, delta, skeleton, state) => {
|
||||
await tank.loadingPromise;
|
||||
await tank2.loadingPromise;
|
||||
|
||||
tank.beforeUpdateWorldTransforms = (canvas, delta, skeleton, state) => {
|
||||
tank.beforeUpdateWorldTransforms = (skeleton, state) => {
|
||||
if (!tank.onScreen) return;
|
||||
tank.skeleton.scaleX = tank2.skeleton.scaleX;
|
||||
tank.skeleton.scaleY = tank2.skeleton.scaleY;
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
import { SpineCanvas, SpineCanvasApp, AtlasAttachmentLoader, SkeletonBinary, SkeletonJson, Skeleton, Animation, AnimationState, AnimationStateData, Physics, Vector2, Vector3, ResizeMode, Color, MixBlend, MixDirection, SceneRenderer, SkeletonData, Input, LoadingScreenWidget, TextureAtlas, Texture } from "./index.js";
|
||||
import { AtlasAttachmentLoader, SkeletonBinary, SkeletonJson, Skeleton, Animation, AnimationState, AnimationStateData, Physics, Vector2, Vector3, Color, MixBlend, MixDirection, SceneRenderer, SkeletonData, Input, LoadingScreenWidget, TextureAtlas, Texture, ManagedWebGLRenderingContext, AssetManager, TimeKeeper } from "./index.js";
|
||||
|
||||
interface Rectangle {
|
||||
x: number,
|
||||
@ -36,7 +36,8 @@ interface Rectangle {
|
||||
height: number,
|
||||
}
|
||||
|
||||
type UpdateSpineWidgetFunction = (canvas: SpineCanvas, delta: number, skeleton: Skeleton, state: AnimationState) => void;
|
||||
type BeforeAfterUpdateSpineWidgetFunction = (skeleton: Skeleton, state: AnimationState) => void;
|
||||
type UpdateSpineWidgetFunction = (delta: number, skeleton: Skeleton, state: AnimationState) => void;
|
||||
|
||||
type OffScreenUpdateBehaviourType = "pause" | "update" | "pose";
|
||||
function isOffScreenUpdateBehaviourType(value: string): value is OffScreenUpdateBehaviourType {
|
||||
@ -109,8 +110,8 @@ class SpineWebComponentWidget extends HTMLElement implements WidgetLayoutOptions
|
||||
public skin?: string;
|
||||
skeletonData?: SkeletonData; // TODO
|
||||
update?: UpdateSpineWidgetFunction;
|
||||
beforeUpdateWorldTransforms: UpdateSpineWidgetFunction = () => {};
|
||||
afterUpdateWorldTransforms: UpdateSpineWidgetFunction= () => {};
|
||||
beforeUpdateWorldTransforms: BeforeAfterUpdateSpineWidgetFunction = () => {};
|
||||
afterUpdateWorldTransforms: BeforeAfterUpdateSpineWidgetFunction= () => {};
|
||||
|
||||
// layout options
|
||||
public fit: FitType = "contain";
|
||||
@ -412,13 +413,13 @@ class SpineWebComponentWidget extends HTMLElement implements WidgetLayoutOptions
|
||||
this.loadTextureAtlasButNoTextures(atlasPath).then(atlas => this.loadTexturesInPagesAttribute(atlas)),
|
||||
]);
|
||||
|
||||
const atlas = this.overlay.spineCanvas.assetManager.require(atlasPath);
|
||||
const atlas = this.overlay.assetManager.require(atlasPath);
|
||||
const atlasLoader = new AtlasAttachmentLoader(atlas);
|
||||
|
||||
const skeletonLoader = isBinary ? new SkeletonBinary(atlasLoader) : new SkeletonJson(atlasLoader);
|
||||
skeletonLoader.scale = scale;
|
||||
|
||||
const skeletonFile = this.overlay.spineCanvas.assetManager.require(skeletonPath);
|
||||
const skeletonFile = this.overlay.assetManager.require(skeletonPath);
|
||||
const skeletonData = skeletonDataInput ?? skeletonLoader.readSkeletonData(skeletonFile);
|
||||
|
||||
const skeleton = new Skeleton(skeletonData);
|
||||
@ -487,7 +488,7 @@ class SpineWebComponentWidget extends HTMLElement implements WidgetLayoutOptions
|
||||
|
||||
public async loadBinary(path: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.overlay.spineCanvas.assetManager.loadBinary(path,
|
||||
this.overlay.assetManager.loadBinary(path,
|
||||
(_, binary) => resolve(binary),
|
||||
(_, message) => reject(message),
|
||||
);
|
||||
@ -496,7 +497,7 @@ class SpineWebComponentWidget extends HTMLElement implements WidgetLayoutOptions
|
||||
|
||||
public async loadJson(path: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.overlay.spineCanvas.assetManager.loadJson(path,
|
||||
this.overlay.assetManager.loadJson(path,
|
||||
(_, object) => resolve(object),
|
||||
(_, message) => reject(message),
|
||||
);
|
||||
@ -505,7 +506,7 @@ class SpineWebComponentWidget extends HTMLElement implements WidgetLayoutOptions
|
||||
|
||||
public async loadTexture(path: string) {
|
||||
return new Promise<Texture>((resolve, reject) => {
|
||||
this.overlay.spineCanvas.assetManager.loadTexture(path,
|
||||
this.overlay.assetManager.loadTexture(path,
|
||||
(_, texture) => resolve(texture),
|
||||
(_, message) => reject(message),
|
||||
);
|
||||
@ -514,7 +515,7 @@ class SpineWebComponentWidget extends HTMLElement implements WidgetLayoutOptions
|
||||
|
||||
public async loadTextureAtlas(path: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.overlay.spineCanvas.assetManager.loadTextureAtlas(path,
|
||||
this.overlay.assetManager.loadTextureAtlas(path,
|
||||
(_, atlas) => resolve(atlas),
|
||||
(_, message) => reject(message),
|
||||
);
|
||||
@ -523,7 +524,7 @@ class SpineWebComponentWidget extends HTMLElement implements WidgetLayoutOptions
|
||||
|
||||
public async loadTextureAtlasButNoTextures(path: string) {
|
||||
return new Promise<TextureAtlas>((resolve, reject) => {
|
||||
this.overlay.spineCanvas.assetManager.loadTextureAtlasButNoTextures(path,
|
||||
this.overlay.assetManager.loadTextureAtlasButNoTextures(path,
|
||||
(_, atlas) => resolve(atlas),
|
||||
(_, message) => reject(message),
|
||||
);
|
||||
@ -535,7 +536,7 @@ class SpineWebComponentWidget extends HTMLElement implements WidgetLayoutOptions
|
||||
*/
|
||||
|
||||
private calculateAnimationViewport (animation?: Animation): Rectangle {
|
||||
const renderer = this.overlay.spineCanvas.renderer;
|
||||
const renderer = this.overlay.renderer;
|
||||
const { skeleton } = this;
|
||||
if (!skeleton) return { x: 0, y: 0, width: 0, height: 0 };
|
||||
skeleton.setToSetupPose();
|
||||
@ -581,7 +582,6 @@ class SpineWebComponentWidget extends HTMLElement implements WidgetLayoutOptions
|
||||
class SpineWebComponentOverlay extends HTMLElement {
|
||||
private root: ShadowRoot;
|
||||
|
||||
public spineCanvas:SpineCanvas;
|
||||
private div: HTMLDivElement;
|
||||
private canvas:HTMLCanvasElement;
|
||||
private fps: HTMLSpanElement;
|
||||
@ -606,6 +606,11 @@ class SpineWebComponentOverlay extends HTMLElement {
|
||||
private currentCanvasBaseWidth = 0;
|
||||
private currentCanvasBaseHeight = 0;
|
||||
|
||||
public renderer: SceneRenderer;
|
||||
public assetManager: AssetManager;
|
||||
private disposed = false;
|
||||
readonly time = new TimeKeeper();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.root = this.attachShadow({ mode: 'open' });
|
||||
@ -626,16 +631,6 @@ class SpineWebComponentOverlay extends HTMLElement {
|
||||
this.canvas.style.top = "0";
|
||||
this.canvas.style.left = "0";
|
||||
|
||||
// sono per l'ennesima volta fermo alla dimensione del canvas.
|
||||
// purtroppo la dimensione dello schermo non permette di determinare la posizione dei div container relativamente allo schermo
|
||||
// se trovassimo un modo per farlo, sarebbe fatta. provare prima a investigare un pochino lì.
|
||||
//
|
||||
// alternativamente giocare ancora con i lvh o qualcosa del genere
|
||||
// purtroppo ho già provato un po' e si hanno oggettivamente dei brevi flash allo scroll quando la dimensione del canvas
|
||||
// ovvero quando compare o scompare la barra durante lo scroll da mobile
|
||||
|
||||
// this.canvas.style.width = "100lvw";
|
||||
// this.canvas.style.height = "120lvh";
|
||||
this.canvas.style.setProperty("pointer-events", "none");
|
||||
this.canvas.style.transform =`translate(0px,0px)`;
|
||||
// this.canvas.style.setProperty("will-change", "transform"); // performance seems to be even worse with this uncommented
|
||||
@ -646,7 +641,11 @@ class SpineWebComponentOverlay extends HTMLElement {
|
||||
this.fps.style.left = "0";
|
||||
this.root.appendChild(this.fps);
|
||||
|
||||
this.spineCanvas = new SpineCanvas(this.canvas, { app: this.setupSpineCanvasApp() });
|
||||
const context = new ManagedWebGLRenderingContext(this.canvas, { alpha: true });
|
||||
this.renderer = new SceneRenderer(this.canvas, context);
|
||||
this.assetManager = new AssetManager(context);
|
||||
this.input = new Input(this.canvas);
|
||||
this.setupSpineCanvasApp(this.canvas);
|
||||
|
||||
this.updateCanvasSize();
|
||||
this.zoomHandler();
|
||||
@ -684,17 +683,13 @@ class SpineWebComponentOverlay extends HTMLElement {
|
||||
this.intersectionObserver!.observe(widget.getHTMLElementReference());
|
||||
}
|
||||
|
||||
private setupSpineCanvasApp(): SpineCanvasApp {
|
||||
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);
|
||||
return {
|
||||
update: (canvas: SpineCanvas, delta: number) => {
|
||||
this.skeletonList.forEach(({ skeleton, state, update, onScreen, offScreenUpdateBehaviour, skeletonPath, beforeUpdateWorldTransforms, afterUpdateWorldTransforms }) => {
|
||||
private setupSpineCanvasApp(canvas: HTMLCanvasElement) {
|
||||
const updateWidgets = () => {
|
||||
const delta = this.time.delta;
|
||||
this.skeletonList.forEach(({ skeleton, state, update, onScreen, offScreenUpdateBehaviour, beforeUpdateWorldTransforms, afterUpdateWorldTransforms }) => {
|
||||
if (!skeleton || !state) return;
|
||||
if (!onScreen && offScreenUpdateBehaviour === "pause") return;
|
||||
if (update) update(canvas, delta, skeleton, state)
|
||||
if (update) update(delta, skeleton, state)
|
||||
else {
|
||||
// delta = 0
|
||||
state.update(delta);
|
||||
@ -702,18 +697,23 @@ class SpineWebComponentOverlay extends HTMLElement {
|
||||
|
||||
if (onScreen || (!onScreen && offScreenUpdateBehaviour === "pose") ) {
|
||||
state.apply(skeleton);
|
||||
beforeUpdateWorldTransforms(canvas, delta, skeleton, state);
|
||||
beforeUpdateWorldTransforms(skeleton, state);
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
afterUpdateWorldTransforms(canvas, delta, skeleton, state);
|
||||
afterUpdateWorldTransforms(skeleton, state);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.fps.innerText = canvas.time.framesPerSecond.toFixed(2) + " fps";
|
||||
},
|
||||
this.fps.innerText = this.time.framesPerSecond.toFixed(2) + " fps";
|
||||
};
|
||||
|
||||
render: (canvas: SpineCanvas) => {
|
||||
canvas.clear(0, 0, 0, 0);
|
||||
let renderer = canvas.renderer;
|
||||
const clear = (r: number, g: number, b: number, a: number) => {
|
||||
this.renderer.context.gl.clearColor(r, g, b, a);
|
||||
this.renderer.context.gl.clear(this.renderer.context.gl.COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
const renderWidgets = () => {
|
||||
clear(0, 0, 0, 0);
|
||||
let renderer = this.renderer;
|
||||
renderer.begin();
|
||||
|
||||
const devicePixelRatio = window.devicePixelRatio;
|
||||
@ -730,16 +730,14 @@ class SpineWebComponentOverlay extends HTMLElement {
|
||||
|
||||
// TODO: now that the clip logic works, remove the code duplication
|
||||
if (clip) {
|
||||
const clipToBoundStart = (canvas: SpineCanvas, divBounds: Rectangle) => {
|
||||
const renderer = canvas.renderer;
|
||||
|
||||
const clipToBoundStart = (divBounds: Rectangle) => {
|
||||
// break current batch and start a new one
|
||||
renderer.end();
|
||||
|
||||
// set the new viewport to the div bound
|
||||
const viewportWidth = divBounds.width * window.devicePixelRatio;
|
||||
const viewporthHeight = divBounds.height * window.devicePixelRatio;
|
||||
canvas.gl.viewport(
|
||||
renderer.context.gl.viewport(
|
||||
divBounds.x * window.devicePixelRatio,
|
||||
this.canvas.height - (divBounds.y + divBounds.height) * window.devicePixelRatio,
|
||||
viewportWidth,
|
||||
@ -768,9 +766,9 @@ class SpineWebComponentOverlay extends HTMLElement {
|
||||
// end clip batch
|
||||
renderer.end();
|
||||
|
||||
canvas.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
||||
canvas.renderer.camera.setViewport(this.canvas.width, this.canvas.height);
|
||||
canvas.renderer.camera.update();
|
||||
renderer.context.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
||||
renderer.camera.setViewport(this.canvas.width, this.canvas.height);
|
||||
renderer.camera.update();
|
||||
|
||||
// start new normal batch
|
||||
renderer.begin();
|
||||
@ -778,7 +776,7 @@ class SpineWebComponentOverlay extends HTMLElement {
|
||||
|
||||
|
||||
|
||||
clipToBoundStart(canvas, divBounds)
|
||||
clipToBoundStart(divBounds)
|
||||
|
||||
|
||||
|
||||
@ -1048,9 +1046,22 @@ class SpineWebComponentOverlay extends HTMLElement {
|
||||
});
|
||||
|
||||
renderer.end();
|
||||
},
|
||||
}
|
||||
|
||||
const loop = () => {
|
||||
if (this.disposed) return;
|
||||
requestAnimationFrame(loop);
|
||||
this.time.update();
|
||||
updateWidgets();
|
||||
renderWidgets();
|
||||
}
|
||||
|
||||
requestAnimationFrame(loop);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
connectedCallback(): void {
|
||||
@ -1082,7 +1093,7 @@ class SpineWebComponentOverlay extends HTMLElement {
|
||||
down: (x, y, ev) => {
|
||||
const originalEvent = ev instanceof MouseEvent ? ev : ev!.changedTouches[0];
|
||||
tempVectorInput.set(originalEvent.pageX - window.scrollX + this.overflowLeftSize, originalEvent.pageY - window.scrollY + this.overflowTopSize, 0);
|
||||
this.spineCanvas.renderer.camera.screenToWorld(tempVectorInput, this.canvas.clientWidth, this.canvas.clientHeight);
|
||||
this.renderer.camera.screenToWorld(tempVectorInput, this.canvas.clientWidth, this.canvas.clientHeight);
|
||||
this.skeletonList.forEach(widget => {
|
||||
if (!widget.draggable || (!widget.onScreen && widget.dragX === 0 && widget.dragY === 0)) return;
|
||||
|
||||
@ -1107,7 +1118,7 @@ class SpineWebComponentOverlay extends HTMLElement {
|
||||
dragged: (x, y, ev) => {
|
||||
const originalEvent = ev instanceof MouseEvent ? ev : ev!.changedTouches[0];
|
||||
tempVectorInput.set(originalEvent.pageX - window.scrollX + this.overflowLeftSize, originalEvent.pageY - window.scrollY + this.overflowTopSize, 0);
|
||||
this.spineCanvas.renderer.camera.screenToWorld(tempVectorInput, this.canvas.clientWidth, this.canvas.clientHeight);
|
||||
this.renderer.camera.screenToWorld(tempVectorInput, this.canvas.clientWidth, this.canvas.clientHeight);
|
||||
let dragX = tempVectorInput.x - prevX;
|
||||
let dragY = tempVectorInput.y - prevY;
|
||||
this.skeletonList.forEach(widget => {
|
||||
@ -1163,7 +1174,7 @@ class SpineWebComponentOverlay extends HTMLElement {
|
||||
|
||||
this.canvas.style.width = totalWidth + "px";
|
||||
this.canvas.style.height = totalHeight + "px";
|
||||
this.spineCanvas.renderer.resize3(totalWidth, totalHeight);
|
||||
this.renderer.resize3(totalWidth, totalHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1193,7 +1204,7 @@ class SpineWebComponentOverlay extends HTMLElement {
|
||||
widget.currentScaleDpi = scale;
|
||||
|
||||
// TODO: improve this horrible thing
|
||||
this.spineCanvas.renderer.resize3(
|
||||
this.renderer.resize3(
|
||||
+this.canvas.style.width.substring(0, this.canvas.style.width.length - 2),
|
||||
+this.canvas.style.height.substring(0, this.canvas.style.height.length - 2),
|
||||
);
|
||||
@ -1225,7 +1236,7 @@ class SpineWebComponentOverlay extends HTMLElement {
|
||||
private screenToWorld(vec: Vector3, x: number, y: number) {
|
||||
vec.set(x, y, 0);
|
||||
// pay attention that clientWidth/Height rounds the size - if we don't like it, we should use getBoundingClientRect as in getPagSize
|
||||
this.spineCanvas.renderer.camera.screenToWorld(vec, this.canvas.clientWidth, this.canvas.clientHeight);
|
||||
this.renderer.camera.screenToWorld(vec, this.canvas.clientWidth, this.canvas.clientHeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user