@melonjs/spine-plugin 1.2.1 → 1.4.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.
@@ -1,11 +1,11 @@
1
1
  /*!
2
- * melonJS Spine plugin - v1.2.1
2
+ * melonJS Spine plugin - v1.4.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
6
6
  * @copyright (C) 2011 - 2023 AltByte Pte Ltd
7
7
  */
8
- import { event, video, Color as Color$1, Polygon, Math as Math$1, Renderable as Renderable$1, Vector2d } from 'melonjs';
8
+ import { event, video, Color as Color$1, Polygon, Math as Math$1, utils, loader, Renderable as Renderable$1, Vector2d } from 'melonjs';
9
9
 
10
10
  /******************************************************************************
11
11
  * Spine Runtimes License Agreement
@@ -11292,21 +11292,39 @@ class WebGLBlendModeConverter {
11292
11292
  default: throw new Error("Unknown blend mode: " + blendMode);
11293
11293
  }
11294
11294
  }
11295
+ static getDestColorGLBlendMode(blendMode) {
11296
+ switch (blendMode) {
11297
+ case BlendMode.Normal: return ONE_MINUS_SRC_ALPHA;
11298
+ case BlendMode.Additive: return ONE;
11299
+ case BlendMode.Multiply: return ONE_MINUS_SRC_ALPHA;
11300
+ case BlendMode.Screen: return ONE_MINUS_SRC_COLOR;
11301
+ default: throw new Error("Unknown blend mode: " + blendMode);
11302
+ }
11303
+ }
11304
+ static getDestAlphaGLBlendMode(blendMode, premultipliedAlpha = false) {
11305
+ switch (blendMode) {
11306
+ case BlendMode.Normal: return ONE_MINUS_SRC_ALPHA;
11307
+ case BlendMode.Additive: return premultipliedAlpha ? ONE_MINUS_SRC_ALPHA : ONE;
11308
+ case BlendMode.Multiply: return ONE_MINUS_SRC_ALPHA;
11309
+ case BlendMode.Screen: return ONE_MINUS_SRC_ALPHA;
11310
+ default: throw new Error("Unknown blend mode: " + blendMode);
11311
+ }
11312
+ }
11295
11313
  static getSourceColorGLBlendMode(blendMode, premultipliedAlpha = false) {
11296
11314
  switch (blendMode) {
11297
11315
  case BlendMode.Normal: return premultipliedAlpha ? ONE : SRC_ALPHA;
11298
11316
  case BlendMode.Additive: return premultipliedAlpha ? ONE : SRC_ALPHA;
11299
11317
  case BlendMode.Multiply: return DST_COLOR;
11300
- case BlendMode.Screen: return ONE;
11318
+ case BlendMode.Screen: return premultipliedAlpha ? ONE : SRC_ALPHA;
11301
11319
  default: throw new Error("Unknown blend mode: " + blendMode);
11302
11320
  }
11303
11321
  }
11304
- static getSourceAlphaGLBlendMode(blendMode) {
11322
+ static getSourceAlphaGLBlendMode(blendMode, premultipliedAlpha = false) {
11305
11323
  switch (blendMode) {
11306
- case BlendMode.Normal: return ONE;
11307
- case BlendMode.Additive: return ONE;
11308
- case BlendMode.Multiply: return ONE_MINUS_SRC_ALPHA;
11309
- case BlendMode.Screen: return ONE_MINUS_SRC_COLOR;
11324
+ case BlendMode.Normal: return premultipliedAlpha ? SRC_ALPHA : ONE;
11325
+ case BlendMode.Additive: return premultipliedAlpha ? SRC_ALPHA : ONE;
11326
+ case BlendMode.Multiply: return ONE;
11327
+ case BlendMode.Screen: return ONE;
11310
11328
  default: throw new Error("Unknown blend mode: " + blendMode);
11311
11329
  }
11312
11330
  }
@@ -12779,7 +12797,8 @@ class PolygonBatcher {
12779
12797
  let gl = this.context.gl;
12780
12798
  this.srcColorBlend = gl.SRC_ALPHA;
12781
12799
  this.srcAlphaBlend = gl.ONE;
12782
- this.dstBlend = gl.ONE_MINUS_SRC_ALPHA;
12800
+ this.dstColorBlend = gl.ONE_MINUS_SRC_ALPHA;
12801
+ this.dstAlphaBlend = gl.ONE_MINUS_SRC_ALPHA;
12783
12802
  }
12784
12803
  begin(shader) {
12785
12804
  if (this.isDrawing)
@@ -12790,23 +12809,24 @@ class PolygonBatcher {
12790
12809
  this.isDrawing = true;
12791
12810
  let gl = this.context.gl;
12792
12811
  gl.enable(gl.BLEND);
12793
- gl.blendFuncSeparate(this.srcColorBlend, this.dstBlend, this.srcAlphaBlend, this.dstBlend);
12812
+ gl.blendFuncSeparate(this.srcColorBlend, this.dstColorBlend, this.srcAlphaBlend, this.dstAlphaBlend);
12794
12813
  if (PolygonBatcher.disableCulling) {
12795
12814
  this.cullWasEnabled = gl.isEnabled(gl.CULL_FACE);
12796
12815
  if (this.cullWasEnabled)
12797
12816
  gl.disable(gl.CULL_FACE);
12798
12817
  }
12799
12818
  }
12800
- setBlendMode(srcColorBlend, srcAlphaBlend, dstBlend) {
12801
- if (this.srcColorBlend == srcColorBlend && this.srcAlphaBlend == srcAlphaBlend && this.dstBlend == dstBlend)
12819
+ setBlendMode(srcColorBlend, srcAlphaBlend, dstColorBlend, dstAlphaBlend) {
12820
+ if (this.srcColorBlend == srcColorBlend && this.srcAlphaBlend == srcAlphaBlend && this.dstColorBlend == dstColorBlend && this.dstAlphaBlend == dstAlphaBlend)
12802
12821
  return;
12803
12822
  this.srcColorBlend = srcColorBlend;
12804
12823
  this.srcAlphaBlend = srcAlphaBlend;
12805
- this.dstBlend = dstBlend;
12824
+ this.dstColorBlend = dstColorBlend;
12825
+ this.dstAlphaBlend = dstAlphaBlend;
12806
12826
  if (this.isDrawing) {
12807
12827
  this.flush();
12808
12828
  let gl = this.context.gl;
12809
- gl.blendFuncSeparate(srcColorBlend, dstBlend, srcAlphaBlend, dstBlend);
12829
+ gl.blendFuncSeparate(srcColorBlend, dstColorBlend, srcAlphaBlend, dstAlphaBlend);
12810
12830
  }
12811
12831
  }
12812
12832
  draw(texture, vertices, indices) {
@@ -12917,7 +12937,8 @@ class ShapeRenderer {
12917
12937
  let gl = this.context.gl;
12918
12938
  this.srcColorBlend = gl.SRC_ALPHA;
12919
12939
  this.srcAlphaBlend = gl.ONE;
12920
- this.dstBlend = gl.ONE_MINUS_SRC_ALPHA;
12940
+ this.dstColorBlend = gl.ONE_MINUS_SRC_ALPHA;
12941
+ this.dstAlphaBlend = gl.ONE_MINUS_SRC_ALPHA;
12921
12942
  }
12922
12943
  begin(shader) {
12923
12944
  if (this.isDrawing)
@@ -12927,16 +12948,17 @@ class ShapeRenderer {
12927
12948
  this.isDrawing = true;
12928
12949
  let gl = this.context.gl;
12929
12950
  gl.enable(gl.BLEND);
12930
- gl.blendFuncSeparate(this.srcColorBlend, this.dstBlend, this.srcAlphaBlend, this.dstBlend);
12951
+ gl.blendFuncSeparate(this.srcColorBlend, this.dstColorBlend, this.srcAlphaBlend, this.dstAlphaBlend);
12931
12952
  }
12932
- setBlendMode(srcColorBlend, srcAlphaBlend, dstBlend) {
12953
+ setBlendMode(srcColorBlend, srcAlphaBlend, dstColorBlend, dstAlphaBlend) {
12933
12954
  this.srcColorBlend = srcColorBlend;
12934
12955
  this.srcAlphaBlend = srcAlphaBlend;
12935
- this.dstBlend = dstBlend;
12956
+ this.dstColorBlend = dstColorBlend;
12957
+ this.dstAlphaBlend = dstAlphaBlend;
12936
12958
  if (this.isDrawing) {
12937
12959
  this.flush();
12938
12960
  let gl = this.context.gl;
12939
- gl.blendFuncSeparate(srcColorBlend, dstBlend, srcAlphaBlend, dstBlend);
12961
+ gl.blendFuncSeparate(srcColorBlend, dstColorBlend, srcAlphaBlend, dstAlphaBlend);
12940
12962
  }
12941
12963
  }
12942
12964
  setColor(color) {
@@ -13271,7 +13293,7 @@ class SkeletonDebugRenderer {
13271
13293
  let skeletonY = skeleton.y;
13272
13294
  let gl = this.context.gl;
13273
13295
  let srcFunc = this.premultipliedAlpha ? gl.ONE : gl.SRC_ALPHA;
13274
- shapes.setBlendMode(srcFunc, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
13296
+ shapes.setBlendMode(srcFunc, gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
13275
13297
  let bones = skeleton.bones;
13276
13298
  if (this.drawBones) {
13277
13299
  shapes.setColor(this.boneLineColor);
@@ -13589,7 +13611,7 @@ let SkeletonRenderer$2 = class SkeletonRenderer {
13589
13611
  let slotBlendMode = slot.data.blendMode;
13590
13612
  if (slotBlendMode != blendMode) {
13591
13613
  blendMode = slotBlendMode;
13592
- batcher.setBlendMode(WebGLBlendModeConverter.getSourceColorGLBlendMode(blendMode, premultipliedAlpha), WebGLBlendModeConverter.getSourceAlphaGLBlendMode(blendMode), WebGLBlendModeConverter.getDestGLBlendMode(blendMode));
13614
+ batcher.setBlendMode(WebGLBlendModeConverter.getSourceColorGLBlendMode(blendMode, premultipliedAlpha), WebGLBlendModeConverter.getSourceAlphaGLBlendMode(blendMode, premultipliedAlpha), WebGLBlendModeConverter.getDestColorGLBlendMode(blendMode), WebGLBlendModeConverter.getDestAlphaGLBlendMode(blendMode, premultipliedAlpha));
13593
13615
  }
13594
13616
  if (clipper.isClipping()) {
13595
13617
  clipper.clipTriangles(renderable.vertices, renderable.numFloats, triangles, triangles.length, uvs, finalColor, darkColor, twoColorTint);
@@ -14185,7 +14207,7 @@ class LoadingScreen {
14185
14207
  let gl = renderer.context.gl;
14186
14208
  renderer.resize(ResizeMode.Expand);
14187
14209
  renderer.camera.position.set(canvas.width / 2, canvas.height / 2, 0);
14188
- renderer.batcher.setBlendMode(gl.ONE, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
14210
+ renderer.batcher.setBlendMode(gl.ONE, gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
14189
14211
  if (complete) {
14190
14212
  this.fadeOut += this.timeKeeper.delta * (this.timeKeeper.totalTime < 1 ? 2 : 1);
14191
14213
  if (this.fadeOut > FADE_OUT)
@@ -14890,28 +14912,50 @@ var spineCanvas = {
14890
14912
  WindowedMean: WindowedMean
14891
14913
  };
14892
14914
 
14915
+ /**
14916
+ * @classdesc
14917
+ * An Asset Manager class to load spine assets
14918
+ */
14893
14919
  class AssetManager {
14894
14920
  asset_manager;
14895
14921
  pathPrefix;
14896
14922
 
14923
+ /**
14924
+ * @param {string} [pathPrefix=""] - a default path prefix for assets location
14925
+ */
14897
14926
  constructor(pathPrefix = "") {
14898
- event.once(event.VIDEO_INIT, this.initAssetManager.bind(this));
14899
- this.pathPrefix = pathPrefix;
14900
- }
14901
-
14902
- initAssetManager() {
14903
- if (video.renderer.WebGLVersion >= 1) {
14904
- this.asset_manager = new AssetManager$2(video.renderer.getContext(), this.pathPrefix);
14905
- } else {
14906
- // canvas renderer
14907
- this.asset_manager = new AssetManager$1(this.pathPrefix);
14908
- }
14927
+ event.once(event.VIDEO_INIT, () => {
14928
+ this.pathPrefix = pathPrefix;
14929
+ if (video.renderer.WebGLVersion >= 1) {
14930
+ this.asset_manager = new AssetManager$2(video.renderer.getContext(), this.pathPrefix);
14931
+ } else {
14932
+ // canvas renderer
14933
+ this.asset_manager = new AssetManager$1(this.pathPrefix);
14934
+ }
14935
+ });
14909
14936
  }
14910
14937
 
14938
+ /**
14939
+ * set a default path prefix for assets location
14940
+ * @see loadAsset
14941
+ * @param {string} pathPrefix
14942
+ */
14911
14943
  setPrefix(pathPrefix) {
14912
- this.asset_manager.pathPrefix = pathPrefix;
14944
+ this.asset_manager.pathPrefix = this.pathPrefix = pathPrefix;
14913
14945
  }
14914
14946
 
14947
+ /**
14948
+ * define all spine assets to be loaded
14949
+ * @see setPrefix
14950
+ * @see loadAll
14951
+ * @param {string} atlas
14952
+ * @param {string} skel
14953
+ * @example
14954
+ * // load spine assets
14955
+ * Spine.assetManager.setPrefix("data/spine/");
14956
+ * Spine.assetManager.loadAsset("alien.atlas", "alien-ess.json");
14957
+ * await Spine.assetManager.loadAll();
14958
+ */
14915
14959
  loadAsset(atlas, skel) {
14916
14960
  if (atlas) {
14917
14961
  this.asset_manager.loadTextureAtlas(atlas);
@@ -14924,22 +14968,28 @@ class AssetManager {
14924
14968
  }
14925
14969
  }
14926
14970
 
14971
+ /**
14972
+ * load all defined spine assets
14973
+ * @see loadAsset
14974
+ */
14927
14975
  loadAll() {
14928
14976
  return this.asset_manager.loadAll();
14929
14977
  }
14930
14978
  }
14931
14979
 
14932
- const worldVertices = new Float32Array(8);
14980
+ const vertexSize = 2 + 2 + 4;
14933
14981
  const blendModeLUT = ["normal", "additive", "multiply", "screen"];
14934
-
14935
14982
  const regionDebugColor = "green";
14983
+ const meshDebugColor = "yellow";
14936
14984
  const clipDebugColor = "blue";
14937
14985
 
14986
+ let worldVertices = new Float32Array(vertexSize * 1024);
14987
+
14938
14988
  class SkeletonRenderer {
14939
14989
  skeletonRenderer;
14940
14990
  runtime;
14941
14991
  tintColor = new Color$1();
14942
- vertexSize = 2 + 2 + 4;
14992
+ tempColor = new Color$1();
14943
14993
  debugRendering = false;
14944
14994
  clipper = new SkeletonClipping();
14945
14995
  clippingVertices = [];
@@ -14958,11 +15008,12 @@ class SkeletonRenderer {
14958
15008
  let debugRendering = this.debugRendering;
14959
15009
 
14960
15010
  for (var i = 0, n = drawOrder.length; i < n; i++) {
14961
- let clippedVertexSize = clipper.isClipping() ? 2 : this.vertexSize;
15011
+ let clippedVertexSize = clipper.isClipping() ? 2 : vertexSize;
14962
15012
  let slot = drawOrder[i];
14963
15013
  let bone = slot.bone;
14964
15014
  let image;
14965
15015
  let region;
15016
+ let triangles;
14966
15017
 
14967
15018
  if (!bone.active) {
14968
15019
  clipper.clipEndWithSlot(slot);
@@ -14977,14 +15028,10 @@ class SkeletonRenderer {
14977
15028
  region = attachment.region;
14978
15029
  image = region.texture.getImage();
14979
15030
  } 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");
15031
+ this.computeMeshVertices(slot, attachment, false, clippedVertexSize);
15032
+ triangles = attachment.triangles;
15033
+ region = attachment.region;
15034
+ image = region.texture.getImage();
14988
15035
  } else if (attachment instanceof ClippingAttachment) {
14989
15036
  let clip = attachment;
14990
15037
  let vertices = this.clippingVertices;
@@ -15008,43 +15055,55 @@ class SkeletonRenderer {
15008
15055
  let blendMode = slot.data.blendMode;
15009
15056
  let color = this.tintColor;
15010
15057
 
15058
+ renderer.save();
15059
+
15011
15060
  color.setFloat(skeletonColor.r * slotColor.r * regionColor.r,
15012
15061
  skeletonColor.g * slotColor.g * regionColor.g,
15013
15062
  skeletonColor.b * slotColor.b * regionColor.b,
15014
15063
  skeletonColor.a * slotColor.a * regionColor.a);
15015
15064
 
15016
- renderer.save();
15017
- renderer.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY);
15018
- renderer.translate(attachment.offset[0], attachment.offset[1]);
15019
- renderer.rotate(Math$1.degToRad(attachment.rotation));
15020
-
15021
- let atlasScale = attachment.width / region.originalWidth;
15022
- renderer.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY);
15023
-
15024
- let w = region.width, h = region.height;
15025
- let hW = w / 2, hH = h / 2;
15026
- renderer.translate(hW, hH);
15027
- if (region.degrees === 90) {
15028
- let t = w;
15029
- w = h;
15030
- h = t;
15031
- renderer.rotate(-Math$1.ETA);
15032
- }
15033
- renderer.scale(1, -1);
15034
- renderer.translate(-hW, -hH);
15065
+ renderer.setGlobalAlpha(color.a);
15035
15066
  renderer.setTint(color);
15036
15067
  renderer.setBlendMode(blendModeLUT[blendMode]);
15037
- renderer.setGlobalAlpha(color.a);
15038
15068
 
15039
- if (clipper.isClipping()) {
15040
- renderer.setMask(clippingMask);
15041
- }
15069
+ if (typeof triangles !== "undefined") {
15070
+ let vertices = worldVertices;
15071
+ for (var j = 0; j < triangles.length; j += 3) {
15072
+ let t1 = triangles[j] * 8, t2 = triangles[j + 1] * 8, t3 = triangles[j + 2] * 8;
15073
+ let x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7];
15074
+ let x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7];
15075
+ let x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7];
15042
15076
 
15043
- renderer.drawImage(image, image.width * region.u, image.height * region.v, w, h, 0, 0, w, h);
15077
+ this.drawTriangle(renderer, image, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2);
15078
+ }
15079
+ } else {
15080
+ let atlasScale = attachment.width / region.originalWidth;
15081
+ let w = region.width, h = region.height;
15082
+ let hW = w / 2, hH = h / 2;
15044
15083
 
15045
- if (debugRendering === true) {
15046
- renderer.setColor(regionDebugColor);
15047
- renderer.strokeRect(0, 0, w, h);
15084
+ renderer.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY);
15085
+ renderer.translate(attachment.offset[0], attachment.offset[1]);
15086
+ renderer.rotate(Math$1.degToRad(attachment.rotation));
15087
+ renderer.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY);
15088
+ renderer.translate(hW, hH);
15089
+ if (region.degrees === 90) {
15090
+ let t = w;
15091
+ w = h;
15092
+ h = t;
15093
+ renderer.rotate(-Math$1.ETA);
15094
+ }
15095
+ renderer.scale(1, -1);
15096
+ renderer.translate(-hW, -hH);
15097
+
15098
+ if (clipper.isClipping()) {
15099
+ renderer.setMask(clippingMask);
15100
+ }
15101
+ renderer.drawImage(image, image.width * region.u, image.height * region.v, w, h, 0, 0, w, h);
15102
+
15103
+ if (debugRendering === true) {
15104
+ renderer.setColor(regionDebugColor);
15105
+ renderer.strokeRect(0, 0, w, h);
15106
+ }
15048
15107
  }
