@melonjs/spine-plugin 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +2 -2
- package/dist/@melonjs/spine-plugin.d.ts +3 -3
- package/dist/@melonjs/spine-plugin.js +159 -55
- package/package.json +18 -17
- package/src/SkeletonRenderer.js +161 -57
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.3.0 - 2023-08-28å
|
|
4
|
+
|
|
5
|
+
- add support for Mesh Attachement
|
|
6
|
+
- added more examples under the test folder and separated them into individual files
|
|
7
|
+
- add a fullscreen option to examples (pressing the "F" key toggles fullscreen mode)
|
|
8
|
+
|
|
9
|
+
## 1.2.1 - 2023-08-23
|
|
10
|
+
|
|
11
|
+
- code refactoring and optimization to prepare for future feature additions
|
|
12
|
+
- fix URLs in the package.json file
|
|
13
|
+
|
|
14
|
+
## 1.2.0 - 2023-08-22
|
|
15
|
+
|
|
16
|
+
- add support for clipping (coin example is now rendered properly)
|
|
17
|
+
|
|
18
|
+
## 1.1.0 - 2023-08-19
|
|
19
|
+
|
|
20
|
+
- add some basic debug rendering
|
|
21
|
+
- optimize code (remove unneeded logic)
|
|
22
|
+
|
|
23
|
+
## 1.0.0 - 2023-08-16
|
|
24
|
+
|
|
25
|
+
initial release
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# melonJS Spine Plugin
|
|
2
2
|
|
|
3
|
-
a [Spine](http://en.esotericsoftware.com/spine-in-depth) 4.1 plugin implementation for [melonJS 2](www.melonjs.org)
|
|
3
|
+
a [Spine](http://en.esotericsoftware.com/spine-in-depth) 4.1 plugin implementation for [melonJS 2](http://www.melonjs.org)
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ a [Spine](http://en.esotericsoftware.com/spine-in-depth) 4.1 plugin implementati
|
|
|
14
14
|
Installation
|
|
15
15
|
-------------------------------------------------------------------------------
|
|
16
16
|
this plugin is already bundled with the required Spine runtime, so there is no need to install it separately.
|
|
17
|
-
>Note: this plugin requires melonJS version 15.9 or higher.
|
|
17
|
+
>Note: this plugin requires melonJS version 15.9.2 or higher.
|
|
18
18
|
|
|
19
19
|
To install the plugin using npm :
|
|
20
20
|
|
|
@@ -4070,17 +4070,17 @@ declare class CanvasTexture extends Texture {
|
|
|
4070
4070
|
}
|
|
4071
4071
|
declare class SkeletonRenderer {
|
|
4072
4072
|
constructor(runtime: any);
|
|
4073
|
-
isWebGLRenderer: any;
|
|
4074
4073
|
skeletonRenderer: any;
|
|
4075
4074
|
runtime: any;
|
|
4076
|
-
tempColor: Color;
|
|
4077
4075
|
tintColor: Color$1;
|
|
4078
|
-
|
|
4076
|
+
tempColor: Color$1;
|
|
4079
4077
|
debugRendering: boolean;
|
|
4080
4078
|
clipper: SkeletonClipping;
|
|
4081
4079
|
clippingVertices: any[];
|
|
4082
4080
|
clippingMask: Polygon;
|
|
4083
4081
|
draw(renderer: any, skeleton: any): void;
|
|
4082
|
+
drawTriangle(renderer: any, img: any, x0: any, y0: any, u0: any, v0: any, x1: any, y1: any, u1: any, v1: any, x2: any, y2: any, u2: any, v2: any): void;
|
|
4083
|
+
computeMeshVertices(slot: any, mesh: any, pma: boolean | undefined, vertexSize: any): void;
|
|
4084
4084
|
}
|
|
4085
4085
|
import { Vector2d } from 'melonjs';
|
|
4086
4086
|
/******************************************************************************
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* melonJS Spine plugin - v1.
|
|
2
|
+
* melonJS Spine plugin - v1.3.0
|
|
3
3
|
* http://www.melonjs.org
|
|
4
4
|
* @melonjs/spine-plugin is licensed under the MIT License.
|
|
5
5
|
* http://www.opensource.org/licenses/mit-license
|
|
@@ -14929,16 +14929,19 @@ class AssetManager {
|
|
|
14929
14929
|
}
|
|
14930
14930
|
}
|
|
14931
14931
|
|
|
14932
|
-
const
|
|
14932
|
+
const vertexSize = 2 + 2 + 4;
|
|
14933
14933
|
const blendModeLUT = ["normal", "additive", "multiply", "screen"];
|
|
14934
|
+
const regionDebugColor = "green";
|
|
14935
|
+
const meshDebugColor = "yellow";
|
|
14936
|
+
const clipDebugColor = "blue";
|
|
14937
|
+
|
|
14938
|
+
let worldVertices = new Float32Array(vertexSize * 1024);
|
|
14934
14939
|
|
|
14935
14940
|
class SkeletonRenderer {
|
|
14936
|
-
isWebGLRenderer;
|
|
14937
14941
|
skeletonRenderer;
|
|
14938
14942
|
runtime;
|
|
14939
|
-
tempColor = new Color();
|
|
14940
14943
|
tintColor = new Color$1();
|
|
14941
|
-
|
|
14944
|
+
tempColor = new Color$1();
|
|
14942
14945
|
debugRendering = false;
|
|
14943
14946
|
clipper = new SkeletonClipping();
|
|
14944
14947
|
clippingVertices = [];
|
|
@@ -14947,18 +14950,22 @@ class SkeletonRenderer {
|
|
|
14947
14950
|
constructor(runtime) {
|
|
14948
14951
|
this.runtime = runtime;
|
|
14949
14952
|
this.skeletonRenderer = new runtime.SkeletonRenderer();
|
|
14950
|
-
this.tempColor = new Color();
|
|
14951
14953
|
}
|
|
14952
14954
|
|
|
14953
14955
|
draw(renderer, skeleton) {
|
|
14954
14956
|
let clipper = this.clipper;
|
|
14955
14957
|
let drawOrder = skeleton.drawOrder;
|
|
14956
14958
|
let skeletonColor = skeleton.color;
|
|
14959
|
+
let clippingMask = this.clippingMask;
|
|
14960
|
+
let debugRendering = this.debugRendering;
|
|
14957
14961
|
|
|
14958
14962
|
for (var i = 0, n = drawOrder.length; i < n; i++) {
|
|
14959
|
-
let clippedVertexSize = clipper.isClipping() ? 2 :
|
|
14963
|
+
let clippedVertexSize = clipper.isClipping() ? 2 : vertexSize;
|
|
14960
14964
|
let slot = drawOrder[i];
|
|
14961
14965
|
let bone = slot.bone;
|
|
14966
|
+
let image;
|
|
14967
|
+
let region;
|
|
14968
|
+
let triangles;
|
|
14962
14969
|
|
|
14963
14970
|
if (!bone.active) {
|
|
14964
14971
|
clipper.clipEndWithSlot(slot);
|
|
@@ -14969,78 +14976,175 @@ class SkeletonRenderer {
|
|
|
14969
14976
|
let attachment = slot.getAttachment();
|
|
14970
14977
|
|
|
14971
14978
|
if (attachment instanceof RegionAttachment) {
|
|
14972
|
-
|
|
14973
|
-
|
|
14979
|
+
attachment.computeWorldVertices(slot, worldVertices, 0, clippedVertexSize);
|
|
14980
|
+
region = attachment.region;
|
|
14981
|
+
image = region.texture.getImage();
|
|
14982
|
+
} else if (attachment instanceof MeshAttachment) {
|
|
14983
|
+
this.computeMeshVertices(slot, attachment, false, clippedVertexSize);
|
|
14984
|
+
triangles = attachment.triangles;
|
|
14985
|
+
region = attachment.region;
|
|
14986
|
+
image = region.texture.getImage();
|
|
14987
|
+
} else if (attachment instanceof ClippingAttachment) {
|
|
14988
|
+
let clip = attachment;
|
|
14989
|
+
let vertices = this.clippingVertices;
|
|
14990
|
+
clipper.clipStart(slot, clip);
|
|
14991
|
+
clip.computeWorldVertices(slot, 0, clip.worldVerticesLength, vertices, 0, 2);
|
|
14992
|
+
clippingMask.setVertices(vertices, clip.worldVerticesLength);
|
|
14993
|
+
if (debugRendering === true) {
|
|
14994
|
+
renderer.setColor(clipDebugColor);
|
|
14995
|
+
renderer.stroke(clippingMask);
|
|
14996
|
+
}
|
|
14997
|
+
continue;
|
|
14998
|
+
} else {
|
|
14999
|
+
clipper.clipEndWithSlot(slot);
|
|
15000
|
+
renderer.clearMask();
|
|
15001
|
+
continue;
|
|
15002
|
+
}
|
|
15003
|
+
|
|
15004
|
+
if (typeof image !== "undefined") {
|
|
14974
15005
|
let slotColor = slot.color;
|
|
14975
15006
|
let regionColor = attachment.color;
|
|
14976
15007
|
let blendMode = slot.data.blendMode;
|
|
14977
15008
|
let color = this.tintColor;
|
|
14978
15009
|
|
|
15010
|
+
renderer.save();
|
|
15011
|
+
|
|
14979
15012
|
color.setFloat(skeletonColor.r * slotColor.r * regionColor.r,
|
|
14980
15013
|
skeletonColor.g * slotColor.g * regionColor.g,
|
|
14981
15014
|
skeletonColor.b * slotColor.b * regionColor.b,
|
|
14982
15015
|
skeletonColor.a * slotColor.a * regionColor.a);
|
|
14983
15016
|
|
|
14984
|
-
|
|
14985
|
-
|
|
14986
|
-
renderer.save();
|
|
14987
|
-
renderer.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY);
|
|
14988
|
-
renderer.translate(attachment.offset[0], attachment.offset[1]);
|
|
14989
|
-
renderer.rotate(Math$1.degToRad(attachment.rotation));
|
|
14990
|
-
|
|
14991
|
-
let atlasScale = attachment.width / region.originalWidth;
|
|
14992
|
-
renderer.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY);
|
|
14993
|
-
|
|
14994
|
-
let w = region.width, h = region.height;
|
|
14995
|
-
let hW = w / 2, hH = h / 2;
|
|
14996
|
-
renderer.translate(hW, hH);
|
|
14997
|
-
if (region.degrees === 90) {
|
|
14998
|
-
let t = w;
|
|
14999
|
-
w = h;
|
|
15000
|
-
h = t;
|
|
15001
|
-
renderer.rotate(-Math$1.ETA);
|
|
15002
|
-
}
|
|
15003
|
-
renderer.scale(1, -1);
|
|
15004
|
-
renderer.translate(-hW, -hH);
|
|
15017
|
+
renderer.setGlobalAlpha(color.a);
|
|
15005
15018
|
renderer.setTint(color);
|
|
15006
15019
|
renderer.setBlendMode(blendModeLUT[blendMode]);
|
|
15007
|
-
renderer.setGlobalAlpha(color.a);
|
|
15008
15020
|
|
|
15009
|
-
if (
|
|
15010
|
-
|
|
15011
|
-
|
|
15021
|
+
if (typeof triangles !== "undefined") {
|
|
15022
|
+
let vertices = worldVertices;
|
|
15023
|
+
for (var j = 0; j < triangles.length; j += 3) {
|
|
15024
|
+
let t1 = triangles[j] * 8, t2 = triangles[j + 1] * 8, t3 = triangles[j + 2] * 8;
|
|
15025
|
+
let x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7];
|
|
15026
|
+
let x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7];
|
|
15027
|
+
let x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7];
|
|
15012
15028
|
|
|
15013
|
-
|
|
15029
|
+
this.drawTriangle(renderer, image, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2);
|
|
15030
|
+
}
|
|
15031
|
+
} else {
|
|
15032
|
+
let atlasScale = attachment.width / region.originalWidth;
|
|
15033
|
+
let w = region.width, h = region.height;
|
|
15034
|
+
let hW = w / 2, hH = h / 2;
|
|
15014
15035
|
|
|
15015
|
-
|
|
15016
|
-
renderer.
|
|
15017
|
-
renderer.
|
|
15036
|
+
renderer.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY);
|
|
15037
|
+
renderer.translate(attachment.offset[0], attachment.offset[1]);
|
|
15038
|
+
renderer.rotate(Math$1.degToRad(attachment.rotation));
|
|
15039
|
+
renderer.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY);
|
|
15040
|
+
renderer.translate(hW, hH);
|
|
15041
|
+
if (region.degrees === 90) {
|
|
15042
|
+
let t = w;
|
|
15043
|
+
w = h;
|
|
15044
|
+
h = t;
|
|
15045
|
+
renderer.rotate(-Math$1.ETA);
|
|
15046
|
+
}
|
|
15047
|
+
renderer.scale(1, -1);
|
|
15048
|
+
renderer.translate(-hW, -hH);
|
|
15049
|
+
|
|
15050
|
+
if (clipper.isClipping()) {
|
|
15051
|
+
renderer.setMask(clippingMask);
|
|
15052
|
+
}
|
|
15053
|
+
renderer.drawImage(image, image.width * region.u, image.height * region.v, w, h, 0, 0, w, h);
|
|
15054
|
+
|
|
15055
|
+
if (debugRendering === true) {
|
|
15056
|
+
renderer.setColor(regionDebugColor);
|
|
15057
|
+
renderer.strokeRect(0, 0, w, h);
|
|
15058
|
+
}
|
|
15018
15059
|
}
|
|
15019
15060
|
|
|
15020
15061
|
renderer.restore();
|
|
15021
|
-
} else if (attachment instanceof MeshAttachment) {
|
|
15022
|
-
// do nothing for now;
|
|
15023
|
-
} else if (attachment instanceof ClippingAttachment) {
|
|
15024
|
-
let clip = attachment;
|
|
15025
|
-
let vertices = this.clippingVertices;
|
|
15026
|
-
clipper.clipStart(slot, clip);
|
|
15027
|
-
clip.computeWorldVertices(slot, 0, clip.worldVerticesLength, vertices, 0, 2);
|
|
15028
|
-
this.clippingMask.setVertices(vertices, clip.worldVerticesLength);
|
|
15029
|
-
if (this.debugRendering === true) {
|
|
15030
|
-
renderer.setColor("blue");
|
|
15031
|
-
renderer.stroke(this.clippingMask);
|
|
15032
|
-
}
|
|
15033
|
-
continue;
|
|
15034
|
-
} else {
|
|
15035
|
-
clipper.clipEndWithSlot(slot);
|
|
15036
|
-
renderer.clearMask();
|
|
15037
|
-
continue;
|
|
15038
15062
|
}
|
|
15039
15063
|
clipper.clipEndWithSlot(slot);
|
|
15040
15064
|
renderer.clearMask();
|
|
15041
15065
|
}
|
|
15042
15066
|
clipper.clipEnd();
|
|
15043
15067
|
}
|
|
15068
|
+
|
|
15069
|
+
drawTriangle(renderer, img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2) {
|
|
15070
|
+
u0 *= img.width;
|
|
15071
|
+
v0 *= img.height;
|
|
15072
|
+
u1 *= img.width;
|
|
15073
|
+
v1 *= img.height;
|
|
15074
|
+
u2 *= img.width;
|
|
15075
|
+
v2 *= img.height;
|
|
15076
|
+
|
|
15077
|
+
renderer.save();
|
|
15078
|
+
renderer.beginPath();
|
|
15079
|
+
renderer.moveTo(x0, y0);
|
|
15080
|
+
renderer.lineTo(x1, y1);
|
|
15081
|
+
renderer.lineTo(x2, y2);
|
|
15082
|
+
renderer.closePath();
|
|
15083
|
+
renderer.setMask();
|
|
15084
|
+
|
|
15085
|
+
x1 -= x0;
|
|
15086
|
+
y1 -= y0;
|
|
15087
|
+
x2 -= x0;
|
|
15088
|
+
y2 -= y0;
|
|
15089
|
+
|
|
15090
|
+
u1 -= u0;
|
|
15091
|
+
v1 -= v0;
|
|
15092
|
+
u2 -= u0;
|
|
15093
|
+
v2 -= v0;
|
|
15094
|
+
|
|
15095
|
+
var det = 1 / (u1 * v2 - u2 * v1),
|
|
15096
|
+
|
|
15097
|
+
// linear transformation
|
|
15098
|
+
a = (v2 * x1 - v1 * x2) * det,
|
|
15099
|
+
b = (v2 * y1 - v1 * y2) * det,
|
|
15100
|
+
c = (u1 * x2 - u2 * x1) * det,
|
|
15101
|
+
d = (u1 * y2 - u2 * y1) * det,
|
|
15102
|
+
|
|
15103
|
+
// translation
|
|
15104
|
+
e = x0 - a * u0 - c * v0,
|
|
15105
|
+
f = y0 - b * u0 - d * v0;
|
|
15106
|
+
|
|
15107
|
+
renderer.transform(a, b, c, d, e, f);
|
|
15108
|
+
renderer.drawImage(img, 0, 0);
|
|
15109
|
+
renderer.clearMask();
|
|
15110
|
+
renderer.restore();
|
|
15111
|
+
|
|
15112
|
+
if (this.debugRendering === true) {
|
|
15113
|
+
renderer.setColor(meshDebugColor);
|
|
15114
|
+
renderer.stroke();
|
|
15115
|
+
}
|
|
15116
|
+
|
|
15117
|
+
}
|
|
15118
|
+
|
|
15119
|
+
computeMeshVertices(slot, mesh, pma = false, vertexSize) {
|
|
15120
|
+
let skeletonColor = slot.bone.skeleton.color;
|
|
15121
|
+
let slotColor = slot.color;
|
|
15122
|
+
let regionColor = mesh.color;
|
|
15123
|
+
let alpha = skeletonColor.a * slotColor.a * regionColor.a;
|
|
15124
|
+
let multiplier = pma ? alpha : 1;
|
|
15125
|
+
|
|
15126
|
+
this.tempColor.setFloat(skeletonColor.r * slotColor.r * regionColor.r * multiplier,
|
|
15127
|
+
skeletonColor.g * slotColor.g * regionColor.g * multiplier,
|
|
15128
|
+
skeletonColor.b * slotColor.b * regionColor.b * multiplier,
|
|
15129
|
+
alpha);
|
|
15130
|
+
|
|
15131
|
+
if (worldVertices.length < mesh.worldVerticesLength) worldVertices = new Float32Array(mesh.worldVerticesLength);
|
|
15132
|
+
mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, worldVertices, 0, vertexSize);
|
|
15133
|
+
|
|
15134
|
+
let uvs = mesh.uvs;
|
|
15135
|
+
let color = this.tempColor.toArray();
|
|
15136
|
+
let vertices = worldVertices;
|
|
15137
|
+
let vertexCount = mesh.worldVerticesLength / 2;
|
|
15138
|
+
for (let i = 0, u = 0, v = 2; i < vertexCount; i++) {
|
|
15139
|
+
vertices[v++] = color[0];
|
|
15140
|
+
vertices[v++] = color[1];
|
|
15141
|
+
vertices[v++] = color[2];
|
|
15142
|
+
vertices[v++] = color[3];
|
|
15143
|
+
vertices[v++] = uvs[u++];
|
|
15144
|
+
vertices[v++] = uvs[u++];
|
|
15145
|
+
v += 2;
|
|
15146
|
+
}
|
|
15147
|
+
}
|
|
15044
15148
|
}
|
|
15045
15149
|
|
|
15046
15150
|
let assetManager = new AssetManager();
|
package/package.json
CHANGED
|
@@ -1,27 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@melonjs/spine-plugin",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "melonJS Spine plugin",
|
|
5
|
+
"homepage": "https://github.com/melonjs/spine-plugin#readme",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"keywords": [
|
|
7
8
|
"2D",
|
|
8
9
|
"HTML5",
|
|
9
10
|
"javascript",
|
|
10
11
|
"TypeScript",
|
|
11
|
-
"
|
|
12
|
+
"ES6",
|
|
12
13
|
"Canvas",
|
|
13
14
|
"WebGL",
|
|
14
15
|
"WebGL2",
|
|
15
16
|
"melonjs",
|
|
16
|
-
"
|
|
17
|
+
"plugin",
|
|
18
|
+
"spine",
|
|
19
|
+
"spine-runtimes",
|
|
20
|
+
"spine-animation",
|
|
17
21
|
"esotericsoftware"
|
|
18
22
|
],
|
|
19
23
|
"repository": {
|
|
20
24
|
"type": "git",
|
|
21
|
-
"url": "git+https://github.com/melonjs/
|
|
25
|
+
"url": "git+https://github.com/melonjs/spine-plugin.git"
|
|
22
26
|
},
|
|
23
27
|
"bugs": {
|
|
24
|
-
"url": "https://github.com/melonjs/
|
|
28
|
+
"url": "https://github.com/melonjs/spine-plugin/issues"
|
|
25
29
|
},
|
|
26
30
|
"license": "MIT",
|
|
27
31
|
"author": "AltByte Pte Ltd",
|
|
@@ -38,10 +42,11 @@
|
|
|
38
42
|
"src/",
|
|
39
43
|
"package.json",
|
|
40
44
|
"README.md",
|
|
41
|
-
"LICENSE"
|
|
45
|
+
"LICENSE",
|
|
46
|
+
"CHANGELOG.md"
|
|
42
47
|
],
|
|
43
48
|
"peerDependencies": {
|
|
44
|
-
"melonjs": "^15.9.
|
|
49
|
+
"melonjs": "^15.9.2"
|
|
45
50
|
},
|
|
46
51
|
"dependencies": {
|
|
47
52
|
"@esotericsoftware/spine-canvas": "^4.2.18",
|
|
@@ -49,17 +54,17 @@
|
|
|
49
54
|
"@esotericsoftware/spine-webgl": "^4.2.18"
|
|
50
55
|
},
|
|
51
56
|
"devDependencies": {
|
|
52
|
-
"@babel/eslint-parser": "^7.22.
|
|
57
|
+
"@babel/eslint-parser": "^7.22.11",
|
|
53
58
|
"@babel/plugin-syntax-import-assertions": "^7.22.5",
|
|
54
59
|
"@rollup/plugin-commonjs": "^25.0.4",
|
|
55
|
-
"@rollup/plugin-node-resolve": "^15.2.
|
|
60
|
+
"@rollup/plugin-node-resolve": "^15.2.1",
|
|
56
61
|
"@rollup/plugin-replace": "^5.0.2",
|
|
57
|
-
"del-cli": "^5.0.
|
|
58
|
-
"eslint": "^8.
|
|
62
|
+
"del-cli": "^5.0.1",
|
|
63
|
+
"eslint": "^8.48.0",
|
|
59
64
|
"eslint-plugin-jsdoc": "^46.5.0",
|
|
60
|
-
"rollup": "^3.28.
|
|
65
|
+
"rollup": "^3.28.1",
|
|
61
66
|
"rollup-plugin-bundle-size": "^1.0.3",
|
|
62
|
-
"typescript": "^5.
|
|
67
|
+
"typescript": "^5.2.2"
|
|
63
68
|
},
|
|
64
69
|
"scripts": {
|
|
65
70
|
"build": "npm run clean && npm run lint && rollup -c --silent && npm run types",
|
|
@@ -69,9 +74,5 @@
|
|
|
69
74
|
"prepublishOnly": "npm run build",
|
|
70
75
|
"clean": "del-cli --force dist/*",
|
|
71
76
|
"types": "tsc"
|
|
72
|
-
},
|
|
73
|
-
"homepage": "https://github.com/melonjs/spine-plugin#readme",
|
|
74
|
-
"directories": {
|
|
75
|
-
"test": "test"
|
|
76
77
|
}
|
|
77
78
|
}
|
package/src/SkeletonRenderer.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { Color as MColor, Math as MMath, Polygon } from "melonjs";
|
|
2
|
-
import { SkeletonClipping, ClippingAttachment, MeshAttachment, RegionAttachment
|
|
2
|
+
import { SkeletonClipping, ClippingAttachment, MeshAttachment, RegionAttachment } from "@esotericsoftware/spine-core";
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const vertexSize = 2 + 2 + 4;
|
|
5
5
|
const blendModeLUT = ["normal", "additive", "multiply", "screen"];
|
|
6
|
+
const regionDebugColor = "green";
|
|
7
|
+
const meshDebugColor = "yellow";
|
|
8
|
+
const clipDebugColor = "blue";
|
|
9
|
+
|
|
10
|
+
let worldVertices = new Float32Array(vertexSize * 1024);
|
|
6
11
|
|
|
7
12
|
export default class SkeletonRenderer {
|
|
8
|
-
isWebGLRenderer;
|
|
9
13
|
skeletonRenderer;
|
|
10
14
|
runtime;
|
|
11
|
-
tempColor = new Color();
|
|
12
15
|
tintColor = new MColor();
|
|
13
|
-
|
|
16
|
+
tempColor = new MColor();
|
|
14
17
|
debugRendering = false;
|
|
15
18
|
clipper = new SkeletonClipping();
|
|
16
19
|
clippingVertices = [];
|
|
@@ -19,18 +22,22 @@ export default class SkeletonRenderer {
|
|
|
19
22
|
constructor(runtime) {
|
|
20
23
|
this.runtime = runtime;
|
|
21
24
|
this.skeletonRenderer = new runtime.SkeletonRenderer();
|
|
22
|
-
this.tempColor = new Color();
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
draw(renderer, skeleton) {
|
|
26
28
|
let clipper = this.clipper;
|
|
27
29
|
let drawOrder = skeleton.drawOrder;
|
|
28
30
|
let skeletonColor = skeleton.color;
|
|
31
|
+
let clippingMask = this.clippingMask;
|
|
32
|
+
let debugRendering = this.debugRendering;
|
|
29
33
|
|
|
30
34
|
for (var i = 0, n = drawOrder.length; i < n; i++) {
|
|
31
|
-
let clippedVertexSize = clipper.isClipping() ? 2 :
|
|
35
|
+
let clippedVertexSize = clipper.isClipping() ? 2 : vertexSize;
|
|
32
36
|
let slot = drawOrder[i];
|
|
33
37
|
let bone = slot.bone;
|
|
38
|
+
let image;
|
|
39
|
+
let region;
|
|
40
|
+
let triangles;
|
|
34
41
|
|
|
35
42
|
if (!bone.active) {
|
|
36
43
|
clipper.clipEndWithSlot(slot);
|
|
@@ -41,76 +48,173 @@ export default class SkeletonRenderer {
|
|
|
41
48
|
let attachment = slot.getAttachment();
|
|
42
49
|
|
|
43
50
|
if (attachment instanceof RegionAttachment) {
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
attachment.computeWorldVertices(slot, worldVertices, 0, clippedVertexSize);
|
|
52
|
+
region = attachment.region;
|
|
53
|
+
image = region.texture.getImage();
|
|
54
|
+
} else if (attachment instanceof MeshAttachment) {
|
|
55
|
+
this.computeMeshVertices(slot, attachment, false, clippedVertexSize);
|
|
56
|
+
triangles = attachment.triangles;
|
|
57
|
+
region = attachment.region;
|
|
58
|
+
image = region.texture.getImage();
|
|
59
|
+
} else if (attachment instanceof ClippingAttachment) {
|
|
60
|
+
let clip = attachment;
|
|
61
|
+
let vertices = this.clippingVertices;
|
|
62
|
+
clipper.clipStart(slot, clip);
|
|
63
|
+
clip.computeWorldVertices(slot, 0, clip.worldVerticesLength, vertices, 0, 2);
|
|
64
|
+
clippingMask.setVertices(vertices, clip.worldVerticesLength);
|
|
65
|
+
if (debugRendering === true) {
|
|
66
|
+
renderer.setColor(clipDebugColor);
|
|
67
|
+
renderer.stroke(clippingMask);
|
|
68
|
+
}
|
|
69
|
+
continue;
|
|
70
|
+
} else {
|
|
71
|
+
clipper.clipEndWithSlot(slot);
|
|
72
|
+
renderer.clearMask();
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (typeof image !== "undefined") {
|
|
46
77
|
let slotColor = slot.color;
|
|
47
78
|
let regionColor = attachment.color;
|
|
48
79
|
let blendMode = slot.data.blendMode;
|
|
49
80
|
let color = this.tintColor;
|
|
50
81
|
|
|
82
|
+
renderer.save();
|
|
83
|
+
|
|
51
84
|
color.setFloat(skeletonColor.r * slotColor.r * regionColor.r,
|
|
52
85
|
skeletonColor.g * slotColor.g * regionColor.g,
|
|
53
86
|
skeletonColor.b * slotColor.b * regionColor.b,
|
|
54
87
|
skeletonColor.a * slotColor.a * regionColor.a);
|
|
55
88
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
renderer.save();
|
|
59
|
-
renderer.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY);
|
|
60
|
-
renderer.translate(attachment.offset[0], attachment.offset[1]);
|
|
61
|
-
renderer.rotate(MMath.degToRad(attachment.rotation));
|
|
62
|
-
|
|
63
|
-
let atlasScale = attachment.width / region.originalWidth;
|
|
64
|
-
renderer.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY);
|
|
65
|
-
|
|
66
|
-
let w = region.width, h = region.height;
|
|
67
|
-
let hW = w / 2, hH = h / 2;
|
|
68
|
-
renderer.translate(hW, hH);
|
|
69
|
-
if (region.degrees === 90) {
|
|
70
|
-
let t = w;
|
|
71
|
-
w = h;
|
|
72
|
-
h = t;
|
|
73
|
-
renderer.rotate(-MMath.ETA);
|
|
74
|
-
}
|
|
75
|
-
renderer.scale(1, -1);
|
|
76
|
-
renderer.translate(-hW, -hH);
|
|
89
|
+
renderer.setGlobalAlpha(color.a);
|
|
77
90
|
renderer.setTint(color);
|
|
78
91
|
renderer.setBlendMode(blendModeLUT[blendMode]);
|
|
79
|
-
renderer.setGlobalAlpha(color.a);
|
|
80
|
-
|
|
81
|
-
if (clipper.isClipping()) {
|
|
82
|
-
renderer.setMask(this.clippingMask);
|
|
83
|
-
}
|
|
84
92
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
93
|
+
if (typeof triangles !== "undefined") {
|
|
94
|
+
let vertices = worldVertices;
|
|
95
|
+
for (var j = 0; j < triangles.length; j += 3) {
|
|
96
|
+
let t1 = triangles[j] * 8, t2 = triangles[j + 1] * 8, t3 = triangles[j + 2] * 8;
|
|
97
|
+
let x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7];
|
|
98
|
+
let x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7];
|
|
99
|
+
let x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7];
|
|
100
|
+
|
|
101
|
+
this.drawTriangle(renderer, image, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2);
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
let atlasScale = attachment.width / region.originalWidth;
|
|
105
|
+
let w = region.width, h = region.height;
|
|
106
|
+
let hW = w / 2, hH = h / 2;
|
|
107
|
+
|
|
108
|
+
renderer.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY);
|
|
109
|
+
renderer.translate(attachment.offset[0], attachment.offset[1]);
|
|
110
|
+
renderer.rotate(MMath.degToRad(attachment.rotation));
|
|
111
|
+
renderer.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY);
|
|
112
|
+
renderer.translate(hW, hH);
|
|
113
|
+
if (region.degrees === 90) {
|
|
114
|
+
let t = w;
|
|
115
|
+
w = h;
|
|
116
|
+
h = t;
|
|
117
|
+
renderer.rotate(-MMath.ETA);
|
|
118
|
+
}
|
|
119
|
+
renderer.scale(1, -1);
|
|
120
|
+
renderer.translate(-hW, -hH);
|
|
121
|
+
|
|
122
|
+
if (clipper.isClipping()) {
|
|
123
|
+
renderer.setMask(clippingMask);
|
|
124
|
+
}
|
|
125
|
+
renderer.drawImage(image, image.width * region.u, image.height * region.v, w, h, 0, 0, w, h);
|
|
126
|
+
|
|
127
|
+
if (debugRendering === true) {
|
|
128
|
+
renderer.setColor(regionDebugColor);
|
|
129
|
+
renderer.strokeRect(0, 0, w, h);
|
|
130
|
+
}
|
|
90
131
|
}
|
|
91
132
|
|
|
92
133
|
renderer.restore();
|
|
93
|
-
} else if (attachment instanceof MeshAttachment) {
|
|
94
|
-
// do nothing for now;
|
|
95
|
-
} else if (attachment instanceof ClippingAttachment) {
|
|
96
|
-
let clip = attachment;
|
|
97
|
-
let vertices = this.clippingVertices;
|
|
98
|
-
clipper.clipStart(slot, clip);
|
|
99
|
-
clip.computeWorldVertices(slot, 0, clip.worldVerticesLength, vertices, 0, 2);
|
|
100
|
-
this.clippingMask.setVertices(vertices, clip.worldVerticesLength);
|
|
101
|
-
if (this.debugRendering === true) {
|
|
102
|
-
renderer.setColor("blue");
|
|
103
|
-
renderer.stroke(this.clippingMask);
|
|
104
|
-
}
|
|
105
|
-
continue;
|
|
106
|
-
} else {
|
|
107
|
-
clipper.clipEndWithSlot(slot);
|
|
108
|
-
renderer.clearMask();
|
|
109
|
-
continue;
|
|
110
134
|
}
|
|
111
135
|
clipper.clipEndWithSlot(slot);
|
|
112
136
|
renderer.clearMask();
|
|
113
137
|
}
|
|
114
138
|
clipper.clipEnd();
|
|
115
139
|
}
|
|
140
|
+
|
|
141
|
+
drawTriangle(renderer, img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2) {
|
|
142
|
+
u0 *= img.width;
|
|
143
|
+
v0 *= img.height;
|
|
144
|
+
u1 *= img.width;
|
|
145
|
+
v1 *= img.height;
|
|
146
|
+
u2 *= img.width;
|
|
147
|
+
v2 *= img.height;
|
|
148
|
+
|
|
149
|
+
renderer.save();
|
|
150
|
+
renderer.beginPath();
|
|
151
|
+
renderer.moveTo(x0, y0);
|
|
152
|
+
renderer.lineTo(x1, y1);
|
|
153
|
+
renderer.lineTo(x2, y2);
|
|
154
|
+
renderer.closePath();
|
|
155
|
+
renderer.setMask();
|
|
156
|
+
|
|
157
|
+
x1 -= x0;
|
|
158
|
+
y1 -= y0;
|
|
159
|
+
x2 -= x0;
|
|
160
|
+
y2 -= y0;
|
|
161
|
+
|
|
162
|
+
u1 -= u0;
|
|
163
|
+
v1 -= v0;
|
|
164
|
+
u2 -= u0;
|
|
165
|
+
v2 -= v0;
|
|
166
|
+
|
|
167
|
+
var det = 1 / (u1 * v2 - u2 * v1),
|
|
168
|
+
|
|
169
|
+
// linear transformation
|
|
170
|
+
a = (v2 * x1 - v1 * x2) * det,
|
|
171
|
+
b = (v2 * y1 - v1 * y2) * det,
|
|
172
|
+
c = (u1 * x2 - u2 * x1) * det,
|
|
173
|
+
d = (u1 * y2 - u2 * y1) * det,
|
|
174
|
+
|
|
175
|
+
// translation
|
|
176
|
+
e = x0 - a * u0 - c * v0,
|
|
177
|
+
f = y0 - b * u0 - d * v0;
|
|
178
|
+
|
|
179
|
+
renderer.transform(a, b, c, d, e, f);
|
|
180
|
+
renderer.drawImage(img, 0, 0);
|
|
181
|
+
renderer.clearMask();
|
|
182
|
+
renderer.restore();
|
|
183
|
+
|
|
184
|
+
if (this.debugRendering === true) {
|
|
185
|
+
renderer.setColor(meshDebugColor);
|
|
186
|
+
renderer.stroke();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
computeMeshVertices(slot, mesh, pma = false, vertexSize) {
|
|
192
|
+
let skeletonColor = slot.bone.skeleton.color;
|
|
193
|
+
let slotColor = slot.color;
|
|
194
|
+
let regionColor = mesh.color;
|
|
195
|
+
let alpha = skeletonColor.a * slotColor.a * regionColor.a;
|
|
196
|
+
let multiplier = pma ? alpha : 1;
|
|
197
|
+
|
|
198
|
+
this.tempColor.setFloat(skeletonColor.r * slotColor.r * regionColor.r * multiplier,
|
|
199
|
+
skeletonColor.g * slotColor.g * regionColor.g * multiplier,
|
|
200
|
+
skeletonColor.b * slotColor.b * regionColor.b * multiplier,
|
|
201
|
+
alpha);
|
|
202
|
+
|
|
203
|
+
if (worldVertices.length < mesh.worldVerticesLength) worldVertices = new Float32Array(mesh.worldVerticesLength);
|
|
204
|
+
mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, worldVertices, 0, vertexSize);
|
|
205
|
+
|
|
206
|
+
let uvs = mesh.uvs;
|
|
207
|
+
let color = this.tempColor.toArray();
|
|
208
|
+
let vertices = worldVertices;
|
|
209
|
+
let vertexCount = mesh.worldVerticesLength / 2;
|
|
210
|
+
for (let i = 0, u = 0, v = 2; i < vertexCount; i++) {
|
|
211
|
+
vertices[v++] = color[0];
|
|
212
|
+
vertices[v++] = color[1];
|
|
213
|
+
vertices[v++] = color[2];
|
|
214
|
+
vertices[v++] = color[3];
|
|
215
|
+
vertices[v++] = uvs[u++];
|
|
216
|
+
vertices[v++] = uvs[u++];
|
|
217
|
+
v += 2;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
116
220
|
}
|