feat: use custom player module

This commit is contained in:
Haoyu Xu
2025-03-23 16:38:13 +08:00
parent c6e2dd936c
commit f749de13c2
455 changed files with 1256 additions and 12936 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,286 @@
spineboy.png
size: 1024,256
format: RGBA8888
filter: Linear,Linear
repeat: none
crosshair
rotate: false
xy: 813, 160
size: 45, 45
orig: 45, 45
offset: 0, 0
index: -1
eye-indifferent
rotate: false
xy: 569, 2
size: 47, 45
orig: 47, 45
offset: 0, 0
index: -1
eye-surprised
rotate: true
xy: 643, 7
size: 47, 45
orig: 47, 45
offset: 0, 0
index: -1
front-bracer
rotate: false
xy: 811, 51
size: 29, 40
orig: 29, 40
offset: 0, 0
index: -1
front-fist-closed
rotate: false
xy: 807, 93
size: 38, 41
orig: 38, 41
offset: 0, 0
index: -1
front-fist-open
rotate: false
xy: 815, 210
size: 43, 44
orig: 43, 44
offset: 0, 0
index: -1
front-foot
rotate: true
xy: 706, 64
size: 63, 35
orig: 63, 35
offset: 0, 0
index: -1
front-shin
rotate: false
xy: 80, 11
size: 41, 92
orig: 41, 92
offset: 0, 0
index: -1
front-thigh
rotate: false
xy: 754, 12
size: 23, 56
orig: 23, 56
offset: 0, 0
index: -1
front-upper-arm
rotate: false
xy: 618, 5
size: 23, 49
orig: 23, 49
offset: 0, 0
index: -1
goggles
rotate: false
xy: 214, 20
size: 131, 83
orig: 131, 83
offset: 0, 0
index: -1
gun
rotate: true
xy: 347, 14
size: 105, 102
orig: 105, 102
offset: 0, 0
index: -1
head
rotate: false
xy: 80, 105
size: 136, 149
orig: 136, 149
offset: 0, 0
index: -1
hoverboard-board
rotate: true
xy: 2, 8
size: 246, 76
orig: 246, 76
offset: 0, 0
index: -1
hoverboard-thruster
rotate: false
xy: 478, 2
size: 30, 32
orig: 30, 32
offset: 0, 0
index: -1
hoverglow-small
rotate: true
xy: 218, 117
size: 137, 38
orig: 137, 38
offset: 0, 0
index: -1
mouth-grind
rotate: true
xy: 775, 80
size: 47, 30
orig: 47, 30
offset: 0, 0
index: -1
mouth-oooo
rotate: true
xy: 779, 31
size: 47, 30
orig: 47, 30
offset: 0, 0
index: -1
mouth-smile
rotate: true
xy: 783, 207
size: 47, 30
orig: 47, 30
offset: 0, 0
index: -1
muzzle-glow
rotate: false
xy: 779, 4
size: 25, 25
orig: 25, 25
offset: 0, 0
index: -1
muzzle-ring
rotate: false
xy: 451, 14
size: 25, 105
orig: 25, 105
offset: 0, 0
index: -1
muzzle01
rotate: true
xy: 664, 60
size: 67, 40
orig: 67, 40
offset: 0, 0
index: -1
muzzle02
rotate: true
xy: 580, 56
size: 68, 42
orig: 68, 42
offset: 0, 0
index: -1
muzzle03
rotate: true
xy: 478, 36
size: 83, 53
orig: 83, 53
offset: 0, 0
index: -1
muzzle04
rotate: true
xy: 533, 49
size: 75, 45
orig: 75, 45
offset: 0, 0
index: -1
muzzle05
rotate: true
xy: 624, 56
size: 68, 38
orig: 68, 38
offset: 0, 0
index: -1
neck
rotate: false
xy: 806, 8
size: 18, 21
orig: 18, 21
offset: 0, 0
index: -1
portal-bg
rotate: false
xy: 258, 121
size: 133, 133
orig: 133, 133
offset: 0, 0
index: -1
portal-flare1
rotate: true
xy: 690, 2
size: 56, 30
orig: 56, 30
offset: 0, 0
index: -1
portal-flare2
rotate: false
xy: 510, 3
size: 57, 31
orig: 57, 31
offset: 0, 0
index: -1
portal-flare3
rotate: true
xy: 722, 4
size: 58, 30
orig: 58, 30
offset: 0, 0
index: -1
portal-shade
rotate: false
xy: 393, 121
size: 133, 133
orig: 133, 133
offset: 0, 0
index: -1
portal-streaks1
rotate: false
xy: 528, 126
size: 126, 128
orig: 126, 128
offset: 0, 0
index: -1
portal-streaks2
rotate: false
xy: 656, 129
size: 125, 125
orig: 125, 125
offset: 0, 0
index: -1
rear-bracer
rotate: false
xy: 826, 13
size: 28, 36
orig: 28, 36
offset: 0, 0
index: -1
rear-foot
rotate: true
xy: 743, 70
size: 57, 30
orig: 57, 30
offset: 0, 0
index: -1
rear-shin
rotate: false
xy: 174, 14
size: 38, 89
orig: 38, 89
offset: 0, 0
index: -1
rear-thigh
rotate: false
xy: 783, 158
size: 28, 47
orig: 28, 47
offset: 0, 0
index: -1
rear-upper-arm
rotate: true
xy: 783, 136
size: 20, 44
orig: 20, 44
offset: 0, 0
index: -1
torso
rotate: false
xy: 123, 13
size: 49, 90
orig: 49, 90
offset: 0, 0
index: -1

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