15049
15108
 
15050
15109
  renderer.restore();
@@ -15054,10 +15113,234 @@ class SkeletonRenderer {
15054
15113
  }
15055
15114
  clipper.clipEnd();
15056
15115
  }
15116
+
15117
+ drawTriangle(renderer, img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2) {
15118
+ u0 *= img.width;
15119
+ v0 *= img.height;
15120
+ u1 *= img.width;
15121
+ v1 *= img.height;
15122
+ u2 *= img.width;
15123
+ v2 *= img.height;
15124
+
15125
+ renderer.save();
15126
+ renderer.beginPath();
15127
+ renderer.moveTo(x0, y0);
15128
+ renderer.lineTo(x1, y1);
15129
+ renderer.lineTo(x2, y2);
15130
+ renderer.closePath();
15131
+ renderer.setMask();
15132
+
15133
+ x1 -= x0;
15134
+ y1 -= y0;
15135
+ x2 -= x0;
15136
+ y2 -= y0;
15137
+
15138
+ u1 -= u0;
15139
+ v1 -= v0;
15140
+ u2 -= u0;
15141
+ v2 -= v0;
15142
+
15143
+ var det = 1 / (u1 * v2 - u2 * v1),
15144
+
15145
+ // linear transformation
15146
+ a = (v2 * x1 - v1 * x2) * det,
15147
+ b = (v2 * y1 - v1 * y2) * det,
15148
+ c = (u1 * x2 - u2 * x1) * det,
15149
+ d = (u1 * y2 - u2 * y1) * det,
15150
+
15151
+ // translation
15152
+ e = x0 - a * u0 - c * v0,
15153
+ f = y0 - b * u0 - d * v0;
15154
+
15155
+ renderer.transform(a, b, c, d, e, f);
15156
+ renderer.drawImage(img, 0, 0);
15157
+ renderer.clearMask();
15158
+ renderer.restore();
15159
+
15160
+ if (this.debugRendering === true) {
15161
+ renderer.setColor(meshDebugColor);
15162
+ renderer.stroke();
15163
+ }
15164
+
15165
+ }
15166
+
15167
+ computeMeshVertices(slot, mesh, pma = false, vertexSize) {
15168
+ let skeletonColor = slot.bone.skeleton.color;
15169
+ let slotColor = slot.color;
15170
+ let regionColor = mesh.color;
15171
+ let alpha = skeletonColor.a * slotColor.a * regionColor.a;
15172
+ let multiplier = pma ? alpha : 1;
15173
+
15174
+ this.tempColor.setFloat(skeletonColor.r * slotColor.r * regionColor.r * multiplier,
15175
+ skeletonColor.g * slotColor.g * regionColor.g * multiplier,
15176
+ skeletonColor.b * slotColor.b * regionColor.b * multiplier,
15177
+ alpha);
15178
+
15179
+ if (worldVertices.length < mesh.worldVerticesLength) worldVertices = new Float32Array(mesh.worldVerticesLength);
15180
+ mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, worldVertices, 0, vertexSize);
15181
+
15182
+ let uvs = mesh.uvs;
15183
+ let color = this.tempColor.toArray();
15184
+ let vertices = worldVertices;
15185
+ let vertexCount = mesh.worldVerticesLength / 2;
15186
+ for (let i = 0, u = 0, v = 2; i < vertexCount; i++) {
15187
+ vertices[v++] = color[0];
15188
+ vertices[v++] = color[1];
15189
+ vertices[v++] = color[2];
15190
+ vertices[v++] = color[3];
15191
+ vertices[v++] = uvs[u++];
15192
+ vertices[v++] = uvs[u++];
15193
+ v += 2;
15194
+ }
15195
+ }
15057
15196
  }
