mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-15 03:21:35 +08:00
[phaser] WebGL and Canvas rendering, fix mixins
# Conflicts: # spine-ts/package-lock.json # spine-ts/package.json
This commit is contained in:
parent
15bbf5701e
commit
7ae9c490d5
@ -17,7 +17,7 @@
|
|||||||
"build:player": "npx copyfiles -f spine-player/css/spine-player.css spine-player/dist/ && npx npx esbuild --bundle spine-player/src/index.ts --tsconfig=spine-player/tsconfig.json --sourcemap --outfile=spine-player/dist/iife/spine-player.js --format=iife --global-name=spine",
|
"build:player": "npx copyfiles -f spine-player/css/spine-player.css spine-player/dist/ && npx npx esbuild --bundle spine-player/src/index.ts --tsconfig=spine-player/tsconfig.json --sourcemap --outfile=spine-player/dist/iife/spine-player.js --format=iife --global-name=spine",
|
||||||
"build:phaser": "npx esbuild --bundle spine-phaser/src/index.ts --tsconfig=spine-phaser/tsconfig.json --sourcemap --outfile=spine-phaser/dist/iife/spine-phaser.js --external:Phaser --alias:phaser=Phaser --format=iife --global-name=spine",
|
"build:phaser": "npx esbuild --bundle spine-phaser/src/index.ts --tsconfig=spine-phaser/tsconfig.json --sourcemap --outfile=spine-phaser/dist/iife/spine-phaser.js --external:Phaser --alias:phaser=Phaser --format=iife --global-name=spine",
|
||||||
"build:threejs": "npx esbuild --bundle spine-threejs/src/index.ts --tsconfig=spine-threejs/tsconfig.json --sourcemap --outfile=spine-threejs/dist/iife/spine-threejs.js --external:three --format=iife --global-name=spine",
|
"build:threejs": "npx esbuild --bundle spine-threejs/src/index.ts --tsconfig=spine-threejs/tsconfig.json --sourcemap --outfile=spine-threejs/dist/iife/spine-threejs.js --external:three --format=iife --global-name=spine",
|
||||||
"minify": "npx esbuild --minify spine-core/dist/iife/spine-core.js --outfile=spine-core/dist/iife/spine-core.min.js && npx esbuild --minify spine-canvas/dist/iife/spine-canvas.js --outfile=spine-canvas/dist/iife/spine-canvas.min.js && npx esbuild --minify spine-player/dist/iife/spine-player.js --outfile=spine-player/dist/iife/spine-player.min.js && npx esbuild --minify spine-webgl/dist/iife/spine-webgl.js --outfile=spine-webgl/dist/iife/spine-webgl.min.js && npx esbuild --minify spine-threejs/dist/iife/spine-threejs.js --outfile=spine-threejs/dist/iife/spine-threejs.min.js",
|
"minify": "npx esbuild --minify spine-core/dist/iife/spine-core.js --outfile=spine-core/dist/iife/spine-core.min.js && npx esbuild --minify spine-canvas/dist/iife/spine-canvas.js --outfile=spine-canvas/dist/iife/spine-canvas.min.js && npx esbuild --minify spine-player/dist/iife/spine-player.js --outfile=spine-player/dist/iife/spine-player.min.js && npx esbuild --minify spine-phaser/dist/iife/spine-phaser.js --outfile=spine-phaser/dist/iife/spine-phaser.min.js && npx esbuild --minify spine-webgl/dist/iife/spine-webgl.js --outfile=spine-webgl/dist/iife/spine-webgl.min.js && npx esbuild --minify spine-threejs/dist/iife/spine-threejs.js --outfile=spine-threejs/dist/iife/spine-threejs.min.js",
|
||||||
"dev": "concurrently \"npx live-server --no-browser\" \"npm run dev:canvas\" \"npm run dev:webgl\" \"npm run dev:phaser\" \"npm run dev:player\" \"npm run dev:threejs\"",
|
"dev": "concurrently \"npx live-server --no-browser\" \"npm run dev:canvas\" \"npm run dev:webgl\" \"npm run dev:phaser\" \"npm run dev:player\" \"npm run dev:threejs\"",
|
||||||
"dev:modules": "npm run build:modules -- --watch",
|
"dev:modules": "npm run build:modules -- --watch",
|
||||||
"dev:canvas": "npm run build:canvas -- --watch",
|
"dev:canvas": "npm run build:canvas -- --watch",
|
||||||
@ -54,13 +54,12 @@
|
|||||||
"spine-webgl"
|
"spine-webgl"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^6.2.1",
|
"@types/offscreencanvas": "^2019.6.4",
|
||||||
|
"concurrently": "^7.6.0",
|
||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
"esbuild": "^0.16.3",
|
"esbuild": "^0.16.4",
|
||||||
"live-server": "^1.2.1",
|
"live-server": "^1.2.2",
|
||||||
"npx": "^10.2.2",
|
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"typescript": "^4.3.5",
|
"typescript": "^4.9.4"
|
||||||
"@types/offscreencanvas": "^2019.6.4"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,10 +8,11 @@ var config = {
|
|||||||
type: Phaser.AUTO,
|
type: Phaser.AUTO,
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
type: Phaser.CANVAS,
|
type: Phaser.WEBGL,
|
||||||
scene: {
|
scene: {
|
||||||
preload: preload,
|
preload: preload,
|
||||||
create: create,
|
create: create,
|
||||||
|
update: update,
|
||||||
},
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
scene: [
|
scene: [
|
||||||
@ -20,18 +21,35 @@ var config = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var game = new Phaser.Game(config);
|
let game = new Phaser.Game(config);
|
||||||
|
let debug;
|
||||||
|
|
||||||
function preload () {
|
function preload () {
|
||||||
this.load.spineJson("raptor-data", "assets/raptor-pro.json");
|
this.load.spineJson("raptor-data", "assets/raptor-pro.json");
|
||||||
this.load.spineAtlas("raptor-atlas", "assets/raptor-pma.atlas");
|
this.load.spineAtlas("raptor-atlas", "assets/raptor-pma.atlas");
|
||||||
this.load.spineBinary("spineboy-data", "assets/spineboy-pro.skel");
|
this.load.spineBinary("spineboy-data", "assets/spineboy-pro.skel");
|
||||||
this.load.spineAtlas("spineboy-atlas", "assets/spineboy-pma.atlas");
|
this.load.spineAtlas("spineboy-atlas", "assets/spineboy-pma.atlas");
|
||||||
|
this.load.image("nyan", "nyan.png");
|
||||||
|
let canvas = document.querySelector("#game-canvas");
|
||||||
}
|
}
|
||||||
|
|
||||||
function create () {
|
function create () {
|
||||||
let plugin = this.spine;
|
let plugin = this.spine;
|
||||||
var raptor = this.add.spine(400, 600, 'raptor-data', "raptor-atlas");
|
let x = 25;
|
||||||
var spineboy = this.add.spine(400, 600, 'spineboy-data', "spineboy-atlas");
|
let y = 60;
|
||||||
this.add.text(10, 10, "Spine", { font: '16px Courier', fill: '#00ff00' });
|
for (let j = 0; j < 10; j++, y+= 600 / 10) {
|
||||||
|
for (let i = 0; i < 20; i++, x += 800 / 20) {
|
||||||
|
let obj = Math.random() > 0.5
|
||||||
|
? this.add.spine(x, y, 'spineboy-data', "spineboy-atlas")
|
||||||
|
: this.add.spine(x, y, 'raptor-data', "raptor-atlas");
|
||||||
|
obj.animationState.setAnimation(0, "walk", true);
|
||||||
|
obj.scale = 0.1;
|
||||||
|
}
|
||||||
|
x = 25;
|
||||||
|
}
|
||||||
|
debug = this.add.text(0, 600 - 40, "FPS: ");
|
||||||
|
}
|
||||||
|
|
||||||
|
function update () {
|
||||||
|
debug.setText("draw calls: " + spine.PolygonBatcher.getAndResetGlobalDrawCalls() + "\ndelta: " + game.loop.delta);
|
||||||
}
|
}
|
||||||
BIN
spine-ts/spine-phaser/example/nyan.png
Normal file
BIN
spine-ts/spine-phaser/example/nyan.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 563 B |
@ -1,7 +1,8 @@
|
|||||||
import { SPINE_GAME_OBJECT_TYPE } from "./keys";
|
import { SPINE_GAME_OBJECT_TYPE } from "./keys";
|
||||||
import { SpinePlugin } from "./SpinePlugin";
|
import { SpinePlugin } from "./SpinePlugin";
|
||||||
import { ComputedSizeMixin, DepthMixin, FlipMixin, ScrollFactorMixin, TransformMixin, VisibleMixin } from "./mixins";
|
import { ComputedSizeMixin, DepthMixin, FlipMixin, ScrollFactorMixin, TransformMixin, VisibleMixin } from "./mixins";
|
||||||
import { AnimationState, AnimationStateData, Skeleton } from "@esotericsoftware/spine-core";
|
import { AnimationState, AnimationStateData, MathUtils, Skeleton } from "@esotericsoftware/spine-core";
|
||||||
|
import { Matrix4, Vector3 } from "@esotericsoftware/spine-webgl";
|
||||||
|
|
||||||
class BaseSpineGameObject extends Phaser.GameObjects.GameObject {
|
class BaseSpineGameObject extends Phaser.GameObjects.GameObject {
|
||||||
constructor (scene: Phaser.Scene, type: string) {
|
constructor (scene: Phaser.Scene, type: string) {
|
||||||
@ -17,6 +18,7 @@ export class SpineGameObject extends ComputedSizeMixin(DepthMixin(FlipMixin(Scro
|
|||||||
blendMode = -1;
|
blendMode = -1;
|
||||||
skeleton: Skeleton | null = null;
|
skeleton: Skeleton | null = null;
|
||||||
animationState: AnimationState | null = null;
|
animationState: AnimationState | null = null;
|
||||||
|
private premultipliedAlpha = false;
|
||||||
|
|
||||||
constructor (scene: Phaser.Scene, private plugin: SpinePlugin, x: number, y: number, dataKey: string, atlasKey: string) {
|
constructor (scene: Phaser.Scene, private plugin: SpinePlugin, x: number, y: number, dataKey: string, atlasKey: string) {
|
||||||
super(scene, SPINE_GAME_OBJECT_TYPE);
|
super(scene, SPINE_GAME_OBJECT_TYPE);
|
||||||
@ -26,21 +28,94 @@ export class SpineGameObject extends ComputedSizeMixin(DepthMixin(FlipMixin(Scro
|
|||||||
|
|
||||||
setSkeleton (dataKey: string, atlasKey: string) {
|
setSkeleton (dataKey: string, atlasKey: string) {
|
||||||
if (dataKey && atlasKey) {
|
if (dataKey && atlasKey) {
|
||||||
|
this.premultipliedAlpha = this.plugin.isAtlasPremultiplied(atlasKey);
|
||||||
this.skeleton = this.plugin.createSkeleton(dataKey, atlasKey);
|
this.skeleton = this.plugin.createSkeleton(dataKey, atlasKey);
|
||||||
this.animationState = new AnimationState(new AnimationStateData(this.skeleton.data));
|
this.animationState = new AnimationState(new AnimationStateData(this.skeleton.data));
|
||||||
} else {
|
} else {
|
||||||
this.skeleton = null;
|
this.skeleton = null;
|
||||||
|
this.animationState = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
preUpdate (time: number, delta: number) {
|
preUpdate (time: number, delta: number) {
|
||||||
|
if (!this.skeleton || !this.animationState) return;
|
||||||
|
|
||||||
|
this.animationState.update(delta / 1000);
|
||||||
|
this.animationState.apply(this.skeleton);
|
||||||
|
this.skeleton.updateWorldTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
renderWebGL (renderer: Phaser.Renderer.WebGL.WebGLRenderer, src: SpineGameObject, camera: Phaser.Cameras.Scene2D.Camera, parentMatrix: Phaser.GameObjects.Components.TransformMatrix, container: SpineContainer) {
|
preDestroy () {
|
||||||
|
this.skeleton = null;
|
||||||
|
this.animationState = null;
|
||||||
|
// FIXME tear down any event emitters
|
||||||
|
}
|
||||||
|
|
||||||
|
willRender (camera: Phaser.Cameras.Scene2D.Camera) {
|
||||||
|
// FIXME
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderWebGL (renderer: Phaser.Renderer.WebGL.WebGLRenderer, src: SpineGameObject, camera: Phaser.Cameras.Scene2D.Camera, parentMatrix: Phaser.GameObjects.Components.TransformMatrix) {
|
||||||
|
if (!this.skeleton || !this.animationState || !this.plugin.webGLRenderer) return;
|
||||||
|
|
||||||
|
let sceneRenderer = this.plugin.webGLRenderer;
|
||||||
|
if (renderer.newType) {
|
||||||
|
renderer.pipelines.clear();
|
||||||
|
sceneRenderer.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
camera.addToRenderList(src);
|
||||||
|
let transform = Phaser.GameObjects.GetCalcMatrix(src, camera, parentMatrix).calc;
|
||||||
|
let x = transform.tx;
|
||||||
|
let y = transform.ty;
|
||||||
|
let scaleX = transform.scaleX;
|
||||||
|
let scaleY = transform.scaleY;
|
||||||
|
let rotation = transform.rotationNormalized;
|
||||||
|
let cosRotation = Math.cos(rotation);
|
||||||
|
let sinRotation = Math.sin(rotation);
|
||||||
|
|
||||||
|
sceneRenderer.drawSkeleton(this.skeleton, this.premultipliedAlpha, -1, -1, (vertices, numVertices, stride) => {
|
||||||
|
for (let i = 0; i < numVertices; i += stride) {
|
||||||
|
let vx = vertices[i];
|
||||||
|
let vy = vertices[i + 1];
|
||||||
|
let vxOld = vx * scaleX, vyOld = vy * scaleY;
|
||||||
|
vx = vxOld * cosRotation - vyOld * sinRotation;
|
||||||
|
vy = vxOld * sinRotation + vyOld * cosRotation;
|
||||||
|
vx += x;
|
||||||
|
vy += y;
|
||||||
|
vertices[i] = vx;
|
||||||
|
vertices[i + 1] = vy;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!renderer.nextTypeMatch) {
|
||||||
|
sceneRenderer.end();
|
||||||
|
renderer.pipelines.rebind();
|
||||||
|
console.log("Draw calls: " + sceneRenderer.batcher.getDrawCalls());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderCanvas (renderer: Phaser.Renderer.Canvas.CanvasRenderer, src: SpineGameObject, camera: Phaser.Cameras.Scene2D.Camera, parentMatrix: Phaser.GameObjects.Components.TransformMatrix) {
|
renderCanvas (renderer: Phaser.Renderer.Canvas.CanvasRenderer, src: SpineGameObject, camera: Phaser.Cameras.Scene2D.Camera, parentMatrix: Phaser.GameObjects.Components.TransformMatrix) {
|
||||||
|
if (!this.skeleton || !this.animationState || !this.plugin.canvasRenderer) return;
|
||||||
|
|
||||||
|
let context = renderer.currentContext;
|
||||||
|
let skeletonRenderer = this.plugin.canvasRenderer;
|
||||||
|
(skeletonRenderer as any).ctx = context;
|
||||||
|
|
||||||
|
camera.addToRenderList(src);
|
||||||
|
let transform = Phaser.GameObjects.GetCalcMatrix(src, camera, parentMatrix).calc;
|
||||||
|
let skeleton = this.skeleton;
|
||||||
|
skeleton.x = transform.tx;
|
||||||
|
skeleton.y = transform.ty;
|
||||||
|
skeleton.scaleX = transform.scaleX;
|
||||||
|
skeleton.scaleY = transform.scaleY;
|
||||||
|
let root = skeleton.getRootBone()!;
|
||||||
|
root.rotation = -MathUtils.radiansToDegrees * transform.rotationNormalized;
|
||||||
|
this.skeleton.updateWorldTransform();
|
||||||
|
|
||||||
|
context.save();
|
||||||
|
skeletonRenderer.draw(skeleton);
|
||||||
|
context.restore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -29,9 +29,9 @@
|
|||||||
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { SPINE_ATLAS_CACHE_KEY, SPINE_CONTAINER_TYPE, SPINE_GAME_OBJECT_TYPE, SPINE_ATLAS_TEXTURE_CACHE_KEY, SPINE_SKELETON_DATA_FILE_TYPE, SPINE_ATLAS_FILE_TYPE, SPINE_SKELETON_FILE_CACHE_KEY as SPINE_SKELETON_DATA_CACHE_KEY } from "./keys";
|
import { SPINE_ATLAS_CACHE_KEY, SPINE_CONTAINER_TYPE, SPINE_GAME_OBJECT_TYPE, SPINE_ATLAS_TEXTURE_CACHE_KEY, SPINE_SKELETON_DATA_FILE_TYPE, SPINE_ATLAS_FILE_TYPE, SPINE_SKELETON_FILE_CACHE_KEY as SPINE_SKELETON_DATA_CACHE_KEY } from "./keys";
|
||||||
import { AtlasAttachmentLoader, GLTexture, SceneRenderer, Skeleton, SkeletonData, SkeletonDebugRenderer, SkeletonJson, SkeletonRenderer, TextureAtlas } from "@esotericsoftware/spine-webgl"
|
import { AtlasAttachmentLoader, Bone, GLTexture, SceneRenderer, Skeleton, SkeletonBinary, SkeletonData, SkeletonJson, TextureAtlas } from "@esotericsoftware/spine-webgl"
|
||||||
import { SpineGameObject } from "./SpineGameObject";
|
import { SpineGameObject } from "./SpineGameObject";
|
||||||
import { CanvasTexture } from "@esotericsoftware/spine-canvas";
|
import { CanvasTexture, SkeletonRenderer } from "@esotericsoftware/spine-canvas";
|
||||||
|
|
||||||
export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
||||||
game: Phaser.Game;
|
game: Phaser.Game;
|
||||||
@ -39,7 +39,8 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
|||||||
gl: WebGLRenderingContext | null;
|
gl: WebGLRenderingContext | null;
|
||||||
textureManager: Phaser.Textures.TextureManager;
|
textureManager: Phaser.Textures.TextureManager;
|
||||||
phaserRenderer: Phaser.Renderer.Canvas.CanvasRenderer | Phaser.Renderer.WebGL.WebGLRenderer | null;
|
phaserRenderer: Phaser.Renderer.Canvas.CanvasRenderer | Phaser.Renderer.WebGL.WebGLRenderer | null;
|
||||||
sceneRenderer: SceneRenderer | null;
|
webGLRenderer: SceneRenderer | null;
|
||||||
|
canvasRenderer: SkeletonRenderer | null;
|
||||||
skeletonDataCache: Phaser.Cache.BaseCache;
|
skeletonDataCache: Phaser.Cache.BaseCache;
|
||||||
atlasCache: Phaser.Cache.BaseCache;
|
atlasCache: Phaser.Cache.BaseCache;
|
||||||
|
|
||||||
@ -50,7 +51,8 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
|||||||
this.gl = this.isWebGL ? (this.game.renderer as Phaser.Renderer.WebGL.WebGLRenderer).gl : null;
|
this.gl = this.isWebGL ? (this.game.renderer as Phaser.Renderer.WebGL.WebGLRenderer).gl : null;
|
||||||
this.textureManager = this.game.textures;
|
this.textureManager = this.game.textures;
|
||||||
this.phaserRenderer = this.game.renderer;
|
this.phaserRenderer = this.game.renderer;
|
||||||
this.sceneRenderer = null;
|
this.webGLRenderer = null;
|
||||||
|
this.canvasRenderer = null;
|
||||||
this.skeletonDataCache = this.game.cache.addCustom(SPINE_SKELETON_DATA_CACHE_KEY);
|
this.skeletonDataCache = this.game.cache.addCustom(SPINE_SKELETON_DATA_CACHE_KEY);
|
||||||
this.atlasCache = this.game.cache.addCustom(SPINE_ATLAS_CACHE_KEY);
|
this.atlasCache = this.game.cache.addCustom(SPINE_ATLAS_CACHE_KEY);
|
||||||
|
|
||||||
@ -116,28 +118,16 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boot () {
|
boot () {
|
||||||
|
Skeleton.yDown = true;
|
||||||
if (this.isWebGL) {
|
if (this.isWebGL) {
|
||||||
// Monkeypatch the Spine setBlendMode functions, or batching is destroyed!
|
if (!this.webGLRenderer) {
|
||||||
let setBlendMode = function (this: any, srcBlend: any, dstBlend: any) {
|
this.webGLRenderer = new SceneRenderer((this.phaserRenderer! as Phaser.Renderer.WebGL.WebGLRenderer).canvas, this.gl!, true);
|
||||||
if (srcBlend !== this.srcBlend || dstBlend !== this.dstBlend) {
|
}
|
||||||
let gl = this.context.gl;
|
this.game.scale.on(Phaser.Scale.Events.RESIZE, this.onResize, this);
|
||||||
this.srcBlend = srcBlend;
|
} else {
|
||||||
this.dstBlend = dstBlend;
|
if (!this.canvasRenderer) {
|
||||||
if (this.isDrawing) {
|
this.canvasRenderer = new SkeletonRenderer(this.scene.sys.context);
|
||||||
this.flush();
|
|
||||||
gl.blendFunc(this.srcBlend, this.dstBlend);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var sceneRenderer = this.sceneRenderer;
|
|
||||||
if (!sceneRenderer) {
|
|
||||||
sceneRenderer = new SceneRenderer((this.phaserRenderer! as Phaser.Renderer.WebGL.WebGLRenderer).canvas, this.gl!, true);
|
|
||||||
sceneRenderer.batcher.setBlendMode = setBlendMode;
|
|
||||||
(sceneRenderer as any).shapes.setBlendMode = setBlendMode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sceneRenderer = sceneRenderer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var eventEmitter = this.systems.events;
|
var eventEmitter = this.systems.events;
|
||||||
@ -148,13 +138,15 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
|||||||
|
|
||||||
onResize () {
|
onResize () {
|
||||||
var phaserRenderer = this.phaserRenderer;
|
var phaserRenderer = this.phaserRenderer;
|
||||||
var sceneRenderer = this.sceneRenderer;
|
var sceneRenderer = this.webGLRenderer;
|
||||||
|
|
||||||
if (phaserRenderer && sceneRenderer) {
|
if (phaserRenderer && sceneRenderer) {
|
||||||
var viewportWidth = phaserRenderer.width;
|
var viewportWidth = phaserRenderer.width;
|
||||||
var viewportHeight = phaserRenderer.height;
|
var viewportHeight = phaserRenderer.height;
|
||||||
sceneRenderer.camera.position.x = viewportWidth / 2;
|
sceneRenderer.camera.position.x = viewportWidth / 2;
|
||||||
sceneRenderer.camera.position.y = viewportHeight / 2;
|
sceneRenderer.camera.position.y = viewportHeight / 2;
|
||||||
|
sceneRenderer.camera.up.y = -1;
|
||||||
|
sceneRenderer.camera.direction.z = 1;
|
||||||
sceneRenderer.camera.setViewport(viewportWidth, viewportHeight);
|
sceneRenderer.camera.setViewport(viewportWidth, viewportHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,7 +165,13 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
|||||||
gameDestroy () {
|
gameDestroy () {
|
||||||
this.pluginManager.removeGameObject(SPINE_GAME_OBJECT_TYPE, true, true);
|
this.pluginManager.removeGameObject(SPINE_GAME_OBJECT_TYPE, true, true);
|
||||||
this.pluginManager.removeGameObject(SPINE_CONTAINER_TYPE, true, true);
|
this.pluginManager.removeGameObject(SPINE_CONTAINER_TYPE, true, true);
|
||||||
if (this.sceneRenderer) this.sceneRenderer.dispose();
|
if (this.webGLRenderer) this.webGLRenderer.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
isAtlasPremultiplied(atlasKey: string) {
|
||||||
|
let atlasFile = this.game.cache.text.get(atlasKey);
|
||||||
|
if (!atlasFile) return false;
|
||||||
|
return atlasFile.premultipliedAlpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
createSkeleton (dataKey: string, atlasKey: string) {
|
createSkeleton (dataKey: string, atlasKey: string) {
|
||||||
@ -181,8 +179,8 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
|||||||
if (this.atlasCache.exists(atlasKey)) {
|
if (this.atlasCache.exists(atlasKey)) {
|
||||||
atlas = this.atlasCache.get(atlasKey);
|
atlas = this.atlasCache.get(atlasKey);
|
||||||
} else {
|
} else {
|
||||||
let atlasFile = this.game.cache.text.get(atlasKey) as string;
|
let atlasFile = this.game.cache.text.get(atlasKey) as { data: string, premultipliedAlpha: boolean };
|
||||||
atlas = new TextureAtlas(atlasFile);
|
atlas = new TextureAtlas(atlasFile.data);
|
||||||
if (this.isWebGL) {
|
if (this.isWebGL) {
|
||||||
let gl = this.gl!;
|
let gl = this.gl!;
|
||||||
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
||||||
@ -207,8 +205,8 @@ export class SpinePlugin extends Phaser.Plugins.ScenePlugin {
|
|||||||
skeletonData = json.readSkeletonData(jsonFile);
|
skeletonData = json.readSkeletonData(jsonFile);
|
||||||
} else {
|
} else {
|
||||||
let binaryFile = this.game.cache.binary.get(dataKey) as ArrayBuffer;
|
let binaryFile = this.game.cache.binary.get(dataKey) as ArrayBuffer;
|
||||||
let binary = new SkeletonJson(new AtlasAttachmentLoader(atlas));
|
let binary = new SkeletonBinary(new AtlasAttachmentLoader(atlas));
|
||||||
skeletonData = binary.readSkeletonData(binaryFile);
|
skeletonData = binary.readSkeletonData(new Uint8Array(binaryFile));
|
||||||
}
|
}
|
||||||
this.skeletonDataCache.add(dataKey, skeletonData);
|
this.skeletonDataCache.add(dataKey, skeletonData);
|
||||||
}
|
}
|
||||||
@ -254,7 +252,7 @@ export class SpineSkeletonDataFile extends Phaser.Loader.MultiFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class SpineAtlasFile extends Phaser.Loader.MultiFile {
|
export class SpineAtlasFile extends Phaser.Loader.MultiFile {
|
||||||
constructor (loader: Phaser.Loader.LoaderPlugin, key: string, url: string, public premultipliedAlpha: boolean, xhrSettings: Phaser.Types.Loader.XHRSettingsObject) {
|
constructor (loader: Phaser.Loader.LoaderPlugin, key: string, url: string, public premultipliedAlpha: boolean = true, xhrSettings: Phaser.Types.Loader.XHRSettingsObject) {
|
||||||
super(loader, SPINE_ATLAS_FILE_TYPE, key, [
|
super(loader, SPINE_ATLAS_FILE_TYPE, key, [
|
||||||
new Phaser.Loader.FileTypes.TextFile(loader, {
|
new Phaser.Loader.FileTypes.TextFile(loader, {
|
||||||
key: key,
|
key: key,
|
||||||
@ -305,6 +303,10 @@ export class SpineAtlasFile extends Phaser.Loader.MultiFile {
|
|||||||
textureManager.addImage(file.key, file.data);
|
textureManager.addImage(file.key, file.data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
file.data = {
|
||||||
|
data: file.data,
|
||||||
|
premultipliedAlpha: this.premultipliedAlpha || file.data.indexOf("pma: true") >= 0
|
||||||
|
};
|
||||||
file.addToCache();
|
file.addToCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,6 @@ export * from "./require-shim"
|
|||||||
export * from "./SpinePlugin"
|
export * from "./SpinePlugin"
|
||||||
export * from "./mixins"
|
export * from "./mixins"
|
||||||
export * from "@esotericsoftware/spine-core";
|
export * from "@esotericsoftware/spine-core";
|
||||||
export * from "@esotericsoftware/spine-canvas";
|
export * from "@esotericsoftware/spine-webgl";
|
||||||
import { SpinePlugin } from "./SpinePlugin";
|
import { SpinePlugin } from "./SpinePlugin";
|
||||||
(window as any).spine = { SpinePlugin: SpinePlugin };
|
(window as any).spine = { SpinePlugin: SpinePlugin };
|
||||||
|
|||||||
@ -26,7 +26,7 @@ SOFTWARE.
|
|||||||
|
|
||||||
let components = (Phaser.GameObjects.Components as any);
|
let components = (Phaser.GameObjects.Components as any);
|
||||||
export const ComputedSize = components.ComputedSize;
|
export const ComputedSize = components.ComputedSize;
|
||||||
export const Depth = components.ComputedSize;
|
export const Depth = components.Depth;
|
||||||
export const Flip = components.Flip;
|
export const Flip = components.Flip;
|
||||||
export const ScrollFactor = components.ScrollFactor;
|
export const ScrollFactor = components.ScrollFactor;
|
||||||
export const Transform = components.Transform;
|
export const Transform = components.Transform;
|
||||||
@ -52,24 +52,11 @@ export function createMixin<
|
|||||||
...component: GameObjectComponent[]
|
...component: GameObjectComponent[]
|
||||||
): Mixin<GameObjectComponent, GameObjectConstraint> {
|
): Mixin<GameObjectComponent, GameObjectConstraint> {
|
||||||
return (BaseGameObject) => {
|
return (BaseGameObject) => {
|
||||||
applyMixins(BaseGameObject, component);
|
(Phaser as any).Class.mixin(BaseGameObject, component);
|
||||||
return BaseGameObject as any;
|
return BaseGameObject as any;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyMixins (derivedCtor: any, constructors: any[]) {
|
|
||||||
constructors.forEach((baseCtor) => {
|
|
||||||
Object.getOwnPropertyNames(baseCtor.prototype || baseCtor).forEach((name) => {
|
|
||||||
Object.defineProperty(
|
|
||||||
derivedCtor.prototype,
|
|
||||||
name,
|
|
||||||
Object.getOwnPropertyDescriptor(baseCtor.prototype || baseCtor, name) ||
|
|
||||||
Object.create(null)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
type ComputedSizeMixin = Mixin<Phaser.GameObjects.Components.Transform, Phaser.GameObjects.GameObject>;
|
type ComputedSizeMixin = Mixin<Phaser.GameObjects.Components.Transform, Phaser.GameObjects.GameObject>;
|
||||||
export const ComputedSizeMixin: ComputedSizeMixin = createMixin<Phaser.GameObjects.Components.ComputedSize>(ComputedSize);
|
export const ComputedSizeMixin: ComputedSizeMixin = createMixin<Phaser.GameObjects.Components.ComputedSize>(ComputedSize);
|
||||||
|
|
||||||
@ -77,14 +64,14 @@ type DepthMixin = Mixin<Phaser.GameObjects.Components.Depth, Phaser.GameObjects.
|
|||||||
export const DepthMixin: DepthMixin = createMixin<Phaser.GameObjects.Components.Depth>(Depth);
|
export const DepthMixin: DepthMixin = createMixin<Phaser.GameObjects.Components.Depth>(Depth);
|
||||||
|
|
||||||
type FlipMixin = Mixin<Phaser.GameObjects.Components.Flip, Phaser.GameObjects.GameObject>;
|
type FlipMixin = Mixin<Phaser.GameObjects.Components.Flip, Phaser.GameObjects.GameObject>;
|
||||||
export const FlipMixin: FlipMixin = createMixin<Phaser.GameObjects.Components.Flip>(Depth);
|
export const FlipMixin: FlipMixin = createMixin<Phaser.GameObjects.Components.Flip>(Flip);
|
||||||
|
|
||||||
type ScrollFactorMixin = Mixin<Phaser.GameObjects.Components.ScrollFactor, Phaser.GameObjects.GameObject>;
|
type ScrollFactorMixin = Mixin<Phaser.GameObjects.Components.ScrollFactor, Phaser.GameObjects.GameObject>;
|
||||||
export const ScrollFactorMixin: ScrollFactorMixin = createMixin<Phaser.GameObjects.Components.ScrollFactor>(Depth);
|
export const ScrollFactorMixin: ScrollFactorMixin = createMixin<Phaser.GameObjects.Components.ScrollFactor>(ScrollFactor);
|
||||||
|
|
||||||
type TransformMixin = Mixin<Phaser.GameObjects.Components.Transform, Phaser.GameObjects.GameObject>;
|
type TransformMixin = Mixin<Phaser.GameObjects.Components.Transform, Phaser.GameObjects.GameObject>;
|
||||||
export const TransformMixin: TransformMixin = createMixin<Phaser.GameObjects.Components.Transform>(Transform);
|
export const TransformMixin: TransformMixin = createMixin<Phaser.GameObjects.Components.Transform>(Transform);
|
||||||
|
|
||||||
type VisibleMixin = Mixin<Phaser.GameObjects.Components.Visible, Phaser.GameObjects.GameObject>;
|
type VisibleMixin = Mixin<Phaser.GameObjects.Components.Visible, Phaser.GameObjects.GameObject>;
|
||||||
export const VisibleMixin: VisibleMixin = createMixin<Phaser.GameObjects.Components.Visible>(Depth);
|
export const VisibleMixin: VisibleMixin = createMixin<Phaser.GameObjects.Components.Visible>(Visible);
|
||||||
|
|
||||||
|
|||||||
@ -36,6 +36,7 @@ import { ManagedWebGLRenderingContext } from "./WebGL";
|
|||||||
export class PolygonBatcher implements Disposable {
|
export class PolygonBatcher implements Disposable {
|
||||||
private context: ManagedWebGLRenderingContext;
|
private context: ManagedWebGLRenderingContext;
|
||||||
private drawCalls = 0;
|
private drawCalls = 0;
|
||||||
|
private static globalDrawCalls = 0;
|
||||||
private isDrawing = false;
|
private isDrawing = false;
|
||||||
private mesh: Mesh;
|
private mesh: Mesh;
|
||||||
private shader: Shader | null = null;
|
private shader: Shader | null = null;
|
||||||
@ -120,6 +121,7 @@ export class PolygonBatcher implements Disposable {
|
|||||||
this.mesh.setVerticesLength(0);
|
this.mesh.setVerticesLength(0);
|
||||||
this.mesh.setIndicesLength(0);
|
this.mesh.setIndicesLength(0);
|
||||||
this.drawCalls++;
|
this.drawCalls++;
|
||||||
|
PolygonBatcher.globalDrawCalls++;
|
||||||
}
|
}
|
||||||
|
|
||||||
end () {
|
end () {
|
||||||
@ -138,6 +140,12 @@ export class PolygonBatcher implements Disposable {
|
|||||||
return this.drawCalls;
|
return this.drawCalls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getAndResetGlobalDrawCalls () {
|
||||||
|
let result = PolygonBatcher.globalDrawCalls;
|
||||||
|
PolygonBatcher.globalDrawCalls = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
dispose () {
|
dispose () {
|
||||||
this.mesh.dispose();
|
this.mesh.dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ import { PolygonBatcher } from "./PolygonBatcher";
|
|||||||
import { Shader } from "./Shader";
|
import { Shader } from "./Shader";
|
||||||
import { ShapeRenderer } from "./ShapeRenderer";
|
import { ShapeRenderer } from "./ShapeRenderer";
|
||||||
import { SkeletonDebugRenderer } from "./SkeletonDebugRenderer";
|
import { SkeletonDebugRenderer } from "./SkeletonDebugRenderer";
|
||||||
import { SkeletonRenderer } from "./SkeletonRenderer";
|
import { SkeletonRenderer, VertexTransformer } from "./SkeletonRenderer";
|
||||||
import { ManagedWebGLRenderingContext } from "./WebGL";
|
import { ManagedWebGLRenderingContext } from "./WebGL";
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -86,10 +86,10 @@ export class SceneRenderer implements Disposable {
|
|||||||
this.enableRenderer(this.batcher);
|
this.enableRenderer(this.batcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawSkeleton (skeleton: Skeleton, premultipliedAlpha = false, slotRangeStart = -1, slotRangeEnd = -1) {
|
drawSkeleton (skeleton: Skeleton, premultipliedAlpha = false, slotRangeStart = -1, slotRangeEnd = -1, transform: VertexTransformer | null = null) {
|
||||||
this.enableRenderer(this.batcher);
|
this.enableRenderer(this.batcher);
|
||||||
this.skeletonRenderer.premultipliedAlpha = premultipliedAlpha;
|
this.skeletonRenderer.premultipliedAlpha = premultipliedAlpha;
|
||||||
this.skeletonRenderer.draw(this.batcher, skeleton, slotRangeStart, slotRangeEnd);
|
this.skeletonRenderer.draw(this.batcher, skeleton, slotRangeStart, slotRangeEnd, transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawSkeletonDebug (skeleton: Skeleton, premultipliedAlpha = false, ignoredBones?: Array<string>) {
|
drawSkeletonDebug (skeleton: Skeleton, premultipliedAlpha = false, ignoredBones?: Array<string>) {
|
||||||
|
|||||||
@ -37,6 +37,8 @@ class Renderable {
|
|||||||
constructor (public vertices: NumberArrayLike, public numVertices: number, public numFloats: number) { }
|
constructor (public vertices: NumberArrayLike, public numVertices: number, public numFloats: number) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type VertexTransformer = (vertices: NumberArrayLike, numVertices: number, stride: number) => void;
|
||||||
|
|
||||||
export class SkeletonRenderer {
|
export class SkeletonRenderer {
|
||||||
static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
|
static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
|
||||||
|
|
||||||
@ -60,7 +62,7 @@ export class SkeletonRenderer {
|
|||||||
this.vertices = Utils.newFloatArray(this.vertexSize * 1024);
|
this.vertices = Utils.newFloatArray(this.vertexSize * 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw (batcher: PolygonBatcher, skeleton: Skeleton, slotRangeStart: number = -1, slotRangeEnd: number = -1) {
|
draw (batcher: PolygonBatcher, skeleton: Skeleton, slotRangeStart: number = -1, slotRangeEnd: number = -1, transformer: VertexTransformer | null = null) {
|
||||||
let clipper = this.clipper;
|
let clipper = this.clipper;
|
||||||
let premultipliedAlpha = this.premultipliedAlpha;
|
let premultipliedAlpha = this.premultipliedAlpha;
|
||||||
let twoColorTint = this.twoColorTint;
|
let twoColorTint = this.twoColorTint;
|
||||||
@ -174,6 +176,7 @@ export class SkeletonRenderer {
|
|||||||
clipper.clipTriangles(renderable.vertices, renderable.numFloats, triangles, triangles.length, uvs, finalColor, darkColor, twoColorTint);
|
clipper.clipTriangles(renderable.vertices, renderable.numFloats, triangles, triangles.length, uvs, finalColor, darkColor, twoColorTint);
|
||||||
let clippedVertices = new Float32Array(clipper.clippedVertices);
|
let clippedVertices = new Float32Array(clipper.clippedVertices);
|
||||||
let clippedTriangles = clipper.clippedTriangles;
|
let clippedTriangles = clipper.clippedTriangles;
|
||||||
|
if (transformer) transformer(renderable.vertices, renderable.numFloats, vertexSize);
|
||||||
batcher.draw(texture, clippedVertices, clippedTriangles);
|
batcher.draw(texture, clippedVertices, clippedTriangles);
|
||||||
} else {
|
} else {
|
||||||
let verts = renderable.vertices;
|
let verts = renderable.vertices;
|
||||||
@ -201,6 +204,7 @@ export class SkeletonRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let view = (renderable.vertices as Float32Array).subarray(0, renderable.numFloats);
|
let view = (renderable.vertices as Float32Array).subarray(0, renderable.numFloats);
|
||||||
|
if (transformer) transformer(renderable.vertices, renderable.numFloats, vertexSize);
|
||||||
batcher.draw(texture, view, triangles);
|
batcher.draw(texture, view, triangles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user