View File

@@ -0,0 +1,168 @@
<html>
<script src="../../build/spine-canvas.js"></script>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<style>
* { margin: 0; padding: 0; }
body, html { height: 100% }
canvas { position: absolute; width: 100% ;height: 100%; }
</style>
<body>
<canvas id="canvas"></canvas>
</body>
<script>
var lastFrameTime = Date.now() / 1000;
var canvas, context;
var assetManager;
var skeleton, state, bounds;
var skeletonRenderer;
var skelName = "spineboy-ess";
var animName = "walk";
function init () {
canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
context = canvas.getContext("2d");
skeletonRenderer = new spine.canvas.SkeletonRenderer(context);
// enable debug rendering
skeletonRenderer.debugRendering = true;
// enable the triangle renderer, supports meshes, but may produce artifacts in some browsers
skeletonRenderer.triangleRendering = false;
assetManager = new spine.canvas.AssetManager();
assetManager.loadText("assets/" + skelName + ".json");
assetManager.loadText("assets/" + skelName.replace("-pro", "").replace("-ess", "") + ".atlas");
assetManager.loadTexture("assets/" + skelName.replace("-pro", "").replace("-ess", "") + ".png");
requestAnimationFrame(load);
}
function load () {
if (assetManager.isLoadingComplete()) {
var data = loadSkeleton(skelName, animName, "default");
skeleton = data.skeleton;
state = data.state;
bounds = data.bounds;
requestAnimationFrame(render);
} else {
requestAnimationFrame(load);
}
}
function loadSkeleton (name, initialAnimation, skin) {
if (skin === undefined) skin = "default";
// Load the texture atlas using name.atlas and name.png from the AssetManager.
// The function passed to TextureAtlas is used to resolve relative paths.
atlas = new spine.TextureAtlas(assetManager.get("assets/" + name.replace("-pro", "").replace("-ess", "") + ".atlas"), function(path) {
return assetManager.get("assets/" + path);
});
// Create a AtlasAttachmentLoader, which is specific to the WebGL backend.
atlasLoader = new spine.AtlasAttachmentLoader(atlas);
// Create a SkeletonJson instance for parsing the .json file.
var skeletonJson = new spine.SkeletonJson(atlasLoader);
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
var skeletonData = skeletonJson.readSkeletonData(assetManager.get("assets/" + name + ".json"));
var skeleton = new spine.Skeleton(skeletonData);
skeleton.scaleY = -1;
var bounds = calculateBounds(skeleton);
skeleton.setSkinByName(skin);
// Create an AnimationState, and set the initial animation in looping mode.
var animationState = new spine.AnimationState(new spine.AnimationStateData(skeleton.data));
animationState.setAnimation(0, initialAnimation, true);
animationState.addListener({
event: function(trackIndex, event) {
// console.log("Event on track " + trackIndex + ": " + JSON.stringify(event));
},
complete: function(trackIndex, loopCount) {
// console.log("Animation on track " + trackIndex + " completed, loop count: " + loopCount);
},
start: function(trackIndex) {
// console.log("Animation on track " + trackIndex + " started");
},
end: function(trackIndex) {
// console.log("Animation on track " + trackIndex + " ended");
}
})
// Pack everything up and return to caller.
return { skeleton: skeleton, state: animationState, bounds: bounds };
}
function calculateBounds(skeleton) {
var data = skeleton.data;
skeleton.setToSetupPose();
skeleton.updateWorldTransform();
var offset = new spine.Vector2();
var size = new spine.Vector2();
skeleton.getBounds(offset, size, []);
return { offset: offset, size: size };
}
function render () {
var now = Date.now() / 1000;
var delta = now - lastFrameTime;
lastFrameTime = now;
resize();
context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.fillStyle = "#cccccc";
context.fillRect(0, 0, canvas.width, canvas.height);
context.restore();
state.update(delta);
state.apply(skeleton);
skeleton.updateWorldTransform();
skeletonRenderer.draw(skeleton);
context.strokeStyle = "green";
context.beginPath();
context.moveTo(-1000, 0);
context.lineTo(1000, 0);
context.moveTo(0, -1000);
context.lineTo(0, 1000);
context.stroke();
requestAnimationFrame(render);
}
function resize () {
var w = canvas.clientWidth;
var h = canvas.clientHeight;
if (canvas.width != w || canvas.height != h) {
canvas.width = w;
canvas.height = h;
}
// magic
var centerX = bounds.offset.x + bounds.size.x / 2;
var centerY = bounds.offset.y + bounds.size.y / 2;
var scaleX = bounds.size.x / canvas.width;
var scaleY = bounds.size.y / canvas.height;
var scale = Math.max(scaleX, scaleY) * 1.2;
if (scale < 1) scale = 1;
var width = canvas.width * scale;
var height = canvas.height * scale;
context.setTransform(1, 0, 0, 1, 0, 0);
context.scale(1 / scale, 1 / scale);
context.translate(-centerX, -centerY);
context.translate(width / 2, height / 2);
}
(function() {
init();
}());
</script>
</html>