15058
15197
 
15198
+ var name = "@melonjs/spine-plugin";
15199
+ var version = "1.4.0";
15200
+ var description = "melonJS Spine plugin";
15201
+ var homepage = "https://github.com/melonjs/spine-plugin#readme";
15202
+ var type = "module";
15203
+ var keywords = [
15204
+ "2D",
15205
+ "HTML5",
15206
+ "javascript",
15207
+ "TypeScript",
15208
+ "ES6",
15209
+ "Canvas",
15210
+ "WebGL",
15211
+ "WebGL2",
15212
+ "melonjs",
15213
+ "plugin",
15214
+ "spine",
15215
+ "spine-runtimes",
15216
+ "spine-animation",
15217
+ "esotericsoftware"
15218
+ ];
15219
+ var repository = {
15220
+ type: "git",
15221
+ url: "git+https://github.com/melonjs/spine-plugin.git"
15222
+ };
15223
+ var bugs = {
15224
+ url: "https://github.com/melonjs/spine-plugin/issues"
15225
+ };
15226
+ var license = "MIT";
15227
+ var author = "AltByte Pte Ltd";
15228
+ var funding = "https://github.com/sponsors/melonjs";
15229
+ var engines = {
15230
+ node: ">= 19"
15231
+ };
15232
+ var main = "dist/@melonjs/spine-plugin.js";
15233
+ var module = "dist/@melonjs/spine-plugin.js";
15234
+ var types = "dist/@melonjs/spine-plugin.d.ts";
15235
+ var sideEffects = false;
15236
+ var files = [
15237
+ "dist/",
15238
+ "src/",
15239
+ "package.json",
15240
+ "README.md",
15241
+ "LICENSE",
15242
+ "CHANGELOG.md"
15243
+ ];
15244
+ var peerDependencies = {
15245
+ melonjs: "^15.10.0"
15246
+ };
15247
+ var dependencies = {
15248
+ "@esotericsoftware/spine-canvas": "^4.2.19",
15249
+ "@esotericsoftware/spine-core": "^4.2.19",
15250
+ "@esotericsoftware/spine-webgl": "^4.2.19"
15251
+ };
15252
+ var devDependencies = {
15253
+ "@babel/eslint-parser": "^7.22.15",
15254
+ "@babel/plugin-syntax-import-assertions": "^7.22.5",
15255
+ "@rollup/plugin-commonjs": "^25.0.4",
15256
+ "@rollup/plugin-json": "^6.0.0",
15257
+ "@rollup/plugin-node-resolve": "^15.2.1",
15258
+ "@rollup/plugin-replace": "^5.0.2",
15259
+ "del-cli": "^5.1.0",
15260
+ eslint: "^8.48.0",
15261
+ "eslint-plugin-jsdoc": "^46.5.1",
15262
+ rollup: "^3.28.1",
15263
+ "rollup-plugin-bundle-size": "^1.0.3",
15264
+ typescript: "^5.2.2"
15265
+ };
15266
+ var scripts = {
15267
+ build: "npm run clean && npm run lint && rollup -c --silent && npm run types",
15268
+ lint: "eslint src/**.js rollup.config.mjs",
15269
+ serve: "python3 -m http.server",
15270
+ test: "npm run serve",
15271
+ prepublishOnly: "npm run build",
15272
+ clean: "del-cli --force dist/*",
15273
+ types: "tsc"
15274
+ };
15275
+ var _package = {
15276
+ name: name,
15277
+ version: version,
15278
+ description: description,
15279
+ homepage: homepage,
15280
+ type: type,
15281
+ keywords: keywords,
15282
+ repository: repository,
15283
+ bugs: bugs,
15284
+ license: license,
15285
+ author: author,
15286
+ funding: funding,
15287
+ engines: engines,
15288
+ main: main,
15289
+ module: module,
15290
+ types: types,
15291
+ sideEffects: sideEffects,
15292
+ files: files,
15293
+ peerDependencies: peerDependencies,
15294
+ dependencies: dependencies,
15295
+ devDependencies: devDependencies,
15296
+ scripts: scripts
15297
+ };
15298
+
15059
15299
  let assetManager = new AssetManager();
