diff --git a/config.yaml b/config.yaml index ac9595a..0209595 100644 --- a/config.yaml +++ b/config.yaml @@ -4,6 +4,7 @@ operators: release_folder: ./release/{name}/ source_folder: ./operator/{name}/extracted/ target_folder: ./operator/{name}/ + use_skel: true server: operator_folder: /operator/ release_folder: ./release/ diff --git a/lib/base64_util.py b/lib/base64_util.py index f64716a..5677db2 100644 --- a/lib/base64_util.py +++ b/lib/base64_util.py @@ -1,18 +1,23 @@ import base64 import pathlib -def encode_image(path, prefix=True): - with open(pathlib.Path.cwd().joinpath(path), "rb") as f: - bytes = f.read() - encoded_bytes = base64.b64encode(bytes) - humanreadable_data = encoded_bytes.decode("utf-8") - if prefix is True: - result = "data:image/png;base64," + humanreadable_data - else: - result = humanreadable_data - return result +def encode_binary(data=None, type="application/octet-stream", path=None, prefix=True): + if data is None and path is None: + raise ValueError("Both data and path arguments are None") + if data is not None: + bytes = data + elif path is not None: + with open(pathlib.Path.cwd().joinpath(path), "rb") as f: + bytes = f.read() + encoded_bytes = base64.b64encode(bytes) + humanreadable_data = encoded_bytes.decode("utf-8") + if prefix is True: + result = "data:{};base64,".format(type) + humanreadable_data + else: + result = humanreadable_data + return result -def decode_image(data: str, path): +def decode_binary(data: str, path): if data.strip().startswith("data:") is True: data = data.split(",")[1] encoded_bytes = data.encode("utf-8") @@ -22,7 +27,7 @@ def decode_image(data: str, path): def encode_string(data=None, type="text/plain", path=None, prefix=True, encoding="utf-8"): if data is None and path is None: - return + raise ValueError("Both data and path arguments are None") if data is not None: bytes = data.encode(encoding) elif path is not None: diff --git a/lib/builder.py b/lib/builder.py index 7686c22..07052c2 100644 --- a/lib/builder.py +++ b/lib/builder.py @@ -1,5 +1,4 @@ import threading -import shutil from lib.skeleton_binary import SkeletonBinary from lib.alpha_composite import AlphaComposite from lib.atlas_reader import AtlasReader @@ -10,6 +9,7 @@ class Builder: def __init__(self, operator_name, config) -> None: self.operator_name = operator_name self.config = config + self.use_skel = config["operators"][operator_name]["use_skel"] self.source_path = config["operators"][operator_name]["source_folder"].format(name=operator_name) self.target_path = config["operators"][operator_name]["target_folder"].format(name=operator_name) self.common_name = config["operators"][operator_name]["common_name"] @@ -47,7 +47,7 @@ class Builder: skeleton_binary_thread = threading.Thread( target=SkeletonBinary, - args=(self.source_path + self.common_name, self.target_path + self.common_name), + args=(self.source_path + self.common_name, self.target_path + self.common_name, self.use_skel), daemon=True, ) ar_thread = threading.Thread( @@ -97,18 +97,30 @@ class Builder: png_to_base64_thread.start() skeleton_binary_thread.join() - - json_base64_thread =threading.Thread( - target=self.__json_to_base64, - args=( - self.file_paths["json"], - data, - ".{}".format(self.config["server"]["operator_folder"]) + self.common_name + ".json", - ), - daemon=True, - ) - json_base64_thread.start() - json_base64_thread.join() + if self.use_skel is True: + skel_base64_thread =threading.Thread( + target=self.__skel_to_base64, + args=( + self.file_paths["skel"], + data, + ".{}".format(self.config["server"]["operator_folder"]) + self.common_name + ".skel", + ), + daemon=True, + ) + skel_base64_thread.start() + skel_base64_thread.join() + else: + json_base64_thread =threading.Thread( + target=self.__json_to_base64, + args=( + self.file_paths["json"], + data, + ".{}".format(self.config["server"]["operator_folder"]) + self.common_name + ".json", + ), + daemon=True, + ) + json_base64_thread.start() + json_base64_thread.join() for thread in png_to_base64_threads: thread.join() @@ -135,6 +147,15 @@ class Builder: dict[key] = result else: return result + + def __skel_to_base64(self, path, dict=None, key=None): + result = encode_binary( + path=path + ) + if dict is not None and key is not None: + dict[key] = result + else: + return result def __atlas_to_base64(self, path, dict=None, key=None): with open(pathlib.Path.cwd().joinpath(path), "r") as f: @@ -146,7 +167,10 @@ class Builder: return result def __png_to_base64(self, path, dict=None, key=None): - result = encode_image(path) + result = encode_binary( + path=path, + type="image/png" + ) if dict is not None and key is not None: dict[key] = result else: diff --git a/lib/config.py b/lib/config.py index 40a531b..d4a659e 100644 --- a/lib/config.py +++ b/lib/config.py @@ -7,18 +7,19 @@ class Config: self.valid_keys = dict( config=dict( server=dict, - operators=dict + operators=dict, ), server=dict( template_folder=str, release_folder=str, - operator_folder=str + operator_folder=str, ), operators=dict( source_folder=str, target_folder=str, common_name=str, - release_folder=str + release_folder=str, + use_skel=bool, ) ) self.__read_config() diff --git a/lib/skeleton_binary.py b/lib/skeleton_binary.py index 42bfe1e..07a17a2 100644 --- a/lib/skeleton_binary.py +++ b/lib/skeleton_binary.py @@ -1,5 +1,6 @@ import pathlib import json +import shutil TransformMode = [ "normal", @@ -62,22 +63,34 @@ CURVE_BEZIER = 2 class SkeletonBinary: - def __init__(self, file_path, save_path, scale=1): + def __init__(self, file_path, save_path, use_skel, scale=1): if file_path.strip().endswith(".skel") is False: file_path += ".skel" - if save_path.strip().endswith(".json") is False: - save_path += ".json" + file_path = pathlib.Path.cwd().joinpath(file_path) + if save_path.strip().endswith(".json") is False or save_path.strip().endswith(".skel") is False: + if use_skel is True: + save_path += ".skel" + else: + save_path += ".json" + save_path = pathlib.Path.cwd().joinpath(save_path) + + if use_skel is True: + shutil.copyfile( + file_path, + save_path + ) + return self.index = 0 self.scale = scale self.dict = dict() try: - with open(pathlib.Path.cwd().joinpath(file_path), "rb") as f: + with open(file_path, "rb") as f: self.binaryData = f.read() self.readSkeletonData() - with open(pathlib.Path.cwd().joinpath(save_path), "w") as f: + with open(save_path, "w") as f: json.dump(self.dict, f) except Exception as e: print(e) @@ -206,7 +219,7 @@ class SkeletonBinary: data["position"] *= self.scale data["spacing"] = self.readFloat() if data["spacingMode"] == "length" or data["spacingMode"] == "fixed": - data["spacing"] = self.scale + data["spacing"] *= self.scale data["rotateMix"] = self.readFloat() data["translateMix"] = self.readFloat() self.dict["path"].append(data) @@ -547,7 +560,6 @@ class SkeletonBinary: e["scaleMix"] = self.readFloat() e["shearMix"] = self.readFloat() timeline[frameIndex] = e - # needs a if statement here to decode dyn_illust_char_1012_skadi2.skel if (frameIndex < frameCount - 1): self.readCurve(frameIndex, timeline) transforms[self.dict["transform"][transformIndex]["name"]] = timeline @@ -561,7 +573,7 @@ class SkeletonBinary: data = self.dict["path"][pathIndex] pathMap = dict() for j in range(self.readInt(True)): - timelineType = self.readByte() + timelineType = self.read() frameCount = self.readInt(True) timeline = [None] * frameCount if timelineType == PATH_POSITION or timelineType == PATH_SPACING: diff --git a/template/assets/runner.js b/template/assets/runner.js index d92bcab..87943fc 100644 --- a/template/assets/runner.js +++ b/template/assets/runner.js @@ -51,7 +51,8 @@ if (!supportsWebGL()) { var resetTime = window.performance.now(); var spinePlayer = new spine.SpinePlayer(e, { - jsonUrl: window.settings.jsonUrl, + jsonUrl: window.settings.jsonUrl, + skelUrl: window.settings.skelUrl, atlasUrl: window.settings.atlasUrl, animation: window.settings.animation, rawDataURIs: window.operator, diff --git a/template/assets/spine-player.js b/template/assets/spine-player.js index f8ce741..fde0574 100644 --- a/template/assets/spine-player.js +++ b/template/assets/spine-player.js @@ -2134,6 +2134,26 @@ var spine; AssetManager.prototype.setRawDataURI = function (path, data) { this.rawDataUris[this.pathPrefix + path] = data; }; + AssetManager.prototype.loadBinary = function (path, success, error) { + var _this = this; + if (success === void 0) { success = null; } + if (error === void 0) { error = null; } + path = this.pathPrefix + path; + this.toLoad++; + this.downloadBinary(path, function (data) { + _this.assets[path] = data; + if (success) + success(path, data); + _this.toLoad--; + _this.loaded++; + }, function (state, responseText) { + _this.errors[path] = "Couldn't load binary " + path + ": status " + status + ", " + responseText; + if (error) + error(path, "Couldn't load binary " + path + ": status " + status + ", " + responseText); + _this.toLoad--; + _this.loaded++; + }); + }; AssetManager.prototype.loadText = function (path, success, error) { var _this = this; if (success === void 0) { success = null; } @@ -3906,6 +3926,840 @@ var spine; spine.Skeleton = Skeleton; })(spine || (spine = {})); var spine; +(function (spine) { + var SkeletonBinary = (function () { + function SkeletonBinary(attachmentLoader) { + this.scale = 1; + this.linkedMeshes = new Array(); + this.attachmentLoader = attachmentLoader; + } + SkeletonBinary.prototype.readSkeletonData = function (binary) { + var scale = this.scale; + var skeletonData = new spine.SkeletonData(); + skeletonData.name = ""; + var input = new BinaryInput(binary); + skeletonData.hash = input.readString(); + skeletonData.version = input.readString(); + // if ("3.8.75" == skeletonData.version) + // throw new Error("Unsupported skeleton data, please export with a newer version of Spine."); + // skeletonData.x = input.readFloat(); + // skeletonData.y = input.readFloat(); + skeletonData.width = input.readFloat(); + skeletonData.height = input.readFloat(); + var nonessential = input.readBoolean(); + if (nonessential) { + skeletonData.fps = input.readFloat(); + skeletonData.imagesPath = input.readString(); + // skeletonData.audioPath = input.readString(); + } + var n = 0; + // n = input.readInt(true); + // for (var i = 0; i < n; i++) + // input.strings.push(input.readString()); + // Bones. + n = input.readInt(true); + for (var i = 0; i < n; i++) { + var name_2 = input.readString(); + var parent_2 = i == 0 ? null : skeletonData.bones[input.readInt(true)]; + var data = new spine.BoneData(i, name_2, parent_2); + data.rotation = input.readFloat(); + data.x = input.readFloat() * scale; + data.y = input.readFloat() * scale; + data.scaleX = input.readFloat(); + data.scaleY = input.readFloat(); + data.shearX = input.readFloat(); + data.shearY = input.readFloat(); + data.length = input.readFloat() * scale; + data.transformMode = SkeletonBinary.TransformModeValues[input.readInt(true)]; + // data.skinRequired = input.readBoolean(); + if (nonessential) + spine.Color.rgba8888ToColor(data.color, input.readInt32()); + skeletonData.bones.push(data); + } + // Slots. + n = input.readInt(true); + for (var i = 0; i < n; i++) { + var slotName = input.readString(); + var boneData = skeletonData.bones[input.readInt(true)]; + var data = new spine.SlotData(i, slotName, boneData); + spine.Color.rgba8888ToColor(data.color, input.readInt32()); + // var darkColor = input.readInt32(); + // if (darkColor != -1) + // spine.Color.rgb888ToColor(data.darkColor = new spine.Color(), darkColor); + // data.attachmentName = input.readStringRef(); + data.attachmentName = input.readString(); + data.blendMode = SkeletonBinary.BlendModeValues[input.readInt(true)]; + skeletonData.slots.push(data); + } + // IK constraints. + n = input.readInt(true); + for (var i = 0, nn = void 0; i < n; i++) { + var data = new spine.IkConstraintData(input.readString()); + data.order = input.readInt(true); + // data.skinRequired = input.readBoolean(); + nn = input.readInt(true); + for (var ii = 0; ii < nn; ii++) + data.bones.push(skeletonData.bones[input.readInt(true)]); + data.target = skeletonData.bones[input.readInt(true)]; + data.mix = input.readFloat(); + // data.softness = input.readFloat() * scale; + data.bendDirection = input.readByte(); + // data.compress = input.readBoolean(); + // data.stretch = input.readBoolean(); + // data.uniform = input.readBoolean(); + skeletonData.ikConstraints.push(data); + } + // Transform constraints. + n = input.readInt(true); + for (var i = 0, nn = void 0; i < n; i++) { + var data = new spine.TransformConstraintData(input.readString()); + data.order = input.readInt(true); + // data.skinRequired = input.readBoolean(); + nn = input.readInt(true); + for (var ii = 0; ii < nn; ii++) + data.bones.push(skeletonData.bones[input.readInt(true)]); + data.target = skeletonData.bones[input.readInt(true)]; + // data.local = input.readBoolean(); + // data.relative = input.readBoolean(); + data.offsetRotation = input.readFloat(); + data.offsetX = input.readFloat() * scale; + data.offsetY = input.readFloat() * scale; + data.offsetScaleX = input.readFloat(); + data.offsetScaleY = input.readFloat(); + data.offsetShearY = input.readFloat(); + data.rotateMix = input.readFloat(); + data.translateMix = input.readFloat(); + data.scaleMix = input.readFloat(); + data.shearMix = input.readFloat(); + skeletonData.transformConstraints.push(data); + } + // Path constraints. + n = input.readInt(true); + for (var i = 0, nn = void 0; i < n; i++) { + var data = new spine.PathConstraintData(input.readString()); + data.order = input.readInt(true); + data.skinRequired = input.readBoolean(); + nn = input.readInt(true); + for (var ii = 0; ii < nn; ii++) + data.bones.push(skeletonData.bones[input.readInt(true)]); + data.target = skeletonData.slots[input.readInt(true)]; + data.positionMode = SkeletonBinary.PositionModeValues[input.readInt(true)]; + data.spacingMode = SkeletonBinary.SpacingModeValues[input.readInt(true)]; + data.rotateMode = SkeletonBinary.RotateModeValues[input.readInt(true)]; + data.offsetRotation = input.readFloat(); + data.position = input.readFloat(); + if (data.positionMode == spine.PositionMode.Fixed) + data.position *= scale; + data.spacing = input.readFloat(); + if (data.spacingMode == spine.SpacingMode.Length || data.spacingMode == spine.SpacingMode.Fixed) + data.spacing *= scale; + data.rotateMix = input.readFloat(); + data.translateMix = input.readFloat(); + skeletonData.pathConstraints.push(data); + } + // Default skin. + var defaultSkin = this.readSkin(input, skeletonData, true, nonessential); + if (defaultSkin != null) { + skeletonData.defaultSkin = defaultSkin; + skeletonData.skins.push(defaultSkin); + } + { + // Skins. + var i = skeletonData.skins.length; + spine.Utils.setArraySize(skeletonData.skins, n = i + input.readInt(true)); + for (; i < n; i++) + skeletonData.skins[i] = this.readSkin(input, skeletonData, false, nonessential); + } + n = this.linkedMeshes.length; + for (var i = 0; i < n; i++) { + var linkedMesh = this.linkedMeshes[i]; + var skin = linkedMesh.skin == null ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin); + if (skin == null) + throw new Error("Skin not found: " + linkedMesh.skin); + var parent_3 = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); + if (parent_3 == null) + throw new Error("Parent mesh not found: " + linkedMesh.parent); + linkedMesh.mesh.deformAttachment = linkedMesh.inheritDeform ? parent_3 : linkedMesh.mesh; + linkedMesh.mesh.setParentMesh(parent_3); + linkedMesh.mesh.updateUVs(); + } + this.linkedMeshes.length = 0; + // Events. + n = input.readInt(true); + for (var i = 0; i < n; i++) { + var data = new spine.EventData(input.readString()); + data.intValue = input.readInt(false); + data.floatValue = input.readFloat(); + data.stringValue = input.readString(); + // data.audioPath = input.readString(); + // if (data.audioPath != null) { + // data.volume = input.readFloat(); + // data.balance = input.readFloat(); + // } + skeletonData.events.push(data); + } + n = input.readInt(true); + for (var i = 0; i < n; i++) + skeletonData.animations.push(this.readAnimation(input, input.readString(), skeletonData)); + return skeletonData; + }; + SkeletonBinary.prototype.readSkin = function (input, skeletonData, defaultSkin, nonessential) { + var skin = null; + var slotCount = 0; + if (defaultSkin) { + slotCount = input.readInt(true); + if (slotCount == 0) + return null; + skin = new spine.Skin("default"); + } + else { + skin = new spine.Skin(input.readString()); + // skin.bones.length = input.readInt(true); + // for (var i = 0, n = skin.bones.length; i < n; i++) + // skin.bones[i] = skeletonData.bones[input.readInt(true)]; + // for (var i = 0, n = input.readInt(true); i < n; i++) + // skin.constraints.push(skeletonData.ikConstraints[input.readInt(true)]); + // for (var i = 0, n = input.readInt(true); i < n; i++) + // skin.constraints.push(skeletonData.transformConstraints[input.readInt(true)]); + // for (var i = 0, n = input.readInt(true); i < n; i++) + // skin.constraints.push(skeletonData.pathConstraints[input.readInt(true)]); + slotCount = input.readInt(true); + } + for (var i = 0; i < slotCount; i++) { + var slotIndex = input.readInt(true); + for (var ii = 0, nn = input.readInt(true); ii < nn; ii++) { + var name_3 = input.readString(); + var attachment = this.readAttachment(input, skeletonData, skin, slotIndex, name_3, nonessential); + if (attachment != null) + skin.addAttachment(slotIndex, name_3, attachment); + } + } + return skin; + }; + SkeletonBinary.prototype.readAttachment = function (input, skeletonData, skin, slotIndex, attachmentName, nonessential) { + var scale = this.scale; + var name = input.readString(); + if (name == null) + name = attachmentName; + var typeIndex = input.readByte(); + var type = SkeletonBinary.AttachmentTypeValues[typeIndex]; + switch (type) { + case spine.AttachmentType.Region: { + var path = input.readString(); + var rotation = input.readFloat(); + var x = input.readFloat(); + var y = input.readFloat(); + var scaleX = input.readFloat(); + var scaleY = input.readFloat(); + var width = input.readFloat(); + var height = input.readFloat(); + var color = input.readInt32(); + if (path == null) + path = name; + var region = this.attachmentLoader.newRegionAttachment(skin, name, path); + if (region == null) + return null; + region.path = path; + region.x = x * scale; + region.y = y * scale; + region.scaleX = scaleX; + region.scaleY = scaleY; + region.rotation = rotation; + region.width = width * scale; + region.height = height * scale; + spine.Color.rgba8888ToColor(region.color, color); + region.updateOffset(); + return region; + } + case spine.AttachmentType.BoundingBox: { + var vertexCount = input.readInt(true); + var vertices = this.readVertices(input, vertexCount); + var color = nonessential ? input.readInt32() : 0; + var box = this.attachmentLoader.newBoundingBoxAttachment(skin, name); + if (box == null) + return null; + box.worldVerticesLength = vertexCount << 1; + box.vertices = vertices.vertices; + box.bones = vertices.bones; + if (nonessential) + spine.Color.rgba8888ToColor(box.color, color); + return box; + } + case spine.AttachmentType.Mesh: { + var path = input.readString(); + var color = input.readInt32(); + var vertexCount = input.readInt(true); + var uvs = this.readFloatArray(input, vertexCount << 1, 1); + var triangles = this.readShortArray(input); + var vertices = this.readVertices(input, vertexCount); + var hullLength = input.readInt(true); + var edges = null; + var width = 0, height = 0; + if (nonessential) { + edges = this.readShortArray(input); + width = input.readFloat(); + height = input.readFloat(); + } + if (path == null) + path = name; + var mesh = this.attachmentLoader.newMeshAttachment(skin, name, path); + if (mesh == null) + return null; + mesh.path = path; + spine.Color.rgba8888ToColor(mesh.color, color); + mesh.bones = vertices.bones; + mesh.vertices = vertices.vertices; + mesh.worldVerticesLength = vertexCount << 1; + mesh.triangles = triangles; + mesh.regionUVs = uvs; + mesh.updateUVs(); + mesh.hullLength = hullLength << 1; + if (nonessential) { + mesh.edges = edges; + mesh.width = width * scale; + mesh.height = height * scale; + } + return mesh; + } + case spine.AttachmentType.LinkedMesh: { + var path = input.readString(); + var color = input.readInt32(); + var skinName = input.readString(); + var parent_4 = input.readString(); + var inheritDeform = input.readBoolean(); + var width = 0, height = 0; + if (nonessential) { + width = input.readFloat(); + height = input.readFloat(); + } + if (path == null) + path = name; + var mesh = this.attachmentLoader.newMeshAttachment(skin, name, path); + if (mesh == null) + return null; + mesh.path = path; + spine.Color.rgba8888ToColor(mesh.color, color); + if (nonessential) { + mesh.width = width * scale; + mesh.height = height * scale; + } + mesh.inheritDeform = inheritDeform; + this.linkedMeshes.push(new LinkedMesh(mesh, skinName, slotIndex, parent_4)); + return mesh; + } + case spine.AttachmentType.Path: { + var closed_1 = input.readBoolean(); + var constantSpeed = input.readBoolean(); + var vertexCount = input.readInt(true); + var vertices = this.readVertices(input, vertexCount); + var lengths = spine.Utils.newArray(vertexCount / 3, 0); + for (var i = 0, n = lengths.length; i < n; i++) + lengths[i] = input.readFloat() * scale; + var color = nonessential ? input.readInt32() : 0; + var path = this.attachmentLoader.newPathAttachment(skin, name); + if (path == null) + return null; + path.closed = closed_1; + path.constantSpeed = constantSpeed; + path.worldVerticesLength = vertexCount << 1; + path.vertices = vertices.vertices; + path.bones = vertices.bones; + path.lengths = lengths; + if (nonessential) + spine.Color.rgba8888ToColor(path.color, color); + return path; + } + case spine.AttachmentType.Point: { + var rotation = input.readFloat(); + var x = input.readFloat(); + var y = input.readFloat(); + var color = nonessential ? input.readInt32() : 0; + var point = this.attachmentLoader.newPointAttachment(skin, name); + if (point == null) + return null; + point.x = x * scale; + point.y = y * scale; + point.rotation = rotation; + if (nonessential) + spine.Color.rgba8888ToColor(point.color, color); + return point; + } + case spine.AttachmentType.Clipping: { + var endSlotIndex = input.readInt(true); + var vertexCount = input.readInt(true); + var vertices = this.readVertices(input, vertexCount); + var color = nonessential ? input.readInt32() : 0; + var clip = this.attachmentLoader.newClippingAttachment(skin, name); + if (clip == null) + return null; + clip.endSlot = skeletonData.slots[endSlotIndex]; + clip.worldVerticesLength = vertexCount << 1; + clip.vertices = vertices.vertices; + clip.bones = vertices.bones; + if (nonessential) + spine.Color.rgba8888ToColor(clip.color, color); + return clip; + } + } + return null; + }; + SkeletonBinary.prototype.readVertices = function (input, vertexCount) { + var verticesLength = vertexCount << 1; + var vertices = new Vertices(); + var scale = this.scale; + if (!input.readBoolean()) { + vertices.vertices = this.readFloatArray(input, verticesLength, scale); + return vertices; + } + var weights = new Array(); + var bonesArray = new Array(); + for (var i = 0; i < vertexCount; i++) { + var boneCount = input.readInt(true); + bonesArray.push(boneCount); + for (var ii = 0; ii < boneCount; ii++) { + bonesArray.push(input.readInt(true)); + weights.push(input.readFloat() * scale); + weights.push(input.readFloat() * scale); + weights.push(input.readFloat()); + } + } + vertices.vertices = spine.Utils.toFloatArray(weights); + vertices.bones = bonesArray; + return vertices; + }; + SkeletonBinary.prototype.readFloatArray = function (input, n, scale) { + var array = new Array(n); + if (scale == 1) { + for (var i = 0; i < n; i++) + array[i] = input.readFloat(); + } + else { + for (var i = 0; i < n; i++) + array[i] = input.readFloat() * scale; + } + return array; + }; + SkeletonBinary.prototype.readShortArray = function (input) { + var n = input.readInt(true); + var array = new Array(n); + for (var i = 0; i < n; i++) + array[i] = input.readShort(); + return array; + }; + SkeletonBinary.prototype.readAnimation = function (input, name, skeletonData) { + var timelines = new Array(); + var scale = this.scale; + var duration = 0; + var tempColor1 = new spine.Color(); + var tempColor2 = new spine.Color(); + // Slot timelines. + for (var i = 0, n = input.readInt(true); i < n; i++) { + var slotIndex = input.readInt(true); + for (var ii = 0, nn = input.readInt(true); ii < nn; ii++) { + var timelineType = input.readByte(); + var frameCount = input.readInt(true); + switch (timelineType) { + case SkeletonBinary.SLOT_ATTACHMENT: { + var timeline = new spine.AttachmentTimeline(frameCount); + timeline.slotIndex = slotIndex; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) + timeline.setFrame(frameIndex, input.readFloat(), input.readString()); + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[frameCount - 1]); + break; + } + case SkeletonBinary.SLOT_COLOR: { + var timeline = new spine.ColorTimeline(frameCount); + timeline.slotIndex = slotIndex; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + var time = input.readFloat(); + spine.Color.rgba8888ToColor(tempColor1, input.readInt32()); + timeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.ColorTimeline.ENTRIES]); + break; + } + case SkeletonBinary.SLOT_TWO_COLOR: { + var timeline = new spine.TwoColorTimeline(frameCount); + timeline.slotIndex = slotIndex; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + var time = input.readFloat(); + spine.Color.rgba8888ToColor(tempColor1, input.readInt32()); + spine.Color.rgb888ToColor(tempColor2, input.readInt32()); + timeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a, tempColor2.r, tempColor2.g, tempColor2.b); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.TwoColorTimeline.ENTRIES]); + break; + } + } + } + } + // Bone timelines. + for (var i = 0, n = input.readInt(true); i < n; i++) { + var boneIndex = input.readInt(true); + for (var ii = 0, nn = input.readInt(true); ii < nn; ii++) { + var timelineType = input.readByte(); + var frameCount = input.readInt(true); + switch (timelineType) { + case SkeletonBinary.BONE_ROTATE: { + var timeline = new spine.RotateTimeline(frameCount); + timeline.boneIndex = boneIndex; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat()); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.RotateTimeline.ENTRIES]); + break; + } + case SkeletonBinary.BONE_TRANSLATE: + case SkeletonBinary.BONE_SCALE: + case SkeletonBinary.BONE_SHEAR: { + var timeline = void 0; + var timelineScale = 1; + if (timelineType == SkeletonBinary.BONE_SCALE) + timeline = new spine.ScaleTimeline(frameCount); + else if (timelineType == SkeletonBinary.BONE_SHEAR) + timeline = new spine.ShearTimeline(frameCount); + else { + timeline = new spine.TranslateTimeline(frameCount); + timelineScale = scale; + } + timeline.boneIndex = boneIndex; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale, input.readFloat() * timelineScale); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.TranslateTimeline.ENTRIES]); + break; + } + } + } + } + // IK constraint timelines. + for (var i = 0, n = input.readInt(true); i < n; i++) { + var index = input.readInt(true); + var frameCount = input.readInt(true); + var timeline = new spine.IkConstraintTimeline(frameCount); + timeline.ikConstraintIndex = index; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + // timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat() * scale, input.readByte(), input.readBoolean(), input.readBoolean()); + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte(), false, false); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.IkConstraintTimeline.ENTRIES]); + } + // Transform constraint timelines. + for (var i = 0, n = input.readInt(true); i < n; i++) { + var index = input.readInt(true); + var frameCount = input.readInt(true); + var timeline = new spine.TransformConstraintTimeline(frameCount); + timeline.transformConstraintIndex = index; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat()); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.TransformConstraintTimeline.ENTRIES]); + } + // Path constraint timelines. + for (var i = 0, n = input.readInt(true); i < n; i++) { + var index = input.readInt(true); + var data = skeletonData.pathConstraints[index]; + for (var ii = 0, nn = input.readInt(true); ii < nn; ii++) { + var timelineType = input.readByte(); + var frameCount = input.readInt(true); + switch (timelineType) { + case SkeletonBinary.PATH_POSITION: + case SkeletonBinary.PATH_SPACING: { + var timeline = void 0; + var timelineScale = 1; + if (timelineType == SkeletonBinary.PATH_SPACING) { + timeline = new spine.PathConstraintSpacingTimeline(frameCount); + if (data.spacingMode == spine.SpacingMode.Length || data.spacingMode == spine.SpacingMode.Fixed) + timelineScale = scale; + } + else { + timeline = new spine.PathConstraintPositionTimeline(frameCount); + if (data.positionMode == spine.PositionMode.Fixed) + timelineScale = scale; + } + timeline.pathConstraintIndex = index; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.PathConstraintPositionTimeline.ENTRIES]); + break; + } + case SkeletonBinary.PATH_MIX: { + var timeline = new spine.PathConstraintMixTimeline(frameCount); + timeline.pathConstraintIndex = index; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat()); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.PathConstraintMixTimeline.ENTRIES]); + break; + } + } + } + } + // Deform timelines. + for (var i = 0, n = input.readInt(true); i < n; i++) { + var skin = skeletonData.skins[input.readInt(true)]; + for (var ii = 0, nn = input.readInt(true); ii < nn; ii++) { + var slotIndex = input.readInt(true); + for (var iii = 0, nnn = input.readInt(true); iii < nnn; iii++) { + var attachment = skin.getAttachment(slotIndex, input.readString()); + var weighted = attachment.bones != null; + var vertices = attachment.vertices; + var deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + var frameCount = input.readInt(true); + var timeline = new spine.DeformTimeline(frameCount); + timeline.slotIndex = slotIndex; + timeline.attachment = attachment; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + var time = input.readFloat(); + var deform = void 0; + var end = input.readInt(true); + if (end == 0) + deform = weighted ? spine.Utils.newFloatArray(deformLength) : vertices; + else { + deform = spine.Utils.newFloatArray(deformLength); + var start = input.readInt(true); + end += start; + if (scale == 1) { + for (var v = start; v < end; v++) + deform[v] = input.readFloat(); + } + else { + for (var v = start; v < end; v++) + deform[v] = input.readFloat() * scale; + } + if (!weighted) { + for (var v = 0, vn = deform.length; v < vn; v++) + deform[v] += vertices[v]; + } + } + timeline.setFrame(frameIndex, time, deform); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[frameCount - 1]); + } + } + } + // Draw order timeline. + var drawOrderCount = input.readInt(true); + if (drawOrderCount > 0) { + var timeline = new spine.DrawOrderTimeline(drawOrderCount); + var slotCount = skeletonData.slots.length; + for (var i = 0; i < drawOrderCount; i++) { + var time = input.readFloat(); + var offsetCount = input.readInt(true); + var drawOrder = spine.Utils.newArray(slotCount, 0); + for (var ii = slotCount - 1; ii >= 0; ii--) + drawOrder[ii] = -1; + var unchanged = spine.Utils.newArray(slotCount - offsetCount, 0); + var originalIndex = 0, unchangedIndex = 0; + for (var ii = 0; ii < offsetCount; ii++) { + var slotIndex = input.readInt(true); + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + drawOrder[originalIndex + input.readInt(true)] = originalIndex++; + } + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + for (var ii = slotCount - 1; ii >= 0; ii--) + if (drawOrder[ii] == -1) + drawOrder[ii] = unchanged[--unchangedIndex]; + timeline.setFrame(i, time, drawOrder); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[drawOrderCount - 1]); + } + // Event timeline. + var eventCount = input.readInt(true); + if (eventCount > 0) { + var timeline = new spine.EventTimeline(eventCount); + for (var i = 0; i < eventCount; i++) { + var time = input.readFloat(); + var eventData = skeletonData.events[input.readInt(true)]; + var event_4 = new spine.Event(time, eventData); + event_4.intValue = input.readInt(false); + event_4.floatValue = input.readFloat(); + event_4.stringValue = input.readBoolean() ? input.readString() : eventData.stringValue; + // if (event_4.data.audioPath != null) { + // event_4.volume = input.readFloat(); + // event_4.balance = input.readFloat(); + // } + timeline.setFrame(i, event_4); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[eventCount - 1]); + } + return new spine.Animation(name, timelines, duration); + }; + SkeletonBinary.prototype.readCurve = function (input, frameIndex, timeline) { + switch (input.readByte()) { + case SkeletonBinary.CURVE_STEPPED: + timeline.setStepped(frameIndex); + break; + case SkeletonBinary.CURVE_BEZIER: + this.setCurve(timeline, frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat()); + break; + } + }; + SkeletonBinary.prototype.setCurve = function (timeline, frameIndex, cx1, cy1, cx2, cy2) { + timeline.setCurve(frameIndex, cx1, cy1, cx2, cy2); + }; + SkeletonBinary.AttachmentTypeValues = [0, 1, 2, 3, 4, 5, 6]; + SkeletonBinary.TransformModeValues = [spine.TransformMode.Normal, spine.TransformMode.OnlyTranslation, spine.TransformMode.NoRotationOrReflection, spine.TransformMode.NoScale, spine.TransformMode.NoScaleOrReflection]; + SkeletonBinary.PositionModeValues = [spine.PositionMode.Fixed, spine.PositionMode.Percent]; + SkeletonBinary.SpacingModeValues = [spine.SpacingMode.Length, spine.SpacingMode.Fixed, spine.SpacingMode.Percent]; + SkeletonBinary.RotateModeValues = [spine.RotateMode.Tangent, spine.RotateMode.Chain, spine.RotateMode.ChainScale]; + SkeletonBinary.BlendModeValues = [spine.BlendMode.Normal, spine.BlendMode.Additive, spine.BlendMode.Multiply, spine.BlendMode.Screen]; + SkeletonBinary.BONE_ROTATE = 0; + SkeletonBinary.BONE_TRANSLATE = 1; + SkeletonBinary.BONE_SCALE = 2; + SkeletonBinary.BONE_SHEAR = 3; + SkeletonBinary.SLOT_ATTACHMENT = 0; + SkeletonBinary.SLOT_COLOR = 1; + SkeletonBinary.SLOT_TWO_COLOR = 2; + SkeletonBinary.PATH_POSITION = 0; + SkeletonBinary.PATH_SPACING = 1; + SkeletonBinary.PATH_MIX = 2; + SkeletonBinary.CURVE_LINEAR = 0; + SkeletonBinary.CURVE_STEPPED = 1; + SkeletonBinary.CURVE_BEZIER = 2; + return SkeletonBinary; + }()); + spine.SkeletonBinary = SkeletonBinary; + var BinaryInput = (function () { + function BinaryInput(data, strings, index, buffer) { + if (strings === void 0) { strings = new Array(); } + if (index === void 0) { index = 0; } + if (buffer === void 0) { buffer = new DataView(data.buffer); } + this.strings = strings; + this.index = index; + this.buffer = buffer; + } + BinaryInput.prototype.readByte = function () { + return this.buffer.getInt8(this.index++); + }; + BinaryInput.prototype.readShort = function () { + var value = this.buffer.getInt16(this.index); + this.index += 2; + return value; + }; + BinaryInput.prototype.readInt32 = function () { + var value = this.buffer.getInt32(this.index); + this.index += 4; + return value; + }; + BinaryInput.prototype.readInt = function (optimizePositive) { + var b = this.readByte(); + var result = b & 0x7F; + if ((b & 0x80) != 0) { + b = this.readByte(); + result |= (b & 0x7F) << 7; + if ((b & 0x80) != 0) { + b = this.readByte(); + result |= (b & 0x7F) << 14; + if ((b & 0x80) != 0) { + b = this.readByte(); + result |= (b & 0x7F) << 21; + if ((b & 0x80) != 0) { + b = this.readByte(); + result |= (b & 0x7F) << 28; + } + } + } + } + return optimizePositive ? result : ((result >>> 1) ^ -(result & 1)); + }; + BinaryInput.prototype.readStringRef = function () { + var index = this.readInt(true); + return index == 0 ? null : this.strings[index - 1]; + }; + BinaryInput.prototype.readString = function () { + var byteCount = this.readInt(true); + switch (byteCount) { + case 0: + return null; + case 1: + return ""; + } + byteCount--; + var chars = ""; + var charCount = 0; + for (var i = 0; i < byteCount;) { + var b = this.readByte(); + switch (b >> 4) { + case 12: + case 13: + chars += String.fromCharCode(((b & 0x1F) << 6 | this.readByte() & 0x3F)); + i += 2; + break; + case 14: + chars += String.fromCharCode(((b & 0x0F) << 12 | (this.readByte() & 0x3F) << 6 | this.readByte() & 0x3F)); + i += 3; + break; + default: + chars += String.fromCharCode(b); + i++; + } + } + return chars; + }; + BinaryInput.prototype.readFloat = function () { + var value = this.buffer.getFloat32(this.index); + this.index += 4; + return value; + }; + BinaryInput.prototype.readBoolean = function () { + return this.readByte() != 0; + }; + return BinaryInput; + }()); + var LinkedMesh = (function () { + function LinkedMesh(mesh, skin, slotIndex, parent) { + this.mesh = mesh; + this.skin = skin; + this.slotIndex = slotIndex; + this.parent = parent; + } + return LinkedMesh; + }()); + var Vertices = (function () { + function Vertices(bones, vertices) { + if (bones === void 0) { bones = null; } + if (vertices === void 0) { vertices = null; } + this.bones = bones; + this.vertices = vertices; + } + return Vertices; + }()); +})(spine || (spine = {})); +var spine; (function (spine) { var SkeletonBounds = (function () { function SkeletonBounds() { @@ -6131,6 +6985,17 @@ var spine; this.a = 1; return this; }; + Color.rgba8888ToColor = function (color, value) { + color.r = ((value & 0xff000000) >>> 24) / 255; + color.g = ((value & 0x00ff0000) >>> 16) / 255; + color.b = ((value & 0x0000ff00) >>> 8) / 255; + color.a = ((value & 0x000000ff)) / 255; + }; + Color.rgb888ToColor = function (color, value) { + color.r = ((value & 0x00ff0000) >>> 16) / 255; + color.g = ((value & 0x0000ff00) >>> 8) / 255; + color.b = ((value & 0x000000ff)) / 255; + }; Color.WHITE = new Color(1, 1, 1, 1); Color.RED = new Color(1, 0, 0, 1); Color.GREEN = new Color(0, 1, 0, 1); @@ -9645,8 +10510,8 @@ var spine; SpinePlayer.prototype.validateConfig = function (config) { if (!config) throw new Error("Please pass a configuration to new.spine.SpinePlayer()."); - if (!config.jsonUrl) - throw new Error("Please specify the URL of the skeleton JSON file."); + if (!config.jsonUrl && !config.skelUrl) + throw new Error("Please specify the URL of the skeleton JSON or .skel file."); if (!config.atlasUrl) throw new Error("Please specify the URL of the atlas file."); if (!config.alpha) @@ -9744,7 +10609,10 @@ var spine; this.assetManager.setRawDataURI(path, data); } } - this.assetManager.loadText(config.jsonUrl); + if (config.jsonUrl) + this.assetManager.loadText(config.jsonUrl); + else + this.assetManager.loadBinary(config.skelUrl); this.assetManager.loadTextureAtlas(config.atlasUrl); if (config.backgroundImage && config.backgroundImage.url) this.assetManager.loadTexture(config.backgroundImage.url); @@ -10093,15 +10961,28 @@ var spine; return; } var atlas = this.assetManager.get(this.config.atlasUrl); - var jsonText = this.assetManager.get(this.config.jsonUrl); - var json = new spine.SkeletonJson(new spine.AtlasAttachmentLoader(atlas)); var skeletonData; - try { - skeletonData = json.readSkeletonData(jsonText); + if (this.config.jsonUrl) { + var jsonText = this.assetManager.get(this.config.jsonUrl); + var json = new spine.SkeletonJson(new spine.AtlasAttachmentLoader(atlas)); + try { + skeletonData = json.readSkeletonData(jsonText); + } + catch (e) { + this.showError("Error: could not load skeleton .json.

" + e.toString()); + return; + } } - catch (e) { - this.showError("Error: could not load skeleton .json.

" + escapeHtml(JSON.stringify(e))); - return; + else { + var binaryData = this.assetManager.get(this.config.skelUrl); + var binary = new spine.SkeletonBinary(new spine.AtlasAttachmentLoader(atlas)); + try { + skeletonData = binary.readSkeletonData(binaryData); + } + catch (e) { + this.showError("Error: could not load skeleton .skel.

" + e.toString()); + return; + } } this.skeleton = new spine.Skeleton(skeletonData); var stateData = new spine.AnimationStateData(skeletonData);