View File

@@ -0,0 +1,38 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
/// <reference path="../../core/src/AssetManager.ts"/>
module spine.canvas {
export class AssetManager extends spine.AssetManager {
constructor (pathPrefix: string = "") {
super((image: HTMLImageElement) => { return new spine.canvas.CanvasTexture(image); }, pathPrefix);
}
}
}

View File

@@ -0,0 +1,42 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
/// <reference path="../../core/src/Texture.ts"/>
module spine.canvas {
export class CanvasTexture extends Texture {
constructor (image: HTMLImageElement) {
super(image);
}
setFilters (minFilter: TextureFilter, magFilter: TextureFilter) { }
setWraps (uWrap: TextureWrap, vWrap: TextureWrap) { }
dispose () { }
}
}

View File

@@ -0,0 +1,323 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
module spine.canvas {
export class SkeletonRenderer {
static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
static VERTEX_SIZE = 2 + 2 + 4;
private ctx: CanvasRenderingContext2D;
public triangleRendering = false;
public debugRendering = false;
private vertices = Utils.newFloatArray(8 * 1024);
private tempColor = new Color();
constructor (context: CanvasRenderingContext2D) {
this.ctx = context;
}
draw (skeleton: Skeleton) {
if (this.triangleRendering) this.drawTriangles(skeleton);
else this.drawImages(skeleton);
}
private drawImages (skeleton: Skeleton) {
let ctx = this.ctx;
let drawOrder = skeleton.drawOrder;
if (this.debugRendering) ctx.strokeStyle = "green";
ctx.save();
for (let i = 0, n = drawOrder.length; i < n; i++) {
let slot = drawOrder[i];
if (!slot.bone.active) continue;
let attachment = slot.getAttachment();
let regionAttachment: RegionAttachment = null;
let region: TextureAtlasRegion = null;
let image: HTMLImageElement = null;
if (attachment instanceof RegionAttachment) {
regionAttachment = <RegionAttachment>attachment;
region = <TextureAtlasRegion>regionAttachment.region;
image = (<CanvasTexture>region.texture).getImage() as HTMLImageElement;
} else continue;
let skeleton = slot.bone.skeleton;
let skeletonColor = skeleton.color;
let slotColor = slot.color;
let regionColor = regionAttachment.color;
let alpha = skeletonColor.a * slotColor.a * regionColor.a;
let color = this.tempColor;
color.set(skeletonColor.r * slotColor.r * regionColor.r,
skeletonColor.g * slotColor.g * regionColor.g,
skeletonColor.b * slotColor.b * regionColor.b,
alpha);
let att = <RegionAttachment>attachment;
let bone = slot.bone;
let w = region.width;
let h = region.height;
ctx.save();
ctx.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY);
ctx.translate(attachment.offset[0], attachment.offset[1]);
ctx.rotate(attachment.rotation * Math.PI / 180);
let atlasScale = att.width / w;
ctx.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY);
ctx.translate(w / 2, h / 2);
if (attachment.region.rotate) {
let t = w;
w = h;
h = t;
ctx.rotate(-Math.PI / 2);
}
ctx.scale(1, -1);
ctx.translate(-w / 2, -h / 2);
ctx.globalAlpha = color.a;
// experimental tinting via compositing, doesn't work
// ctx.globalCompositeOperation = "source-atop";
// ctx.fillStyle = "rgba(" + (color.r * 255 | 0) + ", " + (color.g * 255 | 0) + ", " + (color.b * 255 | 0) + ", " + color.a + ")";
// ctx.fillRect(0, 0, w, h);
ctx.drawImage(image, region.x, region.y, w, h, 0, 0, w, h);
if (this.debugRendering) ctx.strokeRect(0, 0, w, h);
ctx.restore();
}
ctx.restore();
}
private drawTriangles (skeleton: Skeleton) {
let blendMode: BlendMode = null;
let vertices: ArrayLike<number> = this.vertices;
let triangles: Array<number> = null;
let drawOrder = skeleton.drawOrder;
for (let i = 0, n = drawOrder.length; i < n; i++) {
let slot = drawOrder[i];
let attachment = slot.getAttachment();
let texture: HTMLImageElement = null;
let region: TextureAtlasRegion = null;
if (attachment instanceof RegionAttachment) {
let regionAttachment = <RegionAttachment>attachment;
vertices = this.computeRegionVertices(slot, regionAttachment, false);
triangles = SkeletonRenderer.QUAD_TRIANGLES;
region = <TextureAtlasRegion>regionAttachment.region;
texture = (<CanvasTexture>region.texture).getImage() as HTMLImageElement;
} else if (attachment instanceof MeshAttachment) {
let mesh = <MeshAttachment>attachment;
vertices = this.computeMeshVertices(slot, mesh, false);
triangles = mesh.triangles;
texture = (<TextureAtlasRegion>mesh.region.renderObject).texture.getImage() as HTMLImageElement;
} else continue;
if (texture != null) {
let slotBlendMode = slot.data.blendMode;
if (slotBlendMode != blendMode) {
blendMode = slotBlendMode;
}
let skeleton = slot.bone.skeleton;
let skeletonColor = skeleton.color;
let slotColor = slot.color;
let attachmentColor = attachment.color;
let alpha = skeletonColor.a * slotColor.a * attachmentColor.a;
let color = this.tempColor;
color.set(skeletonColor.r * slotColor.r * attachmentColor.r,
skeletonColor.g * slotColor.g * attachmentColor.g,
skeletonColor.b * slotColor.b * attachmentColor.b,
alpha);
let ctx = this.ctx;
ctx.globalAlpha = color.a;
// experimental tinting via compositing, doesn't work
// ctx.globalCompositeOperation = "source-atop";
// ctx.fillStyle = "rgba(" + (color.r * 255 | 0) + ", " + (color.g * 255 | 0) + ", " + (color.b * 255 | 0) + ", " + color.a + ")";
// ctx.fillRect(0, 0, w, h);
for (var j = 0; j < triangles.length; j+=3) {
let t1 = triangles[j] * 8, t2 = triangles[j+1] * 8, t3 = triangles[j+2] * 8;
let x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7];
let x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7];
let x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7];
this.drawTriangle(texture, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2);
if (this.debugRendering) {
ctx.strokeStyle = "green";
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x0, y0);
ctx.stroke();
}
}
}
}
this.ctx.globalAlpha = 1;
}
// Adapted from http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
// Apache 2 licensed
private drawTriangle(img: HTMLImageElement, x0: number, y0: number, u0: number, v0: number,
x1: number, y1: number, u1: number, v1: number,
x2: number, y2: number, u2: number, v2: number) {
let ctx = this.ctx;
u0 *= img.width;
v0 *= img.height;
u1 *= img.width;
v1 *= img.height;
u2 *= img.width;
v2 *= img.height;
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.closePath();
x1 -= x0;
y1 -= y0;
x2 -= x0;
y2 -= y0;
u1 -= u0;
v1 -= v0;
u2 -= u0;
v2 -= v0;
var det = 1 / (u1*v2 - u2*v1),
// linear transformation
a = (v2*x1 - v1*x2) * det,
b = (v2*y1 - v1*y2) * det,
c = (u1*x2 - u2*x1) * det,
d = (u1*y2 - u2*y1) * det,
// translation
e = x0 - a*u0 - c*v0,
f = y0 - b*u0 - d*v0;
ctx.save();
ctx.transform(a, b, c, d, e, f);
ctx.clip();
ctx.drawImage(img, 0, 0);
ctx.restore();
}
private computeRegionVertices(slot: Slot, region: RegionAttachment, pma: boolean) {
let skeleton = slot.bone.skeleton;
let skeletonColor = skeleton.color;
let slotColor = slot.color;
let regionColor = region.color;
let alpha = skeletonColor.a * slotColor.a * regionColor.a;
let multiplier = pma ? alpha : 1;
let color = this.tempColor;
color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier,
skeletonColor.g * slotColor.g * regionColor.g * multiplier,
skeletonColor.b * slotColor.b * regionColor.b * multiplier,
alpha);
region.computeWorldVertices(slot.bone, this.vertices, 0, SkeletonRenderer.VERTEX_SIZE);
let vertices = this.vertices;
let uvs = region.uvs;
vertices[RegionAttachment.C1R] = color.r;
vertices[RegionAttachment.C1G] = color.g;
vertices[RegionAttachment.C1B] = color.b;
vertices[RegionAttachment.C1A] = color.a;
vertices[RegionAttachment.U1] = uvs[0];
vertices[RegionAttachment.V1] = uvs[1];
vertices[RegionAttachment.C2R] = color.r;
vertices[RegionAttachment.C2G] = color.g;
vertices[RegionAttachment.C2B] = color.b;
vertices[RegionAttachment.C2A] = color.a;
vertices[RegionAttachment.U2] = uvs[2];
vertices[RegionAttachment.V2] = uvs[3];
vertices[RegionAttachment.C3R] = color.r;
vertices[RegionAttachment.C3G] = color.g;
vertices[RegionAttachment.C3B] = color.b;
vertices[RegionAttachment.C3A] = color.a;
vertices[RegionAttachment.U3] = uvs[4];
vertices[RegionAttachment.V3] = uvs[5];
vertices[RegionAttachment.C4R] = color.r;
vertices[RegionAttachment.C4G] = color.g;
vertices[RegionAttachment.C4B] = color.b;
vertices[RegionAttachment.C4A] = color.a;
vertices[RegionAttachment.U4] = uvs[6];
vertices[RegionAttachment.V4] = uvs[7];
return vertices;
}
private computeMeshVertices(slot: Slot, mesh: MeshAttachment, pma: boolean) {
let skeleton = slot.bone.skeleton;
let skeletonColor = skeleton.color;
let slotColor = slot.color;
let regionColor = mesh.color;
let alpha = skeletonColor.a * slotColor.a * regionColor.a;
let multiplier = pma ? alpha : 1;
let color = this.tempColor;
color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier,
skeletonColor.g * slotColor.g * regionColor.g * multiplier,
skeletonColor.b * slotColor.b * regionColor.b * multiplier,
alpha);
let numVertices = mesh.worldVerticesLength / 2;
if (this.vertices.length < mesh.worldVerticesLength) {
this.vertices = Utils.newFloatArray(mesh.worldVerticesLength);
}
let vertices = this.vertices;
mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, SkeletonRenderer.VERTEX_SIZE);
let uvs = mesh.uvs;
for (let i = 0, n = numVertices, u = 0, v = 2; i < n; i++) {
vertices[v++] = color.r;
vertices[v++] = color.g;
vertices[v++] = color.b;
vertices[v++] = color.a;
vertices[v++] = uvs[u++];
vertices[v++] = uvs[u++];
v += 2;
}
return vertices;
}
}
}