mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-22 02:06:03 +08:00
Merge branch '4.0' into 4.1-beta
# Conflicts: # spine-ts/package-lock.json # spine-ts/package.json # spine-ts/spine-canvas/package.json # spine-ts/spine-core/package.json # spine-ts/spine-player/package.json # spine-ts/spine-threejs/package.json # spine-ts/spine-webgl/package.json
This commit is contained in:
commit
fb0a658ecf
@ -336,6 +336,7 @@
|
|||||||
* Added `SpinePlayerConfig.draw`. If set, the callback is called each frame, just after the skeleton is drawn.
|
* Added `SpinePlayerConfig.draw`. If set, the callback is called each frame, just after the skeleton is drawn.
|
||||||
* Added `SpinePlayerConfig.downloader`. The `spine.Downloader` instance can be shared between players so assets are only downloaded once.
|
* Added `SpinePlayerConfig.downloader`. The `spine.Downloader` instance can be shared between players so assets are only downloaded once.
|
||||||
* If `SpinePlayerConfig.jsonURL` ends with an anchor, the anchor text is used to find the skeleton in the specified JSON file.
|
* If `SpinePlayerConfig.jsonURL` ends with an anchor, the anchor text is used to find the skeleton in the specified JSON file.
|
||||||
|
* Added `SpinePlayer.dispose()`, disposes all CPU and GPU side resources, removes all listeners, and removes the player DOM from the parent.
|
||||||
|
|
||||||
# 3.8
|
# 3.8
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,7 @@
|
|||||||
<li><a href="/spine-player/example/embedding-binary-example.html">Embedding binary</a></li>
|
<li><a href="/spine-player/example/embedding-binary-example.html">Embedding binary</a></li>
|
||||||
<li><a href="/spine-player/example/embedding-json-example.html">Embedding JSON</a></li>
|
<li><a href="/spine-player/example/embedding-json-example.html">Embedding JSON</a></li>
|
||||||
<li><a href="/spine-player/example/editor.html">Editor</a></li>
|
<li><a href="/spine-player/example/editor.html">Editor</a></li>
|
||||||
|
<li><a href="/spine-player/example/dispose.html">Disposing a player</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<li>WebGL</li>
|
<li>WebGL</li>
|
||||||
<ul>
|
<ul>
|
||||||
|
|||||||
24
spine-ts/publish.sh
Executable file
24
spine-ts/publish.sh
Executable file
@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ ! "$#" -eq 2 ]; then
|
||||||
|
echo "Usage: ./publish.sh <last-version> <new-version>"
|
||||||
|
exit
|
||||||
|
else
|
||||||
|
lastVersion=${1%/}
|
||||||
|
newVersion=${2%/}
|
||||||
|
echo "last version: $lastVersion"
|
||||||
|
echo "new version: $newVersion"
|
||||||
|
fi
|
||||||
|
|
||||||
|
sed -i '' "s/$lastVersion/$newVersion/" package.json
|
||||||
|
sed -i '' "s/$lastVersion/$newVersion/" spine-canvas/package.json
|
||||||
|
sed -i '' "s/$lastVersion/$newVersion/" spine-core/package.json
|
||||||
|
sed -i '' "s/$lastVersion/$newVersion/" spine-player/package.json
|
||||||
|
sed -i '' "s/$lastVersion/$newVersion/" spine-threejs/package.json
|
||||||
|
sed -i '' "s/$lastVersion/$newVersion/" spine-webgl/package.json
|
||||||
|
|
||||||
|
rm -rf node_modules
|
||||||
|
rm package-lock.json
|
||||||
|
npm install
|
||||||
|
npm publish --access public --workspaces
|
||||||
49
spine-ts/spine-player/example/dispose.html
Normal file
49
spine-ts/spine-player/example/dispose.html
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<script src="../dist/iife/spine-player.js"></script>
|
||||||
|
<link rel="stylesheet" href="../css/spine-player.css">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: gray;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="container" style="width:640px; height:380px"></div>
|
||||||
|
<div>
|
||||||
|
<button id="dispose">Dispose</button>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
var player = createPlayer();
|
||||||
|
|
||||||
|
document.getElementById("dispose").addEventListener("click", event => {
|
||||||
|
console.log("Disposing player.");
|
||||||
|
player.dispose();
|
||||||
|
player = createPlayer();
|
||||||
|
});
|
||||||
|
|
||||||
|
function createPlayer() {
|
||||||
|
return new spine.SpinePlayer("container", {
|
||||||
|
skelUrl: "assets/spineboy-pro.skel",
|
||||||
|
atlasUrl: "assets/spineboy-pma.atlas",
|
||||||
|
animation: "run",
|
||||||
|
premultipliedAlpha: true,
|
||||||
|
backgroundColor: "#cccccc",
|
||||||
|
viewport: {
|
||||||
|
debugRender: true,
|
||||||
|
},
|
||||||
|
showControls: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@ -27,7 +27,7 @@
|
|||||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import { Animation, AnimationState, AnimationStateData, AtlasAttachmentLoader, Bone, Color, Downloader, MathUtils, MixBlend, MixDirection, Skeleton, SkeletonBinary, SkeletonData, SkeletonJson, StringMap, TextureAtlas, TextureFilter, TimeKeeper, TrackEntry, Vector2 } from "@esotericsoftware/spine-core"
|
import { Animation, AnimationState, AnimationStateData, AtlasAttachmentLoader, Bone, Color, Disposable, Downloader, MathUtils, MixBlend, MixDirection, 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 { AssetManager, GLTexture, Input, LoadingScreen, ManagedWebGLRenderingContext, ResizeMode, SceneRenderer, Vector3 } from "@esotericsoftware/spine-webgl"
|
||||||
|
|
||||||
export interface SpinePlayerConfig {
|
export interface SpinePlayerConfig {
|
||||||
@ -178,7 +178,7 @@ export interface Viewport {
|
|||||||
padBottom: string | number
|
padBottom: string | number
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SpinePlayer {
|
export class SpinePlayer implements Disposable {
|
||||||
public parent: HTMLElement;
|
public parent: HTMLElement;
|
||||||
public dom: HTMLElement;
|
public dom: HTMLElement;
|
||||||
public canvas: HTMLCanvasElement;
|
public canvas: HTMLCanvasElement;
|
||||||
@ -211,11 +211,13 @@ export class SpinePlayer {
|
|||||||
public speed = 1;
|
public speed = 1;
|
||||||
public time = new TimeKeeper();
|
public time = new TimeKeeper();
|
||||||
private stopRequestAnimationFrame = false;
|
private stopRequestAnimationFrame = false;
|
||||||
|
private disposed = false;
|
||||||
|
|
||||||
private viewport: Viewport = {} as Viewport;
|
private viewport: Viewport = {} as Viewport;
|
||||||
private currentViewport: Viewport;
|
private currentViewport: Viewport;
|
||||||
private previousViewport: Viewport;
|
private previousViewport: Viewport;
|
||||||
private viewportTransitionStart = 0;
|
private viewportTransitionStart = 0;
|
||||||
|
private eventListeners: Array<{ target: any, event: any, func: any }> = [];
|
||||||
|
|
||||||
constructor (parent: HTMLElement | string, private config: SpinePlayerConfig) {
|
constructor (parent: HTMLElement | string, private config: SpinePlayerConfig) {
|
||||||
this.parent = typeof parent === "string" ? document.getElementById(parent) : parent;
|
this.parent = typeof parent === "string" ? document.getElementById(parent) : parent;
|
||||||
@ -248,12 +250,29 @@ export class SpinePlayer {
|
|||||||
this.initialize();
|
this.initialize();
|
||||||
|
|
||||||
// Register a global resize handler to redraw, avoiding flicker.
|
// Register a global resize handler to redraw, avoiding flicker.
|
||||||
window.addEventListener("resize", () => this.drawFrame(false));
|
this.addEventListener(window, "resize", () => this.drawFrame(false));
|
||||||
|
|
||||||
// Start the rendering loop.
|
// Start the rendering loop.
|
||||||
requestAnimationFrame(() => this.drawFrame());
|
requestAnimationFrame(() => this.drawFrame());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dispose (): void {
|
||||||
|
this.sceneRenderer.dispose();
|
||||||
|
this.loadingScreen.dispose();
|
||||||
|
this.assetManager.dispose();
|
||||||
|
for (var i = 0; i < this.eventListeners.length; i++) {
|
||||||
|
var eventListener = this.eventListeners[i];
|
||||||
|
eventListener.target.removeEventListener(eventListener.event, eventListener.func);
|
||||||
|
}
|
||||||
|
this.parent.removeChild(this.dom);
|
||||||
|
this.disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
addEventListener (target: any, event: any, func: any) {
|
||||||
|
this.eventListeners.push({ target: target, event: event, func: func });
|
||||||
|
target.addEventListener(event, func);
|
||||||
|
}
|
||||||
|
|
||||||
private validateConfig (config: SpinePlayerConfig) {
|
private validateConfig (config: SpinePlayerConfig) {
|
||||||
if (!config) throw new Error("A configuration object must be passed to to new SpinePlayer().");
|
if (!config) throw new Error("A configuration object must be passed to to new SpinePlayer().");
|
||||||
if ((config as any).skelUrl) config.binaryUrl = (config as any).skelUrl;
|
if ((config as any).skelUrl) config.binaryUrl = (config as any).skelUrl;
|
||||||
@ -583,16 +602,17 @@ export class SpinePlayer {
|
|||||||
if (config.showControls) {
|
if (config.showControls) {
|
||||||
// For manual hover to work, we need to disable hidding controls if the mouse/touch entered the clickable area of a child of the controls.
|
// For manual hover to work, we need to disable hidding controls if the mouse/touch entered the clickable area of a child of the controls.
|
||||||
// For this we need to register a mouse handler on the document and see if we are within the canvas area.
|
// For this we need to register a mouse handler on the document and see if we are within the canvas area.
|
||||||
document.addEventListener("mousemove", (ev: UIEvent) => {
|
this.addEventListener(document, "mousemove", (ev: UIEvent) => {
|
||||||
if (ev instanceof MouseEvent) handleHover(ev.clientX, ev.clientY);
|
if (ev instanceof MouseEvent) handleHover(ev.clientX, ev.clientY);
|
||||||
});
|
});
|
||||||
document.addEventListener("touchmove", (ev: UIEvent) => {
|
this.addEventListener(document, "touchmove", (ev: UIEvent) => {
|
||||||
if (ev instanceof TouchEvent) {
|
if (ev instanceof TouchEvent) {
|
||||||
let touches = ev.changedTouches;
|
let touches = ev.changedTouches;
|
||||||
if (touches.length) {
|
if (touches.length) {
|
||||||
let touch = touches[0];
|
let touch = touches[0];
|
||||||
handleHover(touch.clientX, touch.clientY);
|
handleHover(touch.clientX, touch.clientY);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -747,6 +767,7 @@ export class SpinePlayer {
|
|||||||
private drawFrame (requestNextFrame = true) {
|
private drawFrame (requestNextFrame = true) {
|
||||||
try {
|
try {
|
||||||
if (this.error) return;
|
if (this.error) return;
|
||||||
|
if (this.disposed) return;
|
||||||
if (requestNextFrame && !this.stopRequestAnimationFrame) requestAnimationFrame(() => this.drawFrame());
|
if (requestNextFrame && !this.stopRequestAnimationFrame) requestAnimationFrame(() => this.drawFrame());
|
||||||
|
|
||||||
let doc = document as any;
|
let doc = document as any;
|
||||||
@ -1015,6 +1036,7 @@ export class SpinePlayer {
|
|||||||
class Popup {
|
class Popup {
|
||||||
public dom: HTMLElement;
|
public dom: HTMLElement;
|
||||||
private className: string;
|
private className: string;
|
||||||
|
private windowClickListener: any;
|
||||||
|
|
||||||
constructor (private id: string, private button: HTMLElement, private player: SpinePlayer, parent: HTMLElement, htmlContent: string) {
|
constructor (private id: string, private button: HTMLElement, private player: SpinePlayer, parent: HTMLElement, htmlContent: string) {
|
||||||
this.dom = createElement(/*html*/`<div class="spine-player-popup spine-player-hidden"></div>`);
|
this.dom = createElement(/*html*/`<div class="spine-player-popup spine-player-hidden"></div>`);
|
||||||
@ -1023,6 +1045,10 @@ class Popup {
|
|||||||
this.className = "spine-player-button-icon-" + id + "-selected";
|
this.className = "spine-player-button-icon-" + id + "-selected";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dispose () {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
hide (id: string): boolean {
|
hide (id: string): boolean {
|
||||||
this.dom.remove();
|
this.dom.remove();
|
||||||
this.button.classList.remove(this.className);
|
this.button.classList.remove(this.className);
|
||||||
@ -1063,7 +1089,7 @@ class Popup {
|
|||||||
dismissed = true;
|
dismissed = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
window.addEventListener("click", windowClickListener);
|
this.player.addEventListener(window, "click", windowClickListener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1074,6 +1100,7 @@ class Switch {
|
|||||||
|
|
||||||
constructor (private text: string) { }
|
constructor (private text: string) { }
|
||||||
|
|
||||||
|
|
||||||
create (): HTMLElement {
|
create (): HTMLElement {
|
||||||
this.switch = createElement(/*html*/`
|
this.switch = createElement(/*html*/`
|
||||||
<div class="spine-player-switch">
|
<div class="spine-player-switch">
|
||||||
@ -1092,7 +1119,8 @@ class Switch {
|
|||||||
setEnabled (enabled: boolean) {
|
setEnabled (enabled: boolean) {
|
||||||
if (enabled) this.switch.classList.add("active");
|
if (enabled) this.switch.classList.add("active");
|
||||||
else this.switch.classList.remove("active");
|
else this.switch.classList.remove("active");
|
||||||
this.enabled = enabled;
|
this.enabled = enabled
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
isEnabled (): boolean {
|
isEnabled (): boolean {
|
||||||
|
|||||||
@ -27,8 +27,6 @@
|
|||||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import { Pool } from "@esotericsoftware/spine-core";
|
|
||||||
|
|
||||||
export class Input {
|
export class Input {
|
||||||
element: HTMLElement;
|
element: HTMLElement;
|
||||||
mouseX = 0;
|
mouseX = 0;
|
||||||
@ -38,6 +36,7 @@ export class Input {
|
|||||||
touch1: Touch = null;
|
touch1: Touch = null;
|
||||||
initialPinchDistance = 0;
|
initialPinchDistance = 0;
|
||||||
private listeners = new Array<InputListener>();
|
private listeners = new Array<InputListener>();
|
||||||
|
private eventListeners: Array<{ target: any, event: any, func: any }> = [];
|
||||||
|
|
||||||
constructor (element: HTMLElement) {
|
constructor (element: HTMLElement) {
|
||||||
this.element = element;
|
this.element = element;
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import { Color, TimeKeeper } from "@esotericsoftware/spine-core";
|
import { Color, Disposable, TimeKeeper } from "@esotericsoftware/spine-core";
|
||||||
import { GLTexture } from "./GLTexture";
|
import { GLTexture } from "./GLTexture";
|
||||||
import { ResizeMode, SceneRenderer } from "./SceneRenderer";
|
import { ResizeMode, SceneRenderer } from "./SceneRenderer";
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ let loaded = 0;
|
|||||||
const FADE_IN = 1, FADE_OUT = 1;
|
const FADE_IN = 1, FADE_OUT = 1;
|
||||||
const logoWidth = 165, logoHeight = 108, spinnerSize = 163;
|
const logoWidth = 165, logoHeight = 108, spinnerSize = 163;
|
||||||
|
|
||||||
export class LoadingScreen {
|
export class LoadingScreen implements Disposable {
|
||||||
private renderer: SceneRenderer;
|
private renderer: SceneRenderer;
|
||||||
private logo: GLTexture = null;
|
private logo: GLTexture = null;
|
||||||
private spinner: GLTexture = null;
|
private spinner: GLTexture = null;
|
||||||
@ -69,6 +69,10 @@ export class LoadingScreen {
|
|||||||
spinnerImage.onload = onload;
|
spinnerImage.onload = onload;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dispose (): void {
|
||||||
|
this.logo.dispose();
|
||||||
|
this.spinner.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
draw (complete = false) {
|
draw (complete = false) {
|
||||||
if (loaded < 2 || (complete && this.fadeOut > FADE_OUT)) return;
|
if (loaded < 2 || (complete && this.fadeOut > FADE_OUT)) return;
|
||||||
|
|||||||
@ -73,6 +73,14 @@ export class SceneRenderer implements Disposable {
|
|||||||
this.skeletonDebugRenderer = new SkeletonDebugRenderer(this.context);
|
this.skeletonDebugRenderer = new SkeletonDebugRenderer(this.context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dispose () {
|
||||||
|
this.batcher.dispose();
|
||||||
|
this.batcherShader.dispose();
|
||||||
|
this.shapes.dispose();
|
||||||
|
this.shapesShader.dispose();
|
||||||
|
this.skeletonDebugRenderer.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
begin () {
|
begin () {
|
||||||
this.camera.update();
|
this.camera.update();
|
||||||
this.enableRenderer(this.batcher);
|
this.enableRenderer(this.batcher);
|
||||||
@ -498,14 +506,6 @@ export class SceneRenderer implements Disposable {
|
|||||||
} else
|
} else
|
||||||
this.activeRenderer = this.skeletonDebugRenderer;
|
this.activeRenderer = this.skeletonDebugRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose () {
|
|
||||||
this.batcher.dispose();
|
|
||||||
this.batcherShader.dispose();
|
|
||||||
this.shapes.dispose();
|
|
||||||
this.shapesShader.dispose();
|
|
||||||
this.skeletonDebugRenderer.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ResizeMode {
|
export enum ResizeMode {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user