15060
15300
 
15301
+ // a custom Spine parser for melonJS preloader
15302
+ function spineParser(data, onload, onerror) {
15303
+
15304
+ // decompose data.src for the spine loader
15305
+ const ext = utils.file.getExtension(data.src);
15306
+ const basename = utils.file.getBasename(data.src);
15307
+ const path = utils.file.getPath(data.src);
15308
+ const filename = basename + "." + ext;
15309
+
15310
+ // set url prefix
15311
+ assetManager.setPrefix(path);
15312
+
15313
+ // load asset
15314
+ switch (ext) {
15315
+ case "atlas":
15316
+ assetManager.asset_manager.loadTextureAtlas(filename, onload, onerror);
15317
+ break;
15318
+ case "json":
15319
+ assetManager.asset_manager.loadText(filename, onload, onerror);
15320
+ break;
15321
+ case "skel":
15322
+ assetManager.asset_manager.loadBinary(filename, onload, onerror);
15323
+ break;
15324
+ default:
15325
+ throw "Spine plugin: unknown extension when preloading spine assets";
15326
+ }
15327
+
15328
+ return 1;
15329
+ }
15330
+
15331
+ // set the spine custom parser
15332
+ loader.setParser("spine", spineParser);
15333
+
15334
+ // hello world
15335
+ event.once(event.VIDEO_INIT, () => {
15336
+ console.log(`${name} ${version} - spine runtime ${dependencies["@esotericsoftware/spine-core"]} | ${homepage}`);
15337
+ });
15338
+
15339
+ /**
15340
+ * @classdesc
15341
+ * An object to display a Spine animated skeleton on screen.
15342
+ * @augments Renderable
15343
+ */
15061
15344
  class Spine extends Renderable$1 {
15062
15345
  runtime;
15063
15346
  skeleton;
@@ -15068,6 +15351,40 @@ class Spine extends Renderable$1 {
15068
15351
  boneOffset;
15069
15352
  boneSize;
15070
15353
 
15354
+ /**
15355
+ * @param {number} x - the x coordinates of the Spine object
15356
+ * @param {number} y - the y coordinates of the Spine object
15357
+ * @param {object} settings - Configuration parameters for the Spine object
15358
+ * @param {number} [settings.atlasFile] - the name of the atlasFile to be used to create this spine animation
15359
+ * @param {number} [settings.jsonFile] - the name of the atlasFile to be used to create this spine animation
15360
+ * @param {number} [settings.mixTime = 0.2] - the default mix duration to use when no mix duration has been defined between two animations.
15361
+ * @example
15362
+ * import * as Spine from '@melonjs/spine-plugin';
15363
+ * import * as me from 'melonjs';
15364
+ *
15365
+ * // prepare/declare assets for the preloader
15366
+ * const DataManifest = [
15367
+ * {
15368
+ * "name": "alien-ess.json",
15369
+ * "type": "spine",
15370
+ * "src": "data/spine/alien-ess.json"
15371
+ * },
15372
+ * {
15373
+ * "name": "alien.atlas",
15374
+ * "type": "spine",
15375
+ * "src": "data/spine/alien.atlas"
15376
+ * },
15377
+ * ]
15378
+ *
15379
+ * // create a new Spine Renderable
15380
+ * let spineAlien = new Spine(100, 100, {atlasFile: "alien.atlas", jsonFile: "alien-ess.json"});
15381
+ *
15382
+ * // set default animation
15383
+ * spineAlien.setAnimation(0, "death", true);
15384
+ *
15385
+ * // add it to the game world
15386
+ * me.game.world.addChild(spineAlien);
15387
+ */
15071
15388
  constructor(x, y, settings) {
15072
15389
  super(x, y, settings.width, settings.height);
15073
15390
 
@@ -15088,20 +15405,26 @@ class Spine extends Renderable$1 {
15088
15405
  this.pos.z = settings.z;
15089
15406
  }
15090
15407
 
15091
- this.scaleValue = {x: 1, y: 1};
15408
+ // use internally when calulcating bounds
15092
15409
  this.boneOffset = new Vector2();
15093
15410
  this.boneSize = new Vector2();
15094
15411
 
15095
- this.mixTime = settings.mixTime || 0.2;
15412
+ // default mixTime
15413
+ this.mixTime = typeof settings.mixTime !== "undefined" ? settings.mixTime : 0.2;
15414
+
15096
15415
 
15097
15416
  if (settings.jsonFile) {
15098
15417
  this.jsonFile = settings.jsonFile;
15099
15418
  this.atlasFile = settings.atlasFile;
15100
-
15101
15419
  this.setSkeleton(this.atlasFile, this.jsonFile);
15102
15420
  }
15103
15421
  }
15104
15422
 
15423
+ /**
15424
+ * Whether to enabler the debug mode when rendering the spine object
15425
+ * @default false
15426
+ * @type {boolean}
15427
+ */
15105
15428
  get debugRendering() {
15106
15429
  return this.skeletonRenderer.debugRendering;
15107
15430
  }
@@ -15110,14 +15433,25 @@ class Spine extends Renderable$1 {
15110
15433
  this.skeletonRenderer.debugRendering = value;
15111
15434
  }
15112
15435
 
15436
+ /**
15437
+ * set and load the given skeleton atlas and json definition files
15438
+ * (use this if you did not specify any json or atlas through the constructor)
15439
+ * @param {number} [atlasFile] - the name of the atlasFile to be used to create this spine animation
15440
+ * @param {number} [jsonFile] - the name of the atlasFile to be used to create this spine animation
15441
+ * @example
15442
+ * // create a new Spine Renderable
15443
+ * let spineAlien = new Spine(100, 100);
15444
+ *
15445
+ * // set the skeleton
15446
+ * spineAlien.setSkeleton("alien.atlas", "alien-ess.json");
15447
+ *
15448
+ * // set default animation
15449
+ * spineAlien.setAnimation(0, "death", true);
15450
+ *
15451
+ * // add it to the game world
15452
+ * me.game.world.addChild(spineAlien);
15453
+ */
15113
15454
  setSkeleton(atlasFile, jsonFile) {
15114
- this.loadSpineAssets(atlasFile, jsonFile);
15115
- this.root = this.skeleton.getRootBone();
15116
- // Spine uses Y-up, melonJS uses Y-down
15117
- this.root.scaleY *= -1;
15118
- }
15119
-
15120
- loadSpineAssets(atlasFile, jsonFile) {
15121
15455
  // Create the texture atlas and skeleton data.
15122
15456
  let atlas = this.assetManager.require(atlasFile);
15123
15457
  let atlasLoader = new this.runtime.AtlasAttachmentLoader(atlas);
@@ -15133,20 +15467,50 @@ class Spine extends Renderable$1 {
15133
15467
  var animationStateData = new this.runtime.AnimationStateData(this.skeleton.data);
15134
15468
  animationStateData.defaultMix = this.mixTime;
15135
15469
  this.animationState = new this.runtime.AnimationState(animationStateData);
15470
+
15471
+ // get a reference to the root bone
15472
+ this.root = this.skeleton.getRootBone();
15473
+ // Spine uses Y-up, melonJS uses Y-down
15474
+ this.root.scaleY *= -1;
15475
+
15476
+ // mark the object as dirty
15477
+ this.isDirty = true;
15136
15478
  }
15137
15479
 
15480
+ /**
15481
+ * Rotate this Spine object by the specified angle (in radians).
15482
+ * @param {number} angle - The angle to rotate (in radians)
15483
+ * @param {Vector2d|ObservableVector2d} [v] - an optional point to rotate around
15484
+ * @returns {Spine} Reference to this object for method chaining
15485
+ */
15138
15486
  rotate(angle, v) {
15139
15487
  // rotation for rootBone is in degrees (anti-clockwise)
15140
15488
  this.skeleton.getRootBone().rotation -= Math$1.radToDeg(angle) + 90;
15141
15489
  // melonJS rotate method takes radians
15142
- super.rotate(angle, v);
15490
+ return super.rotate(angle, v);
15143
15491
  }
15144
15492
 
15493
+ /**
15494
+ * scale the Spine object around his anchor point. Scaling actually applies changes
15495
+ * to the currentTransform member wich is used by the renderer to scale the object
15496
+ * when rendering. It does not scale the object itself. For example if the renderable
15497
+ * is an image, the image.width and image.height properties are unaltered but the currentTransform
15498
+ * member will be changed.
15499
+ * @param {number} x - a number representing the abscissa of the scaling vector.
15500
+ * @param {number} [y=x] - a number representing the ordinate of the scaling vector.
15501
+ * @returns {Spine} Reference to this object for method chaining
15502
+ */
15145
15503
  scale(x, y = x) {
15146
- this.scaleValue = {x, y};
15147
- super.scale(x, y);
15504
+ // untested
15505
+ return super.scale(x, y);
15148
15506
  }
15149
15507
 
15508
+ /**
15509
+ * update the bounding box for this spine object.
15510
+ * (this will automatically update the bounds of the entire skeleton animation)
15511
+ * @param {boolean} [absolute=true] - update the bounds size and position in (world) absolute coordinates
15512
+ * @returns {Bounds} this shape bounding box Rectangle object
15513
+ */
15150
15514
  updateBounds(absolute = true) {
15151
15515
  if (this.isRenderable) {
15152
15516
  let bounds = this.getBounds();
@@ -15222,9 +15586,6 @@ class Spine extends Renderable$1 {
15222
15586
 
15223
15587
  /**
15224
15588
  * draw this spine object
15225
- * @name draw
15226
- * @memberof Spine
15227
- * @protected
15228
15589
  * @param {CanvasRenderer|WebGLRenderer} renderer - a renderer instance
15229
15590
  * @param {Camera2d} [viewport] - the viewport to (re)draw
15230
15591
  */
@@ -15232,6 +15593,13 @@ class Spine extends Renderable$1 {
15232
15593
  this.skeletonRenderer.draw(renderer, this.skeleton);
15233
15594
  }
15234
15595
 
15596
+ /**
15597
+ * Sets the current animation for a track, discarding any queued animations.
15598
+ * @param {number} [track_index] - If the formerly current track entry was never applied to a skeleton, it is replaced (not mixed from). In either case trackEnd determines when the track is cleared.
15599
+ * @param {number} [index] - the animation index
15600
+ * @param {boolean} [loop= false] - If true, the animation will repeat. If false it will not, instead its last frame is applied if played beyond its duration.
15601
+ * @returns A track entry to allow further customization of animation playback. References to the track entry must not be kept after the dispose event occurs.
15602
+ */
15235
15603
  setAnimationByIndex(track_index, index, loop = false) {
15236
15604
  if (index < 0 || index >= this.skeleton.data.animations.length) {
15237
15605
  return (console.log("Animation Index not found"));
@@ -15240,10 +15608,25 @@ class Spine extends Renderable$1 {
15240
15608
  }
15241
15609
  }
15242
15610
 
15611
+ /**
15612
+ * Sets the current animation for a track, discarding any queued animations.
15613
+ * @param {number} [track_index] - If the formerly current track entry was never applied to a skeleton, it is replaced (not mixed from). In either case trackEnd determines when the track is cleared.
15614
+ * @param {string} [name] - the animation name
15615
+ * @param {boolean} [loop= false] - If true, the animation will repeat. If false it will not, instead its last frame is applied if played beyond its duration.
15616
+ * @returns A track entry to allow further customization of animation playback. References to the track entry must not be kept after the dispose event occurs.
15617
+ * @example
15618
+ * // set the current animation
15619
+ * spineAlien.setAnimation(0, "death", true);
15620
+ */
15243
15621
  setAnimation(track_index, name, loop = false) {
15244
15622
  this.animationState.setAnimation(track_index, name, loop);
15245
15623
  }
15246
15624
 
15625
+ /**
15626
+ * Adds an animation to be played after the current or last queued animation for a track, and sets the track entry's mixDuration.
15627
+ * @param {number} [delay=0] - If > 0, sets delay. If <= 0, the delay set is the duration of the previous track entry minus any mix duration plus the specified `delay` (ie the mix ends at (`delay` = 0) or before (`delay` < 0) the previous track entry duration). If the previous entry is looping, its next loop completion is used instead of its duration.
15628
+ * @return A track entry to allow further customization of animation playback. References to the track entry must not be kept after the dispose} event occurs.
15629
+ */
15247
15630
  addAnimationByIndex(track_index, index, loop = false, delay = 0) {
15248
15631
  if (index < 0 || index >= this.skeleton.data.animations.length) {
15249
15632
  return (console.log("Animation Index not found"));
@@ -15272,18 +15655,44 @@ class Spine extends Renderable$1 {
15272
15655
  };
15273
15656
  }
15274
15657
 
15658
+ /**
15659
+ * Set the default mix duration to use when no mix duration has been defined between two animations.
15660
+ * @param {number} mixTime
15661
+ */
15275
15662
  setDefaultMixTime(mixTime) {
15276
- this.animationState.data.defaultMix = mixTime;
15663
+ this.animationState.data.defaultMix = this.mixTime = mixTime;
15277
15664
  }
15278
15665
 
15666
+ /**
15667
+ * Sets a mix duration by animation name.
15668
+ */
15279
15669
  setTransitionMixTime(firstAnimation, secondAnimation, mixTime) {
15280
15670
  this.animationState.setMix(firstAnimation, secondAnimation, mixTime);
15281
15671
  }
15282
15672
 
15673
+ /**
15674
+ * Sets a skin by name.
15675
+ * @param {string} skinName
15676
+ * @example
15677
+ * // create a new Spine Renderable
15678
+ * let spineAlien = new Spine(100, 100, {atlasFile: "mix-and-match-pma.atlas", jsonFile: "mix-and-match-pro.json"});
15679
+ *
15680
+ * // set default animation
15681
+ * spineAlien.setAnimation(0, "dance", true);
15682
+ *
15683
+ * // set default skin
15684
+ * spineAlien.setSkinByName("full-skins/girl");
15685
+ *
15686
+ * // add it to the game world
15687
+ * me.game.world.addChild(spineAlien);
15688
+ */
15283
15689
  setSkinByName(skinName) {
15284
15690
  this.skeleton.setSkinByName(skinName);
15285
15691
  }
15286
15692
 
15693
+ /**
15694
+ * Sets this slot to the setup pose.
15695
+ */
15287
15696
  setToSetupPose() {
15288
15697
  this.skeleton.setToSetupPose();
15289
15698
  }