@melonjs/spine-plugin 1.1.0 → 1.2.1
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 +19 -0
- package/README.md +3 -2
- package/dist/@melonjs/spine-plugin.d.ts +5 -2
- package/dist/@melonjs/spine-plugin.js +62 -16
- package/package.json +14 -13
- package/src/SkeletonRenderer.js +62 -16
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.2.1 - _2023-08-23
|
|
4
|
+
|
|
5
|
+
- code refactoring and optimization to prepare for future feature additions
|
|
6
|
+
- fix URLs in the package.json file
|
|
7
|
+
|
|
8
|
+
## 1.2.0 - _2023-08-22
|
|
9
|
+
|
|
10
|
+
- add support for clipping (coin example is now rendered properly)
|
|
11
|
+
|
|
12
|
+
## 1.1.0 - _2023-08-19
|
|
13
|
+
|
|
14
|
+
- add some basic debug rendering
|
|
15
|
+
- optimize code (remove unneeded logic)
|
|
16
|
+
|
|
17
|
+
## 1.0.0 - _2023-08-16_
|
|
18
|
+
|
|
19
|
+
initial release
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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
|
-

|
|
6
6
|
|
|
7
7
|
>Note: although functional, this plugin is still a work in progress. Feedback and especially contributions are welcome!
|
|
8
8
|
|
|
@@ -17,6 +17,7 @@ this plugin is already bundled with the required Spine runtime, so there is no n
|
|
|
17
17
|
>Note: this plugin requires melonJS version 15.9 or higher.
|
|
18
18
|
|
|
19
19
|
To install the plugin using npm :
|
|
20
|
+
|
|
20
21
|
`$ [sudo] npm install @melonjs/spine-plugin`
|
|
21
22
|
|
|
22
23
|
Then import and use the plugin in your project. For example:
|
|
@@ -4070,12 +4070,14 @@ 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;
|
|
4076
|
+
vertexSize: number;
|
|
4078
4077
|
debugRendering: boolean;
|
|
4078
|
+
clipper: SkeletonClipping;
|
|
4079
|
+
clippingVertices: any[];
|
|
4080
|
+
clippingMask: Polygon;
|
|
4079
4081
|
draw(renderer: any, skeleton: any): void;
|
|
4080
4082
|
}
|
|
4081
4083
|
import { Vector2d } from 'melonjs';
|
|
@@ -4129,4 +4131,5 @@ declare class Vertices {
|
|
|
4129
4131
|
vertices: any;
|
|
4130
4132
|
}
|
|
4131
4133
|
import { Color as Color$1 } from 'melonjs';
|
|
4134
|
+
import { Polygon } from 'melonjs';
|
|
4132
4135
|
export { Spine as default };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* melonJS Spine plugin - v1.1
|
|
2
|
+
* melonJS Spine plugin - v1.2.1
|
|
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
|
|
6
6
|
* @copyright (C) 2011 - 2023 AltByte Pte Ltd
|
|
7
7
|
*/
|
|
8
|
-
import { event, video, Color as Color$1, Math as Math$1, Renderable as Renderable$1, Vector2d } from 'melonjs';
|
|
8
|
+
import { event, video, Color as Color$1, Polygon, Math as Math$1, Renderable as Renderable$1, Vector2d } from 'melonjs';
|
|
9
9
|
|
|
10
10
|
/******************************************************************************
|
|
11
11
|
* Spine Runtimes License Agreement
|
|
@@ -14932,40 +14932,77 @@ class AssetManager {
|
|
|
14932
14932
|
const worldVertices = new Float32Array(8);
|
|
14933
14933
|
const blendModeLUT = ["normal", "additive", "multiply", "screen"];
|
|
14934
14934
|
|
|
14935
|
+
const regionDebugColor = "green";
|
|
14936
|
+
const clipDebugColor = "blue";
|
|
14937
|
+
|
|
14935
14938
|
class SkeletonRenderer {
|
|
14936
|
-
isWebGLRenderer;
|
|
14937
14939
|
skeletonRenderer;
|
|
14938
14940
|
runtime;
|
|
14939
|
-
tempColor = new Color();
|
|
14940
14941
|
tintColor = new Color$1();
|
|
14942
|
+
vertexSize = 2 + 2 + 4;
|
|
14941
14943
|
debugRendering = false;
|
|
14944
|
+
clipper = new SkeletonClipping();
|
|
14945
|
+
clippingVertices = [];
|
|
14946
|
+
clippingMask = new Polygon(0, 0);
|
|
14942
14947
|
|
|
14943
14948
|
constructor(runtime) {
|
|
14944
14949
|
this.runtime = runtime;
|
|
14945
14950
|
this.skeletonRenderer = new runtime.SkeletonRenderer();
|
|
14946
|
-
this.tempColor = new Color();
|
|
14947
14951
|
}
|
|
14948
14952
|
|
|
14949
14953
|
draw(renderer, skeleton) {
|
|
14950
|
-
|
|
14954
|
+
let clipper = this.clipper;
|
|
14951
14955
|
let drawOrder = skeleton.drawOrder;
|
|
14952
14956
|
let skeletonColor = skeleton.color;
|
|
14953
|
-
|
|
14954
|
-
|
|
14955
|
-
renderer.setColor("green");
|
|
14956
|
-
}
|
|
14957
|
+
let clippingMask = this.clippingMask;
|
|
14958
|
+
let debugRendering = this.debugRendering;
|
|
14957
14959
|
|
|
14958
14960
|
for (var i = 0, n = drawOrder.length; i < n; i++) {
|
|
14961
|
+
let clippedVertexSize = clipper.isClipping() ? 2 : this.vertexSize;
|
|
14959
14962
|
let slot = drawOrder[i];
|
|
14960
14963
|
let bone = slot.bone;
|
|
14964
|
+
let image;
|
|
14965
|
+
let region;
|
|
14961
14966
|
|
|
14962
|
-
if (!bone.active)
|
|
14967
|
+
if (!bone.active) {
|
|
14968
|
+
clipper.clipEndWithSlot(slot);
|
|
14969
|
+
renderer.clearMask();
|
|
14970
|
+
continue;
|
|
14971
|
+
}
|
|
14963
14972
|
|
|
14964
14973
|
let attachment = slot.getAttachment();
|
|
14965
14974
|
|
|
14966
14975
|
if (attachment instanceof RegionAttachment) {
|
|
14967
|
-
|
|
14968
|
-
|
|
14976
|
+
attachment.computeWorldVertices(slot, worldVertices, 0, clippedVertexSize);
|
|
14977
|
+
region = attachment.region;
|
|
14978
|
+
image = region.texture.getImage();
|
|
14979
|
+
} else if (attachment instanceof MeshAttachment) {
|
|
14980
|
+
/*
|
|
14981
|
+
// commenting for now as totally untested
|
|
14982
|
+
let mesh = attachment;
|
|
14983
|
+
mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, worldVertices, 0, 2);
|
|
14984
|
+
region = mesh.region;
|
|
14985
|
+
image = mesh.region.texture.getImage();
|
|
14986
|
+
*/
|
|
14987
|
+
console.warn("spine-plugin: MeshAttachment is not supported yet");
|
|
14988
|
+
} else if (attachment instanceof ClippingAttachment) {
|
|
14989
|
+
let clip = attachment;
|
|
14990
|
+
let vertices = this.clippingVertices;
|
|
14991
|
+
clipper.clipStart(slot, clip);
|
|
14992
|
+
clip.computeWorldVertices(slot, 0, clip.worldVerticesLength, vertices, 0, 2);
|
|
14993
|
+
clippingMask.setVertices(vertices, clip.worldVerticesLength);
|
|
14994
|
+
if (debugRendering === true) {
|
|
14995
|
+
renderer.setColor(clipDebugColor);
|
|
14996
|
+
renderer.stroke(clippingMask);
|
|
14997
|
+
}
|
|
14998
|
+
continue;
|
|
14999
|
+
} else {
|
|
15000
|
+
clipper.clipEndWithSlot(slot);
|
|
15001
|
+
renderer.clearMask();
|
|
15002
|
+
continue;
|
|
15003
|
+
}
|
|
15004
|
+
|
|
15005
|
+
if (typeof image !== "undefined") {
|
|
14969
15006
|
let slotColor = slot.color;
|
|
14970
15007
|
let regionColor = attachment.color;
|
|
14971
15008
|
let blendMode = slot.data.blendMode;
|
|
@@ -14976,8 +15013,6 @@ class SkeletonRenderer {
|
|
|
14976
15013
|
skeletonColor.b * slotColor.b * regionColor.b,
|
|
14977
15014
|
skeletonColor.a * slotColor.a * regionColor.a);
|
|
14978
15015
|
|
|
14979
|
-
attachment.computeWorldVertices(slot, worldVertices, 0, 2);
|
|
14980
|
-
|
|
14981
15016
|
renderer.save();
|
|
14982
15017
|
renderer.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY);
|
|
14983
15018
|
renderer.translate(attachment.offset[0], attachment.offset[1]);
|
|
@@ -15000,13 +15035,24 @@ class SkeletonRenderer {
|
|
|
15000
15035
|
renderer.setTint(color);
|
|
15001
15036
|
renderer.setBlendMode(blendModeLUT[blendMode]);
|
|
15002
15037
|
renderer.setGlobalAlpha(color.a);
|
|
15038
|
+
|
|
15039
|
+
if (clipper.isClipping()) {
|
|
15040
|
+
renderer.setMask(clippingMask);
|
|
15041
|
+
}
|
|
15042
|
+
|
|
15003
15043
|
renderer.drawImage(image, image.width * region.u, image.height * region.v, w, h, 0, 0, w, h);
|
|
15004
|
-
|
|
15044
|
+
|
|
15045
|
+
if (debugRendering === true) {
|
|
15046
|
+
renderer.setColor(regionDebugColor);
|
|
15005
15047
|
renderer.strokeRect(0, 0, w, h);
|
|
15006
15048
|
}
|
|
15049
|
+
|
|
15007
15050
|
renderer.restore();
|
|
15008
15051
|
}
|
|
15052
|
+
clipper.clipEndWithSlot(slot);
|
|
15053
|
+
renderer.clearMask();
|
|
15009
15054
|
}
|
|
15055
|
+
clipper.clipEnd();
|
|
15010
15056
|
}
|
|
15011
15057
|
}
|
|
15012
15058
|
|
package/package.json
CHANGED
|
@@ -1,27 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@melonjs/spine-plugin",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
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,7 +42,8 @@
|
|
|
38
42
|
"src/",
|
|
39
43
|
"package.json",
|
|
40
44
|
"README.md",
|
|
41
|
-
"LICENSE"
|
|
45
|
+
"LICENSE",
|
|
46
|
+
"CHANGELOG.md"
|
|
42
47
|
],
|
|
43
48
|
"peerDependencies": {
|
|
44
49
|
"melonjs": "^15.9.0"
|
|
@@ -52,12 +57,12 @@
|
|
|
52
57
|
"@babel/eslint-parser": "^7.22.0",
|
|
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
62
|
"del-cli": "^5.0.0",
|
|
58
63
|
"eslint": "^8.47.0",
|
|
59
|
-
"eslint-plugin-jsdoc": "^46.
|
|
60
|
-
"rollup": "^3.28.
|
|
64
|
+
"eslint-plugin-jsdoc": "^46.5.0",
|
|
65
|
+
"rollup": "^3.28.1",
|
|
61
66
|
"rollup-plugin-bundle-size": "^1.0.3",
|
|
62
67
|
"typescript": "^5.1.6"
|
|
63
68
|
},
|
|
@@ -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,43 +1,80 @@
|
|
|
1
|
-
import { Color as MColor, Math as MMath } from "melonjs";
|
|
2
|
-
import {
|
|
1
|
+
import { Color as MColor, Math as MMath, Polygon } from "melonjs";
|
|
2
|
+
import { SkeletonClipping, ClippingAttachment, MeshAttachment, RegionAttachment } from "@esotericsoftware/spine-core";
|
|
3
3
|
|
|
4
4
|
const worldVertices = new Float32Array(8);
|
|
5
5
|
const blendModeLUT = ["normal", "additive", "multiply", "screen"];
|
|
6
6
|
|
|
7
|
+
const regionDebugColor = "green";
|
|
8
|
+
const clipDebugColor = "blue";
|
|
9
|
+
|
|
7
10
|
export default class SkeletonRenderer {
|
|
8
|
-
isWebGLRenderer;
|
|
9
11
|
skeletonRenderer;
|
|
10
12
|
runtime;
|
|
11
|
-
tempColor = new Color();
|
|
12
13
|
tintColor = new MColor();
|
|
14
|
+
vertexSize = 2 + 2 + 4;
|
|
13
15
|
debugRendering = false;
|
|
16
|
+
clipper = new SkeletonClipping();
|
|
17
|
+
clippingVertices = [];
|
|
18
|
+
clippingMask = new Polygon(0, 0);
|
|
14
19
|
|
|
15
20
|
constructor(runtime) {
|
|
16
21
|
this.runtime = runtime;
|
|
17
22
|
this.skeletonRenderer = new runtime.SkeletonRenderer();
|
|
18
|
-
this.tempColor = new Color();
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
draw(renderer, skeleton) {
|
|
22
|
-
|
|
26
|
+
let clipper = this.clipper;
|
|
23
27
|
let drawOrder = skeleton.drawOrder;
|
|
24
28
|
let skeletonColor = skeleton.color;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
renderer.setColor("green");
|
|
28
|
-
}
|
|
29
|
+
let clippingMask = this.clippingMask;
|
|
30
|
+
let debugRendering = this.debugRendering;
|
|
29
31
|
|
|
30
32
|
for (var i = 0, n = drawOrder.length; i < n; i++) {
|
|
33
|
+
let clippedVertexSize = clipper.isClipping() ? 2 : this.vertexSize;
|
|
31
34
|
let slot = drawOrder[i];
|
|
32
35
|
let bone = slot.bone;
|
|
36
|
+
let image;
|
|
37
|
+
let region;
|
|
33
38
|
|
|
34
|
-
if (!bone.active)
|
|
39
|
+
if (!bone.active) {
|
|
40
|
+
clipper.clipEndWithSlot(slot);
|
|
41
|
+
renderer.clearMask();
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
35
44
|
|
|
36
45
|
let attachment = slot.getAttachment();
|
|
37
46
|
|
|
38
47
|
if (attachment instanceof RegionAttachment) {
|
|
39
|
-
|
|
40
|
-
|
|
48
|
+
attachment.computeWorldVertices(slot, worldVertices, 0, clippedVertexSize);
|
|
49
|
+
region = attachment.region;
|
|
50
|
+
image = region.texture.getImage();
|
|
51
|
+
} else if (attachment instanceof MeshAttachment) {
|
|
52
|
+
/*
|
|
53
|
+
// commenting for now as totally untested
|
|
54
|
+
let mesh = attachment;
|
|
55
|
+
mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, worldVertices, 0, 2);
|
|
56
|
+
region = mesh.region;
|
|
57
|
+
image = mesh.region.texture.getImage();
|
|
58
|
+
*/
|
|
59
|
+
console.warn("spine-plugin: MeshAttachment is not supported yet");
|
|
60
|
+
} else if (attachment instanceof ClippingAttachment) {
|
|
61
|
+
let clip = attachment;
|
|
62
|
+
let vertices = this.clippingVertices;
|
|
63
|
+
clipper.clipStart(slot, clip);
|
|
64
|
+
clip.computeWorldVertices(slot, 0, clip.worldVerticesLength, vertices, 0, 2);
|
|
65
|
+
clippingMask.setVertices(vertices, clip.worldVerticesLength);
|
|
66
|
+
if (debugRendering === true) {
|
|
67
|
+
renderer.setColor(clipDebugColor);
|
|
68
|
+
renderer.stroke(clippingMask);
|
|
69
|
+
}
|
|
70
|
+
continue;
|
|
71
|
+
} else {
|
|
72
|
+
clipper.clipEndWithSlot(slot);
|
|
73
|
+
renderer.clearMask();
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (typeof image !== "undefined") {
|
|
41
78
|
let slotColor = slot.color;
|
|
42
79
|
let regionColor = attachment.color;
|
|
43
80
|
let blendMode = slot.data.blendMode;
|
|
@@ -48,8 +85,6 @@ export default class SkeletonRenderer {
|
|
|
48
85
|
skeletonColor.b * slotColor.b * regionColor.b,
|
|
49
86
|
skeletonColor.a * slotColor.a * regionColor.a);
|
|
50
87
|
|
|
51
|
-
attachment.computeWorldVertices(slot, worldVertices, 0, 2);
|
|
52
|
-
|
|
53
88
|
renderer.save();
|
|
54
89
|
renderer.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY);
|
|
55
90
|
renderer.translate(attachment.offset[0], attachment.offset[1]);
|
|
@@ -72,12 +107,23 @@ export default class SkeletonRenderer {
|
|
|
72
107
|
renderer.setTint(color);
|
|
73
108
|
renderer.setBlendMode(blendModeLUT[blendMode]);
|
|
74
109
|
renderer.setGlobalAlpha(color.a);
|
|
110
|
+
|
|
111
|
+
if (clipper.isClipping()) {
|
|
112
|
+
renderer.setMask(clippingMask);
|
|
113
|
+
}
|
|
114
|
+
|
|
75
115
|
renderer.drawImage(image, image.width * region.u, image.height * region.v, w, h, 0, 0, w, h);
|
|
76
|
-
|
|
116
|
+
|
|
117
|
+
if (debugRendering === true) {
|
|
118
|
+
renderer.setColor(regionDebugColor);
|
|
77
119
|
renderer.strokeRect(0, 0, w, h);
|
|
78
120
|
}
|
|
121
|
+
|
|
79
122
|
renderer.restore();
|
|
80
123
|
}
|
|
124
|
+
clipper.clipEndWithSlot(slot);
|
|
125
|
+
renderer.clearMask();
|
|
81
126
|
}
|
|
127
|
+
clipper.clipEnd();
|
|
82
128
|
}
|
|
83
129
|
}
|