mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
Merge branch '4.1' into 4.2-beta
This commit is contained in:
commit
3b66796bb7
@ -30,137 +30,136 @@
|
|||||||
import { SPINE_GAME_OBJECT_TYPE } from "./keys";
|
import { SPINE_GAME_OBJECT_TYPE } from "./keys";
|
||||||
import { SpinePlugin } from "./SpinePlugin";
|
import { SpinePlugin } from "./SpinePlugin";
|
||||||
import {
|
import {
|
||||||
ComputedSizeMixin,
|
ComputedSizeMixin,
|
||||||
DepthMixin,
|
DepthMixin,
|
||||||
FlipMixin,
|
FlipMixin,
|
||||||
ScrollFactorMixin,
|
ScrollFactorMixin,
|
||||||
TransformMixin,
|
TransformMixin,
|
||||||
VisibleMixin,
|
VisibleMixin,
|
||||||
AlphaMixin,
|
AlphaMixin,
|
||||||
OriginMixin,
|
OriginMixin,
|
||||||
} from "./mixins";
|
} from "./mixins";
|
||||||
import {
|
import {
|
||||||
AnimationState,
|
AnimationState,
|
||||||
AnimationStateData,
|
AnimationStateData,
|
||||||
Bone,
|
Bone,
|
||||||
MathUtils,
|
MathUtils,
|
||||||
Skeleton,
|
Skeleton,
|
||||||
Skin,
|
Skin,
|
||||||
Vector2,
|
Vector2,
|
||||||
} from "@esotericsoftware/spine-core";
|
} from "@esotericsoftware/spine-core";
|
||||||
|
|
||||||
class BaseSpineGameObject extends Phaser.GameObjects.GameObject {
|
class BaseSpineGameObject extends Phaser.GameObjects.GameObject {
|
||||||
constructor(scene: Phaser.Scene, type: string) {
|
constructor (scene: Phaser.Scene, type: string) {
|
||||||
super(scene, type);
|
super(scene, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A bounds provider calculates the bounding box for a skeleton, which is then assigned as the size of the SpineGameObject. */
|
/** A bounds provider calculates the bounding box for a skeleton, which is then assigned as the size of the SpineGameObject. */
|
||||||
export interface SpineGameObjectBoundsProvider {
|
export interface SpineGameObjectBoundsProvider {
|
||||||
// Returns the bounding box for the skeleton, in skeleton space.
|
// Returns the bounding box for the skeleton, in skeleton space.
|
||||||
calculateBounds(gameObject: SpineGameObject): {
|
calculateBounds (gameObject: SpineGameObject): {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A bounds provider that calculates the bounding box from the setup pose. */
|
/** A bounds provider that calculates the bounding box from the setup pose. */
|
||||||
export class SetupPoseBoundsProvider implements SpineGameObjectBoundsProvider {
|
export class SetupPoseBoundsProvider implements SpineGameObjectBoundsProvider {
|
||||||
calculateBounds(gameObject: SpineGameObject) {
|
calculateBounds (gameObject: SpineGameObject) {
|
||||||
if (!gameObject.skeleton) return { x: 0, y: 0, width: 0, height: 0 };
|
if (!gameObject.skeleton) return { x: 0, y: 0, width: 0, height: 0 };
|
||||||
// Make a copy of animation state and skeleton as this might be called while
|
// Make a copy of animation state and skeleton as this might be called while
|
||||||
// the skeleton in the GameObject has already been heavily modified. We can not
|
// the skeleton in the GameObject has already been heavily modified. We can not
|
||||||
// reconstruct that state.
|
// reconstruct that state.
|
||||||
const skeleton = new Skeleton(gameObject.skeleton.data);
|
const skeleton = new Skeleton(gameObject.skeleton.data);
|
||||||
skeleton.setToSetupPose();
|
skeleton.setToSetupPose();
|
||||||
skeleton.updateWorldTransform();
|
skeleton.updateWorldTransform();
|
||||||
const bounds = skeleton.getBoundsRect();
|
const bounds = skeleton.getBoundsRect();
|
||||||
return bounds.width == Number.NEGATIVE_INFINITY
|
return bounds.width == Number.NEGATIVE_INFINITY
|
||||||
? { x: 0, y: 0, width: 0, height: 0 }
|
? { x: 0, y: 0, width: 0, height: 0 }
|
||||||
: bounds;
|
: bounds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A bounds provider that calculates the bounding box by taking the maximumg bounding box for a combination of skins and specific animation. */
|
/** A bounds provider that calculates the bounding box by taking the maximumg bounding box for a combination of skins and specific animation. */
|
||||||
export class SkinsAndAnimationBoundsProvider
|
export class SkinsAndAnimationBoundsProvider
|
||||||
implements SpineGameObjectBoundsProvider
|
implements SpineGameObjectBoundsProvider {
|
||||||
{
|
/**
|
||||||
/**
|
* @param animation The animation to use for calculating the bounds. If null, the setup pose is used.
|
||||||
* @param animation The animation to use for calculating the bounds. If null, the setup pose is used.
|
* @param skins The skins to use for calculating the bounds. If empty, the default skin is used.
|
||||||
* @param skins The skins to use for calculating the bounds. If empty, the default skin is used.
|
* @param timeStep The time step to use for calculating the bounds. A smaller time step means more precision, but slower calculation.
|
||||||
* @param timeStep The time step to use for calculating the bounds. A smaller time step means more precision, but slower calculation.
|
*/
|
||||||
*/
|
constructor (
|
||||||
constructor(
|
private animation: string | null,
|
||||||
private animation: string | null,
|
private skins: string[] = [],
|
||||||
private skins: string[] = [],
|
private timeStep: number = 0.05
|
||||||
private timeStep: number = 0.05
|
) { }
|
||||||
) {}
|
|
||||||
|
|
||||||
calculateBounds(gameObject: SpineGameObject): {
|
calculateBounds (gameObject: SpineGameObject): {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
} {
|
} {
|
||||||
if (!gameObject.skeleton || !gameObject.animationState)
|
if (!gameObject.skeleton || !gameObject.animationState)
|
||||||
return { x: 0, y: 0, width: 0, height: 0 };
|
return { x: 0, y: 0, width: 0, height: 0 };
|
||||||
// Make a copy of animation state and skeleton as this might be called while
|
// Make a copy of animation state and skeleton as this might be called while
|
||||||
// the skeleton in the GameObject has already been heavily modified. We can not
|
// the skeleton in the GameObject has already been heavily modified. We can not
|
||||||
// reconstruct that state.
|
// reconstruct that state.
|
||||||
const animationState = new AnimationState(gameObject.animationState.data);
|
const animationState = new AnimationState(gameObject.animationState.data);
|
||||||
const skeleton = new Skeleton(gameObject.skeleton.data);
|
const skeleton = new Skeleton(gameObject.skeleton.data);
|
||||||
const data = skeleton.data;
|
const data = skeleton.data;
|
||||||
if (this.skins.length > 0) {
|
if (this.skins.length > 0) {
|
||||||
let customSkin = new Skin("custom-skin");
|
let customSkin = new Skin("custom-skin");
|
||||||
for (const skinName of this.skins) {
|
for (const skinName of this.skins) {
|
||||||
const skin = data.findSkin(skinName);
|
const skin = data.findSkin(skinName);
|
||||||
if (skin == null) continue;
|
if (skin == null) continue;
|
||||||
customSkin.addSkin(skin);
|
customSkin.addSkin(skin);
|
||||||
}
|
}
|
||||||
skeleton.setSkin(customSkin);
|
skeleton.setSkin(customSkin);
|
||||||
}
|
}
|
||||||
skeleton.setToSetupPose();
|
skeleton.setToSetupPose();
|
||||||
|
|
||||||
const animation =
|
const animation =
|
||||||
this.animation != null ? data.findAnimation(this.animation!) : null;
|
this.animation != null ? data.findAnimation(this.animation!) : null;
|
||||||
if (animation == null) {
|
if (animation == null) {
|
||||||
skeleton.updateWorldTransform();
|
skeleton.updateWorldTransform();
|
||||||
const bounds = skeleton.getBoundsRect();
|
const bounds = skeleton.getBoundsRect();
|
||||||
return bounds.width == Number.NEGATIVE_INFINITY
|
return bounds.width == Number.NEGATIVE_INFINITY
|
||||||
? { x: 0, y: 0, width: 0, height: 0 }
|
? { x: 0, y: 0, width: 0, height: 0 }
|
||||||
: bounds;
|
: bounds;
|
||||||
} else {
|
} else {
|
||||||
let minX = Number.POSITIVE_INFINITY,
|
let minX = Number.POSITIVE_INFINITY,
|
||||||
minY = Number.POSITIVE_INFINITY,
|
minY = Number.POSITIVE_INFINITY,
|
||||||
maxX = Number.NEGATIVE_INFINITY,
|
maxX = Number.NEGATIVE_INFINITY,
|
||||||
maxY = Number.NEGATIVE_INFINITY;
|
maxY = Number.NEGATIVE_INFINITY;
|
||||||
animationState.clearTracks();
|
animationState.clearTracks();
|
||||||
animationState.setAnimationWith(0, animation, false);
|
animationState.setAnimationWith(0, animation, false);
|
||||||
const steps = Math.max(animation.duration / this.timeStep, 1.0);
|
const steps = Math.max(animation.duration / this.timeStep, 1.0);
|
||||||
for (let i = 0; i < steps; i++) {
|
for (let i = 0; i < steps; i++) {
|
||||||
animationState.update(i > 0 ? this.timeStep : 0);
|
animationState.update(i > 0 ? this.timeStep : 0);
|
||||||
animationState.apply(skeleton);
|
animationState.apply(skeleton);
|
||||||
skeleton.updateWorldTransform();
|
skeleton.updateWorldTransform();
|
||||||
|
|
||||||
const bounds = skeleton.getBoundsRect();
|
const bounds = skeleton.getBoundsRect();
|
||||||
minX = Math.min(minX, bounds.x);
|
minX = Math.min(minX, bounds.x);
|
||||||
minY = Math.min(minY, bounds.y);
|
minY = Math.min(minY, bounds.y);
|
||||||
maxX = Math.max(maxX, minX + bounds.width);
|
maxX = Math.max(maxX, minX + bounds.width);
|
||||||
maxY = Math.max(maxY, minY + bounds.height);
|
maxY = Math.max(maxY, minY + bounds.height);
|
||||||
}
|
}
|
||||||
const bounds = {
|
const bounds = {
|
||||||
x: minX,
|
x: minX,
|
||||||
y: minY,
|
y: minY,
|
||||||
width: maxX - minX,
|
width: maxX - minX,
|
||||||
height: maxY - minY,
|
height: maxY - minY,
|
||||||
};
|
};
|
||||||
return bounds.width == Number.NEGATIVE_INFINITY
|
return bounds.width == Number.NEGATIVE_INFINITY
|
||||||
? { x: 0, y: 0, width: 0, height: 0 }
|
? { x: 0, y: 0, width: 0, height: 0 }
|
||||||
: bounds;
|
: bounds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -185,214 +184,214 @@ export class SkinsAndAnimationBoundsProvider
|
|||||||
* See {@link skeletonToPhaserWorldCoordinates}, {@link phaserWorldCoordinatesToSkeleton}, and {@link phaserWorldCoordinatesToBoneLocal.}
|
* See {@link skeletonToPhaserWorldCoordinates}, {@link phaserWorldCoordinatesToSkeleton}, and {@link phaserWorldCoordinatesToBoneLocal.}
|
||||||
*/
|
*/
|
||||||
export class SpineGameObject extends DepthMixin(
|
export class SpineGameObject extends DepthMixin(
|
||||||
OriginMixin(
|
OriginMixin(
|
||||||
ComputedSizeMixin(
|
ComputedSizeMixin(
|
||||||
FlipMixin(
|
FlipMixin(
|
||||||
ScrollFactorMixin(
|
ScrollFactorMixin(
|
||||||
TransformMixin(VisibleMixin(AlphaMixin(BaseSpineGameObject)))
|
TransformMixin(VisibleMixin(AlphaMixin(BaseSpineGameObject)))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
blendMode = -1;
|
blendMode = -1;
|
||||||
skeleton: Skeleton;
|
skeleton: Skeleton;
|
||||||
animationStateData: AnimationStateData;
|
animationStateData: AnimationStateData;
|
||||||
animationState: AnimationState;
|
animationState: AnimationState;
|
||||||
beforeUpdateWorldTransforms: (object: SpineGameObject) => void = () => {};
|
beforeUpdateWorldTransforms: (object: SpineGameObject) => void = () => { };
|
||||||
afterUpdateWorldTransforms: (object: SpineGameObject) => void = () => {};
|
afterUpdateWorldTransforms: (object: SpineGameObject) => void = () => { };
|
||||||
private premultipliedAlpha = false;
|
private premultipliedAlpha = false;
|
||||||
|
|
||||||
constructor(
|
constructor (
|
||||||
scene: Phaser.Scene,
|
scene: Phaser.Scene,
|
||||||
private plugin: SpinePlugin,
|
private plugin: SpinePlugin,
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
dataKey: string,
|
dataKey: string,
|
||||||
atlasKey: string,
|
atlasKey: string,
|
||||||
public boundsProvider: SpineGameObjectBoundsProvider = new SetupPoseBoundsProvider()
|
public boundsProvider: SpineGameObjectBoundsProvider = new SetupPoseBoundsProvider()
|
||||||
) {
|
) {
|
||||||
super(scene, (window as any).SPINE_GAME_OBJECT_TYPE ? (window as any).SPINE_GAME_OBJECT_TYPE : SPINE_GAME_OBJECT_TYPE);
|
super(scene, (window as any).SPINE_GAME_OBJECT_TYPE ? (window as any).SPINE_GAME_OBJECT_TYPE : SPINE_GAME_OBJECT_TYPE);
|
||||||
this.setPosition(x, y);
|
this.setPosition(x, y);
|
||||||
|
|
||||||
this.premultipliedAlpha = this.plugin.isAtlasPremultiplied(atlasKey);
|
this.premultipliedAlpha = this.plugin.isAtlasPremultiplied(atlasKey);
|
||||||
this.skeleton = this.plugin.createSkeleton(dataKey, atlasKey);
|
this.skeleton = this.plugin.createSkeleton(dataKey, atlasKey);
|
||||||
this.animationStateData = new AnimationStateData(this.skeleton.data);
|
this.animationStateData = new AnimationStateData(this.skeleton.data);
|
||||||
this.animationState = new AnimationState(this.animationStateData);
|
this.animationState = new AnimationState(this.animationStateData);
|
||||||
this.skeleton.updateWorldTransform();
|
this.skeleton.updateWorldTransform();
|
||||||
this.updateSize();
|
this.updateSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSize() {
|
updateSize () {
|
||||||
if (!this.skeleton) return;
|
if (!this.skeleton) return;
|
||||||
let bounds = this.boundsProvider.calculateBounds(this);
|
let bounds = this.boundsProvider.calculateBounds(this);
|
||||||
// For some reason the TS compiler and the ComputedSize mixin don't work well together and we have
|
// For some reason the TS compiler and the ComputedSize mixin don't work well together and we have
|
||||||
// to cast to any.
|
// to cast to any.
|
||||||
let self = this as any;
|
let self = this as any;
|
||||||
self.width = bounds.width;
|
self.width = bounds.width;
|
||||||
self.height = bounds.height;
|
self.height = bounds.height;
|
||||||
this.displayOriginX = -bounds.x;
|
this.displayOriginX = -bounds.x;
|
||||||
this.displayOriginY = -bounds.y;
|
this.displayOriginY = -bounds.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts a point from the skeleton coordinate system to the Phaser world coordinate system. */
|
/** Converts a point from the skeleton coordinate system to the Phaser world coordinate system. */
|
||||||
skeletonToPhaserWorldCoordinates(point: { x: number; y: number }) {
|
skeletonToPhaserWorldCoordinates (point: { x: number; y: number }) {
|
||||||
let transform = this.getWorldTransformMatrix();
|
let transform = this.getWorldTransformMatrix();
|
||||||
let a = transform.a,
|
let a = transform.a,
|
||||||
b = transform.b,
|
b = transform.b,
|
||||||
c = transform.c,
|
c = transform.c,
|
||||||
d = transform.d,
|
d = transform.d,
|
||||||
tx = transform.tx,
|
tx = transform.tx,
|
||||||
ty = transform.ty;
|
ty = transform.ty;
|
||||||
let x = point.x;
|
let x = point.x;
|
||||||
let y = point.y;
|
let y = point.y;
|
||||||
point.x = x * a + y * c + tx;
|
point.x = x * a + y * c + tx;
|
||||||
point.y = x * b + y * d + ty;
|
point.y = x * b + y * d + ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts a point from the Phaser world coordinate system to the skeleton coordinate system. */
|
/** Converts a point from the Phaser world coordinate system to the skeleton coordinate system. */
|
||||||
phaserWorldCoordinatesToSkeleton(point: { x: number; y: number }) {
|
phaserWorldCoordinatesToSkeleton (point: { x: number; y: number }) {
|
||||||
let transform = this.getWorldTransformMatrix();
|
let transform = this.getWorldTransformMatrix();
|
||||||
transform = transform.invert();
|
transform = transform.invert();
|
||||||
let a = transform.a,
|
let a = transform.a,
|
||||||
b = transform.b,
|
b = transform.b,
|
||||||
c = transform.c,
|
c = transform.c,
|
||||||
d = transform.d,
|
d = transform.d,
|
||||||
tx = transform.tx,
|
tx = transform.tx,
|
||||||
ty = transform.ty;
|
ty = transform.ty;
|
||||||
let x = point.x;
|
let x = point.x;
|
||||||
let y = point.y;
|
let y = point.y;
|
||||||
point.x = x * a + y * c + tx;
|
point.x = x * a + y * c + tx;
|
||||||
point.y = x * b + y * d + ty;
|
point.y = x * b + y * d + ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts a point from the Phaser world coordinate system to the bone's local coordinate system. */
|
/** Converts a point from the Phaser world coordinate system to the bone's local coordinate system. */
|
||||||
phaserWorldCoordinatesToBone(point: { x: number; y: number }, bone: Bone) {
|
phaserWorldCoordinatesToBone (point: { x: number; y: number }, bone: Bone) {
|
||||||
this.phaserWorldCoordinatesToSkeleton(point);
|
this.phaserWorldCoordinatesToSkeleton(point);
|
||||||
if (bone.parent) {
|
if (bone.parent) {
|
||||||
bone.parent.worldToLocal(point as Vector2);
|
bone.parent.worldToLocal(point as Vector2);
|
||||||
} else {
|
} else {
|
||||||
bone.worldToLocal(point as Vector2);
|
bone.worldToLocal(point as Vector2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the {@link AnimationState}, applies it to the {@link Skeleton}, then updates the world transforms of all bones.
|
* Updates the {@link AnimationState}, applies it to the {@link Skeleton}, then updates the world transforms of all bones.
|
||||||
* @param delta The time delta in milliseconds
|
* @param delta The time delta in milliseconds
|
||||||
*/
|
*/
|
||||||
updatePose(delta: number) {
|
updatePose (delta: number) {
|
||||||
this.animationState.update(delta / 1000);
|
this.animationState.update(delta / 1000);
|
||||||
this.animationState.apply(this.skeleton);
|
this.animationState.apply(this.skeleton);
|
||||||
this.beforeUpdateWorldTransforms(this);
|
this.beforeUpdateWorldTransforms(this);
|
||||||
this.skeleton.updateWorldTransform();
|
this.skeleton.updateWorldTransform();
|
||||||
this.afterUpdateWorldTransforms(this);
|
this.afterUpdateWorldTransforms(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
preUpdate(time: number, delta: number) {
|
preUpdate (time: number, delta: number) {
|
||||||
if (!this.skeleton || !this.animationState) return;
|
if (!this.skeleton || !this.animationState) return;
|
||||||
this.updatePose(delta);
|
this.updatePose(delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
preDestroy() {
|
preDestroy () {
|
||||||
// FIXME tear down any event emitters
|
// FIXME tear down any event emitters
|
||||||
}
|
}
|
||||||
|
|
||||||
willRender(camera: Phaser.Cameras.Scene2D.Camera) {
|
willRender (camera: Phaser.Cameras.Scene2D.Camera) {
|
||||||
if (!this.visible) return false;
|
if (!this.visible) return false;
|
||||||
|
|
||||||
var GameObjectRenderMask = 0xf;
|
var GameObjectRenderMask = 0xf;
|
||||||
var result = !this.skeleton || !(GameObjectRenderMask !== this.renderFlags || (this.cameraFilter !== 0 && this.cameraFilter & camera.id));
|
var result = !this.skeleton || !(GameObjectRenderMask !== this.renderFlags || (this.cameraFilter !== 0 && this.cameraFilter & camera.id));
|
||||||
|
|
||||||
if (!result && this.parentContainer && this.plugin.webGLRenderer) {
|
if (!result && this.parentContainer && this.plugin.webGLRenderer) {
|
||||||
var sceneRenderer = this.plugin.webGLRenderer;
|
var sceneRenderer = this.plugin.webGLRenderer;
|
||||||
|
|
||||||
if (this.plugin.gl && this.plugin.phaserRenderer instanceof Phaser.Renderer.WebGL.WebGLRenderer && sceneRenderer.batcher.isDrawing) {
|
if (this.plugin.gl && this.plugin.phaserRenderer instanceof Phaser.Renderer.WebGL.WebGLRenderer && sceneRenderer.batcher.isDrawing) {
|
||||||
sceneRenderer.end();
|
sceneRenderer.end();
|
||||||
this.plugin.phaserRenderer.pipelines.rebind();
|
this.plugin.phaserRenderer.pipelines.rebind();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderWebGL(
|
renderWebGL (
|
||||||
renderer: Phaser.Renderer.WebGL.WebGLRenderer,
|
renderer: Phaser.Renderer.WebGL.WebGLRenderer,
|
||||||
src: SpineGameObject,
|
src: SpineGameObject,
|
||||||
camera: Phaser.Cameras.Scene2D.Camera,
|
camera: Phaser.Cameras.Scene2D.Camera,
|
||||||
parentMatrix: Phaser.GameObjects.Components.TransformMatrix
|
parentMatrix: Phaser.GameObjects.Components.TransformMatrix
|
||||||
) {
|
) {
|
||||||
if (!this.skeleton || !this.animationState || !this.plugin.webGLRenderer)
|
if (!this.skeleton || !this.animationState || !this.plugin.webGLRenderer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let sceneRenderer = this.plugin.webGLRenderer;
|
let sceneRenderer = this.plugin.webGLRenderer;
|
||||||
if (renderer.newType) {
|
if (renderer.newType) {
|
||||||
renderer.pipelines.clear();
|
renderer.pipelines.clear();
|
||||||
sceneRenderer.begin();
|
sceneRenderer.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
camera.addToRenderList(src);
|
camera.addToRenderList(src);
|
||||||
let transform = Phaser.GameObjects.GetCalcMatrix(
|
let transform = Phaser.GameObjects.GetCalcMatrix(
|
||||||
src,
|
src,
|
||||||
camera,
|
camera,
|
||||||
parentMatrix
|
parentMatrix
|
||||||
).calc;
|
).calc;
|
||||||
let a = transform.a,
|
let a = transform.a,
|
||||||
b = transform.b,
|
b = transform.b,
|
||||||
c = transform.c,
|
c = transform.c,
|
||||||
d = transform.d,
|
d = transform.d,
|
||||||
tx = transform.tx,
|
tx = transform.tx,
|
||||||
ty = transform.ty;
|
ty = transform.ty;
|
||||||
sceneRenderer.drawSkeleton(
|
sceneRenderer.drawSkeleton(
|
||||||
this.skeleton,
|
this.skeleton,
|
||||||
this.premultipliedAlpha,
|
this.premultipliedAlpha,
|
||||||
-1,
|
-1,
|
||||||
-1,
|
-1,
|
||||||
(vertices, numVertices, stride) => {
|
(vertices, numVertices, stride) => {
|
||||||
for (let i = 0; i < numVertices; i += stride) {
|
for (let i = 0; i < numVertices; i += stride) {
|
||||||
let vx = vertices[i];
|
let vx = vertices[i];
|
||||||
let vy = vertices[i + 1];
|
let vy = vertices[i + 1];
|
||||||
vertices[i] = vx * a + vy * c + tx;
|
vertices[i] = vx * a + vy * c + tx;
|
||||||
vertices[i + 1] = vx * b + vy * d + ty;
|
vertices[i + 1] = vx * b + vy * d + ty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!renderer.nextTypeMatch) {
|
if (!renderer.nextTypeMatch) {
|
||||||
sceneRenderer.end();
|
sceneRenderer.end();
|
||||||
renderer.pipelines.rebind();
|
renderer.pipelines.rebind();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderCanvas(
|
renderCanvas (
|
||||||
renderer: Phaser.Renderer.Canvas.CanvasRenderer,
|
renderer: Phaser.Renderer.Canvas.CanvasRenderer,
|
||||||
src: SpineGameObject,
|
src: SpineGameObject,
|
||||||
camera: Phaser.Cameras.Scene2D.Camera,
|
camera: Phaser.Cameras.Scene2D.Camera,
|
||||||
parentMatrix: Phaser.GameObjects.Components.TransformMatrix
|
parentMatrix: Phaser.GameObjects.Components.TransformMatrix
|
||||||
) {
|
) {
|
||||||
if (!this.skeleton || !this.animationState || !this.plugin.canvasRenderer)
|
if (!this.skeleton || !this.animationState || !this.plugin.canvasRenderer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let context = renderer.currentContext;
|
let context = renderer.currentContext;
|
||||||
let skeletonRenderer = this.plugin.canvasRenderer;
|
let skeletonRenderer = this.plugin.canvasRenderer;
|
||||||
(skeletonRenderer as any).ctx = context;
|
(skeletonRenderer as any).ctx = context;
|
||||||
|
|
||||||
camera.addToRenderList(src);
|
camera.addToRenderList(src);
|
||||||
let transform = Phaser.GameObjects.GetCalcMatrix(
|
let transform = Phaser.GameObjects.GetCalcMatrix(
|
||||||
src,
|
src,
|
||||||
camera,
|
camera,
|
||||||
parentMatrix
|
parentMatrix
|
||||||
).calc;
|
).calc;
|
||||||
let skeleton = this.skeleton;
|
let skeleton = this.skeleton;
|
||||||
skeleton.x = transform.tx;
|
skeleton.x = transform.tx;
|
||||||
skeleton.y = transform.ty;
|
skeleton.y = transform.ty;
|
||||||
skeleton.scaleX = transform.scaleX;
|
skeleton.scaleX = transform.scaleX;
|
||||||
skeleton.scaleY = transform.scaleY;
|
skeleton.scaleY = transform.scaleY;
|
||||||
let root = skeleton.getRootBone()!;
|
let root = skeleton.getRootBone()!;
|
||||||
root.rotation = -MathUtils.radiansToDegrees * transform.rotationNormalized;
|
root.rotation = -MathUtils.radiansToDegrees * transform.rotationNormalized;
|
||||||
this.skeleton.updateWorldTransform();
|
this.skeleton.updateWorldTransform();
|
||||||
|
|
||||||
context.save();
|
context.save();
|
||||||
skeletonRenderer.draw(skeleton);
|
skeletonRenderer.draw(skeleton);
|
||||||
context.restore();
|
context.restore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -271,7 +271,7 @@ class SpineSkeletonDataFile extends Phaser.Loader.MultiFile {
|
|||||||
url = config.url;
|
url = config.url;
|
||||||
fileType = config.type === "spineJson" ? SpineSkeletonDataFileType.json : SpineSkeletonDataFileType.binary;
|
fileType = config.type === "spineJson" ? SpineSkeletonDataFileType.json : SpineSkeletonDataFileType.binary;
|
||||||
xhrSettings = config.xhrSettings;
|
xhrSettings = config.xhrSettings;
|
||||||
}
|
}
|
||||||
let file = null;
|
let file = null;
|
||||||
let isJson = fileType == SpineSkeletonDataFileType.json;
|
let isJson = fileType == SpineSkeletonDataFileType.json;
|
||||||
if (isJson) {
|
if (isJson) {
|
||||||
|
|||||||
@ -28,32 +28,32 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AnimationState,
|
AnimationState,
|
||||||
AnimationStateData,
|
AnimationStateData,
|
||||||
BlendMode,
|
BlendMode,
|
||||||
ClippingAttachment,
|
ClippingAttachment,
|
||||||
Color,
|
Color,
|
||||||
MeshAttachment,
|
MeshAttachment,
|
||||||
NumberArrayLike,
|
NumberArrayLike,
|
||||||
RegionAttachment,
|
RegionAttachment,
|
||||||
Skeleton,
|
Skeleton,
|
||||||
SkeletonClipping,
|
SkeletonClipping,
|
||||||
SkeletonData,
|
SkeletonData,
|
||||||
TextureAtlasRegion,
|
TextureAtlasRegion,
|
||||||
Utils,
|
Utils,
|
||||||
Vector2,
|
Vector2,
|
||||||
} from "@esotericsoftware/spine-core";
|
} from "@esotericsoftware/spine-core";
|
||||||
import { MeshBatcher } from "./MeshBatcher";
|
import { MeshBatcher } from "./MeshBatcher";
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { ThreeJsTexture } from "./ThreeJsTexture";
|
import { ThreeJsTexture } from "./ThreeJsTexture";
|
||||||
|
|
||||||
export type SkeletonMeshMaterialParametersCustomizer = (
|
export type SkeletonMeshMaterialParametersCustomizer = (
|
||||||
materialParameters: THREE.ShaderMaterialParameters
|
materialParameters: THREE.ShaderMaterialParameters
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
export class SkeletonMeshMaterial extends THREE.ShaderMaterial {
|
export class SkeletonMeshMaterial extends THREE.ShaderMaterial {
|
||||||
constructor(customizer: SkeletonMeshMaterialParametersCustomizer) {
|
constructor (customizer: SkeletonMeshMaterialParametersCustomizer) {
|
||||||
let vertexShader = `
|
let vertexShader = `
|
||||||
attribute vec4 color;
|
attribute vec4 color;
|
||||||
varying vec2 vUv;
|
varying vec2 vUv;
|
||||||
varying vec4 vColor;
|
varying vec4 vColor;
|
||||||
@ -63,7 +63,7 @@ export class SkeletonMeshMaterial extends THREE.ShaderMaterial {
|
|||||||
gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
|
gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
let fragmentShader = `
|
let fragmentShader = `
|
||||||
uniform sampler2D map;
|
uniform sampler2D map;
|
||||||
#ifdef USE_SPINE_ALPHATEST
|
#ifdef USE_SPINE_ALPHATEST
|
||||||
uniform float alphaTest;
|
uniform float alphaTest;
|
||||||
@ -78,253 +78,253 @@ export class SkeletonMeshMaterial extends THREE.ShaderMaterial {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
let parameters: THREE.ShaderMaterialParameters = {
|
let parameters: THREE.ShaderMaterialParameters = {
|
||||||
uniforms: {
|
uniforms: {
|
||||||
map: { value: null },
|
map: { value: null },
|
||||||
},
|
},
|
||||||
vertexShader: vertexShader,
|
vertexShader: vertexShader,
|
||||||
fragmentShader: fragmentShader,
|
fragmentShader: fragmentShader,
|
||||||
side: THREE.DoubleSide,
|
side: THREE.DoubleSide,
|
||||||
transparent: true,
|
transparent: true,
|
||||||
depthWrite: true,
|
depthWrite: true,
|
||||||
alphaTest: 0.0,
|
alphaTest: 0.0,
|
||||||
};
|
};
|
||||||
customizer(parameters);
|
customizer(parameters);
|
||||||
if (parameters.alphaTest && parameters.alphaTest > 0) {
|
if (parameters.alphaTest && parameters.alphaTest > 0) {
|
||||||
parameters.defines = { USE_SPINE_ALPHATEST: 1 };
|
parameters.defines = { USE_SPINE_ALPHATEST: 1 };
|
||||||
if (!parameters.uniforms) parameters.uniforms = {};
|
if (!parameters.uniforms) parameters.uniforms = {};
|
||||||
parameters.uniforms["alphaTest"] = { value: parameters.alphaTest };
|
parameters.uniforms["alphaTest"] = { value: parameters.alphaTest };
|
||||||
}
|
}
|
||||||
super(parameters);
|
super(parameters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SkeletonMesh extends THREE.Object3D {
|
export class SkeletonMesh extends THREE.Object3D {
|
||||||
tempPos: Vector2 = new Vector2();
|
tempPos: Vector2 = new Vector2();
|
||||||
tempUv: Vector2 = new Vector2();
|
tempUv: Vector2 = new Vector2();
|
||||||
tempLight = new Color();
|
tempLight = new Color();
|
||||||
tempDark = new Color();
|
tempDark = new Color();
|
||||||
skeleton: Skeleton;
|
skeleton: Skeleton;
|
||||||
state: AnimationState;
|
state: AnimationState;
|
||||||
zOffset: number = 0.1;
|
zOffset: number = 0.1;
|
||||||
|
|
||||||
private batches = new Array<MeshBatcher>();
|
private batches = new Array<MeshBatcher>();
|
||||||
private nextBatchIndex = 0;
|
private nextBatchIndex = 0;
|
||||||
private clipper: SkeletonClipping = new SkeletonClipping();
|
private clipper: SkeletonClipping = new SkeletonClipping();
|
||||||
|
|
||||||
static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
|
static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
|
||||||
static VERTEX_SIZE = 2 + 2 + 4;
|
static VERTEX_SIZE = 2 + 2 + 4;
|
||||||
|
|
||||||
private vertices = Utils.newFloatArray(1024);
|
private vertices = Utils.newFloatArray(1024);
|
||||||
private tempColor = new Color();
|
private tempColor = new Color();
|
||||||
|
|
||||||
constructor(
|
constructor (
|
||||||
skeletonData: SkeletonData,
|
skeletonData: SkeletonData,
|
||||||
private materialCustomerizer: SkeletonMeshMaterialParametersCustomizer = (
|
private materialCustomerizer: SkeletonMeshMaterialParametersCustomizer = (
|
||||||
material
|
material
|
||||||
) => {}
|
) => { }
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.skeleton = new Skeleton(skeletonData);
|
this.skeleton = new Skeleton(skeletonData);
|
||||||
let animData = new AnimationStateData(skeletonData);
|
let animData = new AnimationStateData(skeletonData);
|
||||||
this.state = new AnimationState(animData);
|
this.state = new AnimationState(animData);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(deltaTime: number) {
|
update (deltaTime: number) {
|
||||||
let state = this.state;
|
let state = this.state;
|
||||||
let skeleton = this.skeleton;
|
let skeleton = this.skeleton;
|
||||||
|
|
||||||
state.update(deltaTime);
|
state.update(deltaTime);
|
||||||
state.apply(skeleton);
|
state.apply(skeleton);
|
||||||
skeleton.updateWorldTransform();
|
skeleton.updateWorldTransform();
|
||||||
|
|
||||||
this.updateGeometry();
|
this.updateGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose () {
|
||||||
for (var i = 0; i < this.batches.length; i++) {
|
for (var i = 0; i < this.batches.length; i++) {
|
||||||
this.batches[i].dispose();
|
this.batches[i].dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private clearBatches() {
|
private clearBatches () {
|
||||||
for (var i = 0; i < this.batches.length; i++) {
|
for (var i = 0; i < this.batches.length; i++) {
|
||||||
this.batches[i].clear();
|
this.batches[i].clear();
|
||||||
this.batches[i].visible = false;
|
this.batches[i].visible = false;
|
||||||
}
|
}
|
||||||
this.nextBatchIndex = 0;
|
this.nextBatchIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private nextBatch() {
|
private nextBatch () {
|
||||||
if (this.batches.length == this.nextBatchIndex) {
|
if (this.batches.length == this.nextBatchIndex) {
|
||||||
let batch = new MeshBatcher(10920, this.materialCustomerizer);
|
let batch = new MeshBatcher(10920, this.materialCustomerizer);
|
||||||
this.add(batch);
|
this.add(batch);
|
||||||
this.batches.push(batch);
|
this.batches.push(batch);
|
||||||
}
|
}
|
||||||
let batch = this.batches[this.nextBatchIndex++];
|
let batch = this.batches[this.nextBatchIndex++];
|
||||||
batch.visible = true;
|
batch.visible = true;
|
||||||
return batch;
|
return batch;
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateGeometry() {
|
private updateGeometry () {
|
||||||
this.clearBatches();
|
this.clearBatches();
|
||||||
|
|
||||||
let tempPos = this.tempPos;
|
let tempPos = this.tempPos;
|
||||||
let tempUv = this.tempUv;
|
let tempUv = this.tempUv;
|
||||||
let tempLight = this.tempLight;
|
let tempLight = this.tempLight;
|
||||||
let tempDark = this.tempDark;
|
let tempDark = this.tempDark;
|
||||||
let clipper = this.clipper;
|
let clipper = this.clipper;
|
||||||
|
|
||||||
let vertices: NumberArrayLike = this.vertices;
|
let vertices: NumberArrayLike = this.vertices;
|
||||||
let triangles: Array<number> | null = null;
|
let triangles: Array<number> | null = null;
|
||||||
let uvs: NumberArrayLike | null = null;
|
let uvs: NumberArrayLike | null = null;
|
||||||
let drawOrder = this.skeleton.drawOrder;
|
let drawOrder = this.skeleton.drawOrder;
|
||||||
let batch = this.nextBatch();
|
let batch = this.nextBatch();
|
||||||
batch.begin();
|
batch.begin();
|
||||||
let z = 0;
|
let z = 0;
|
||||||
let zOffset = this.zOffset;
|
let zOffset = this.zOffset;
|
||||||
for (let i = 0, n = drawOrder.length; i < n; i++) {
|
for (let i = 0, n = drawOrder.length; i < n; i++) {
|
||||||
let vertexSize = clipper.isClipping() ? 2 : SkeletonMesh.VERTEX_SIZE;
|
let vertexSize = clipper.isClipping() ? 2 : SkeletonMesh.VERTEX_SIZE;
|
||||||
let slot = drawOrder[i];
|
let slot = drawOrder[i];
|
||||||
if (!slot.bone.active) {
|
if (!slot.bone.active) {
|
||||||
clipper.clipEndWithSlot(slot);
|
clipper.clipEndWithSlot(slot);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let attachment = slot.getAttachment();
|
let attachment = slot.getAttachment();
|
||||||
let attachmentColor: Color | null;
|
let attachmentColor: Color | null;
|
||||||
let texture: ThreeJsTexture | null;
|
let texture: ThreeJsTexture | null;
|
||||||
let numFloats = 0;
|
let numFloats = 0;
|
||||||
if (attachment instanceof RegionAttachment) {
|
if (attachment instanceof RegionAttachment) {
|
||||||
let region = <RegionAttachment>attachment;
|
let region = <RegionAttachment>attachment;
|
||||||
attachmentColor = region.color;
|
attachmentColor = region.color;
|
||||||
vertices = this.vertices;
|
vertices = this.vertices;
|
||||||
numFloats = vertexSize * 4;
|
numFloats = vertexSize * 4;
|
||||||
region.computeWorldVertices(slot, vertices, 0, vertexSize);
|
region.computeWorldVertices(slot, vertices, 0, vertexSize);
|
||||||
triangles = SkeletonMesh.QUAD_TRIANGLES;
|
triangles = SkeletonMesh.QUAD_TRIANGLES;
|
||||||
uvs = region.uvs;
|
uvs = region.uvs;
|
||||||
texture = <ThreeJsTexture>region.region!.texture;
|
texture = <ThreeJsTexture>region.region!.texture;
|
||||||
} else if (attachment instanceof MeshAttachment) {
|
} else if (attachment instanceof MeshAttachment) {
|
||||||
let mesh = <MeshAttachment>attachment;
|
let mesh = <MeshAttachment>attachment;
|
||||||
attachmentColor = mesh.color;
|
attachmentColor = mesh.color;
|
||||||
vertices = this.vertices;
|
vertices = this.vertices;
|
||||||
numFloats = (mesh.worldVerticesLength >> 1) * vertexSize;
|
numFloats = (mesh.worldVerticesLength >> 1) * vertexSize;
|
||||||
if (numFloats > vertices.length) {
|
if (numFloats > vertices.length) {
|
||||||
vertices = this.vertices = Utils.newFloatArray(numFloats);
|
vertices = this.vertices = Utils.newFloatArray(numFloats);
|
||||||
}
|
}
|
||||||
mesh.computeWorldVertices(
|
mesh.computeWorldVertices(
|
||||||
slot,
|
slot,
|
||||||
0,
|
0,
|
||||||
mesh.worldVerticesLength,
|
mesh.worldVerticesLength,
|
||||||
vertices,
|
vertices,
|
||||||
0,
|
0,
|
||||||
vertexSize
|
vertexSize
|
||||||
);
|
);
|
||||||
triangles = mesh.triangles;
|
triangles = mesh.triangles;
|
||||||
uvs = mesh.uvs;
|
uvs = mesh.uvs;
|
||||||
texture = <ThreeJsTexture>mesh.region!.texture;
|
texture = <ThreeJsTexture>mesh.region!.texture;
|
||||||
} else if (attachment instanceof ClippingAttachment) {
|
} else if (attachment instanceof ClippingAttachment) {
|
||||||
let clip = <ClippingAttachment>attachment;
|
let clip = <ClippingAttachment>attachment;
|
||||||
clipper.clipStart(slot, clip);
|
clipper.clipStart(slot, clip);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
clipper.clipEndWithSlot(slot);
|
clipper.clipEndWithSlot(slot);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (texture != null) {
|
if (texture != null) {
|
||||||
let skeleton = slot.bone.skeleton;
|
let skeleton = slot.bone.skeleton;
|
||||||
let skeletonColor = skeleton.color;
|
let skeletonColor = skeleton.color;
|
||||||
let slotColor = slot.color;
|
let slotColor = slot.color;
|
||||||
let alpha = skeletonColor.a * slotColor.a * attachmentColor.a;
|
let alpha = skeletonColor.a * slotColor.a * attachmentColor.a;
|
||||||
let color = this.tempColor;
|
let color = this.tempColor;
|
||||||
color.set(
|
color.set(
|
||||||
skeletonColor.r * slotColor.r * attachmentColor.r,
|
skeletonColor.r * slotColor.r * attachmentColor.r,
|
||||||
skeletonColor.g * slotColor.g * attachmentColor.g,
|
skeletonColor.g * slotColor.g * attachmentColor.g,
|
||||||
skeletonColor.b * slotColor.b * attachmentColor.b,
|
skeletonColor.b * slotColor.b * attachmentColor.b,
|
||||||
alpha
|
alpha
|
||||||
);
|
);
|
||||||
|
|
||||||
let finalVertices: NumberArrayLike;
|
let finalVertices: NumberArrayLike;
|
||||||
let finalVerticesLength: number;
|
let finalVerticesLength: number;
|
||||||
let finalIndices: NumberArrayLike;
|
let finalIndices: NumberArrayLike;
|
||||||
let finalIndicesLength: number;
|
let finalIndicesLength: number;
|
||||||
|
|
||||||
if (clipper.isClipping()) {
|
if (clipper.isClipping()) {
|
||||||
clipper.clipTriangles(
|
clipper.clipTriangles(
|
||||||
vertices,
|
vertices,
|
||||||
numFloats,
|
numFloats,
|
||||||
triangles,
|
triangles,
|
||||||
triangles.length,
|
triangles.length,
|
||||||
uvs,
|
uvs,
|
||||||
color,
|
color,
|
||||||
tempLight,
|
tempLight,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
let clippedVertices = clipper.clippedVertices;
|
let clippedVertices = clipper.clippedVertices;
|
||||||
let clippedTriangles = clipper.clippedTriangles;
|
let clippedTriangles = clipper.clippedTriangles;
|
||||||
finalVertices = clippedVertices;
|
finalVertices = clippedVertices;
|
||||||
finalVerticesLength = clippedVertices.length;
|
finalVerticesLength = clippedVertices.length;
|
||||||
finalIndices = clippedTriangles;
|
finalIndices = clippedTriangles;
|
||||||
finalIndicesLength = clippedTriangles.length;
|
finalIndicesLength = clippedTriangles.length;
|
||||||
} else {
|
} else {
|
||||||
let verts = vertices;
|
let verts = vertices;
|
||||||
for (
|
for (
|
||||||
let v = 2, u = 0, n = numFloats;
|
let v = 2, u = 0, n = numFloats;
|
||||||
v < n;
|
v < n;
|
||||||
v += vertexSize, u += 2
|
v += vertexSize, u += 2
|
||||||
) {
|
) {
|
||||||
verts[v] = color.r;
|
verts[v] = color.r;
|
||||||
verts[v + 1] = color.g;
|
verts[v + 1] = color.g;
|
||||||
verts[v + 2] = color.b;
|
verts[v + 2] = color.b;
|
||||||
verts[v + 3] = color.a;
|
verts[v + 3] = color.a;
|
||||||
verts[v + 4] = uvs[u];
|
verts[v + 4] = uvs[u];
|
||||||
verts[v + 5] = uvs[u + 1];
|
verts[v + 5] = uvs[u + 1];
|
||||||
}
|
}
|
||||||
finalVertices = vertices;
|
finalVertices = vertices;
|
||||||
finalVerticesLength = numFloats;
|
finalVerticesLength = numFloats;
|
||||||
finalIndices = triangles;
|
finalIndices = triangles;
|
||||||
finalIndicesLength = triangles.length;
|
finalIndicesLength = triangles.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finalVerticesLength == 0 || finalIndicesLength == 0) {
|
if (finalVerticesLength == 0 || finalIndicesLength == 0) {
|
||||||
clipper.clipEndWithSlot(slot);
|
clipper.clipEndWithSlot(slot);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start new batch if this one can't hold vertices/indices
|
// Start new batch if this one can't hold vertices/indices
|
||||||
if (
|
if (
|
||||||
!batch.canBatch(
|
!batch.canBatch(
|
||||||
finalVerticesLength / SkeletonMesh.VERTEX_SIZE,
|
finalVerticesLength / SkeletonMesh.VERTEX_SIZE,
|
||||||
finalIndicesLength
|
finalIndicesLength
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
batch.end();
|
batch.end();
|
||||||
batch = this.nextBatch();
|
batch = this.nextBatch();
|
||||||
batch.begin();
|
batch.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
const slotBlendMode = slot.data.blendMode;
|
const slotBlendMode = slot.data.blendMode;
|
||||||
const slotTexture = texture.texture;
|
const slotTexture = texture.texture;
|
||||||
const materialGroup = batch.findMaterialGroup(
|
const materialGroup = batch.findMaterialGroup(
|
||||||
slotTexture,
|
slotTexture,
|
||||||
slotBlendMode
|
slotBlendMode
|
||||||
);
|
);
|
||||||
|
|
||||||
batch.addMaterialGroup(finalIndicesLength, materialGroup);
|
batch.addMaterialGroup(finalIndicesLength, materialGroup);
|
||||||
batch.batch(
|
batch.batch(
|
||||||
finalVertices,
|
finalVertices,
|
||||||
finalVerticesLength,
|
finalVerticesLength,
|
||||||
finalIndices,
|
finalIndices,
|
||||||
finalIndicesLength,
|
finalIndicesLength,
|
||||||
z
|
z
|
||||||
);
|
);
|
||||||
z += zOffset;
|
z += zOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
clipper.clipEndWithSlot(slot);
|
clipper.clipEndWithSlot(slot);
|
||||||
}
|
}
|
||||||
clipper.clipEnd();
|
clipper.clipEnd();
|
||||||
batch.end();
|
batch.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -170,7 +170,7 @@ export class SkeletonRenderer {
|
|||||||
WebGLBlendModeConverter.getSourceColorGLBlendMode(blendMode, premultipliedAlpha),
|
WebGLBlendModeConverter.getSourceColorGLBlendMode(blendMode, premultipliedAlpha),
|
||||||
WebGLBlendModeConverter.getSourceAlphaGLBlendMode(blendMode, premultipliedAlpha),
|
WebGLBlendModeConverter.getSourceAlphaGLBlendMode(blendMode, premultipliedAlpha),
|
||||||
WebGLBlendModeConverter.getDestColorGLBlendMode(blendMode),
|
WebGLBlendModeConverter.getDestColorGLBlendMode(blendMode),
|
||||||
WebGLBlendModeConverter.getDestAlphaGLBlendMode(blendMode, premultipliedAlpha) );
|
WebGLBlendModeConverter.getDestAlphaGLBlendMode(blendMode, premultipliedAlpha));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clipper.isClipping()) {
|
if (clipper.isClipping()) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user