diff --git a/spine-c/spine-c/src/spine/Color.c b/spine-c/spine-c/src/spine/Color.c index 02168ee3c..48ec062c2 100644 --- a/spine-c/spine-c/src/spine/Color.c +++ b/spine-c/spine-c/src/spine/Color.c @@ -44,6 +44,7 @@ void spColor_setFromFloats(spColor* self, float r, float g, float b, float a) { self->g = g; self->b = b; self->a = a; + spColor_clamp(self); } void spColor_setFromColor(spColor* self, spColor* otherColor) { diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java index ecff30cf0..2d053ce41 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java @@ -127,7 +127,7 @@ public class Skin { if (name == null) throw new IllegalArgumentException("name cannot be null."); this.slotIndex = slotIndex; this.name = name; - hashCode = 31 * (31 + name.hashCode()) + slotIndex; + hashCode = name.hashCode() + slotIndex * 37; } public int hashCode () { diff --git a/spine-ts/build/spine-all.d.ts b/spine-ts/build/spine-all.d.ts index 165b4326d..3117af273 100644 --- a/spine-ts/build/spine-all.d.ts +++ b/spine-ts/build/spine-all.d.ts @@ -670,7 +670,7 @@ declare module spine { findIkConstraint(constraintName: string): IkConstraint; findTransformConstraint(constraintName: string): TransformConstraint; findPathConstraint(constraintName: string): PathConstraint; - getBounds(offset: Vector2, size: Vector2, temp: Array): void; + getBounds(offset: Vector2, size: Vector2, temp?: Array): void; update(delta: number): void; } } @@ -1772,6 +1772,76 @@ declare module spine.threejs { static toThreeJsTextureWrap(wrap: TextureWrap): THREE.Wrapping; } } +declare module spine { + interface SpinePlayerConfig { + jsonUrl: string; + atlasUrl: string; + animation: string; + animations: string[]; + skin: string; + skins: string[]; + debug: { + bones: boolean; + regions: boolean; + meshes: boolean; + bounds: boolean; + paths: boolean; + clipping: boolean; + points: boolean; + hulls: boolean; + }; + viewport: { + x: number; + y: number; + width: number; + height: number; + }; + alpha: boolean; + backgroundColor: string; + backgroundImage: { + url: string; + x: number; + y: number; + width: number; + height: number; + }; + premultipliedAlpha: boolean; + success: (widget: SpineWidget) => void; + error: (widget: SpineWidget, msg: string) => void; + } + class SpinePlayer { + private config; + private sceneRenderer; + private dom; + private playerControls; + private canvas; + private timelineSlider; + private playButton; + private context; + private loadingScreen; + private assetManager; + private loaded; + private skeleton; + private animationState; + private time; + private paused; + private playTime; + private speed; + constructor(parent: HTMLElement, config: SpinePlayerConfig); + validateConfig(config: SpinePlayerConfig): SpinePlayerConfig; + render(): HTMLElement; + showSpeedDialog(): void; + showAnimationsDialog(): void; + showSkinsDialog(): void; + showSettingsDialog(): void; + drawFrame(requestNextFrame?: boolean): void; + scale(sourceWidth: number, sourceHeight: number, targetWidth: number, targetHeight: number): Vector2; + loadSkeleton(): void; + private play(); + private pause(); + private resize(); + } +} declare module spine { class SpineWidget { skeleton: Skeleton; diff --git a/spine-ts/build/spine-all.js b/spine-ts/build/spine-all.js index 13f4ac0fe..de8d4ddf0 100644 --- a/spine-ts/build/spine-all.js +++ b/spine-ts/build/spine-all.js @@ -3826,6 +3826,7 @@ var spine; return null; }; Skeleton.prototype.getBounds = function (offset, size, temp) { + if (temp === void 0) { temp = new Array(2); } if (offset == null) throw new Error("offset cannot be null."); if (size == null) @@ -7226,7 +7227,7 @@ var spine; } Input.prototype.setupCallbacks = function (element) { var _this = this; - element.addEventListener("mousedown", function (ev) { + var mouseDown = function (ev) { if (ev instanceof MouseEvent) { var rect = element.getBoundingClientRect(); var x = ev.clientX - rect.left; @@ -7238,9 +7239,11 @@ var spine; _this.lastX = x; _this.lastY = y; _this.buttonDown = true; + document.addEventListener("mousemove", mouseMove); + document.addEventListener("mouseup", mouseUp); } - }, true); - element.addEventListener("mousemove", function (ev) { + }; + var mouseMove = function (ev) { if (ev instanceof MouseEvent) { var rect = element.getBoundingClientRect(); var x = ev.clientX - rect.left; @@ -7257,8 +7260,8 @@ var spine; _this.lastX = x; _this.lastY = y; } - }, true); - element.addEventListener("mouseup", function (ev) { + }; + var mouseUp = function (ev) { if (ev instanceof MouseEvent) { var rect = element.getBoundingClientRect(); var x = ev.clientX - rect.left; @@ -7270,8 +7273,13 @@ var spine; _this.lastX = x; _this.lastY = y; _this.buttonDown = false; + document.removeEventListener("mousemove", mouseMove); + document.removeEventListener("mouseup", mouseUp); } - }, true); + }; + element.addEventListener("mousedown", mouseDown, true); + element.addEventListener("mousemove", mouseMove, true); + element.addEventListener("mouseup", mouseUp, true); element.addEventListener("touchstart", function (ev) { if (_this.currTouch != null) return; @@ -7433,11 +7441,11 @@ var spine; var renderer = this.renderer; var canvas = renderer.canvas; var gl = renderer.context.gl; + renderer.resize(webgl.ResizeMode.Stretch); var oldX = renderer.camera.position.x, oldY = renderer.camera.position.y; renderer.camera.position.set(canvas.width / 2, canvas.height / 2, 0); renderer.camera.viewportWidth = canvas.width; renderer.camera.viewportHeight = canvas.height; - renderer.resize(webgl.ResizeMode.Stretch); if (!complete) { gl.clearColor(this.backgroundColor.r, this.backgroundColor.g, this.backgroundColor.b, this.backgroundColor.a); gl.clear(gl.COLOR_BUFFER_BIT); @@ -10055,6 +10063,533 @@ var spine; })(threejs = spine.threejs || (spine.threejs = {})); })(spine || (spine = {})); var spine; +(function (spine) { + var Popup = (function () { + function Popup(parent, htmlContent) { + this.dom = createElement("\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t"); + this.dom.innerHTML = htmlContent; + parent.appendChild(this.dom); + } + Popup.prototype.show = function () { + var _this = this; + this.dom.classList.remove("spine-player-hidden"); + var justClicked = true; + var windowClickListener = function (event) { + if (justClicked) { + justClicked = false; + return; + } + if (!isContained(_this.dom, event.target)) { + _this.dom.parentNode.removeChild(_this.dom); + window.removeEventListener("click", windowClickListener); + } + }; + window.addEventListener("click", windowClickListener); + }; + return Popup; + }()); + var Switch = (function () { + function Switch(text) { + this.text = text; + this.enabled = false; + } + Switch.prototype.render = function () { + var _this = this; + this["switch"] = createElement("\n\t\t\t\t
\n\t\t\t\t\t" + this.text + "\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t"); + this["switch"].addEventListener("click", function () { + _this.setEnabled(!_this.enabled); + if (_this.change) + _this.change(_this.enabled); + }); + return this["switch"]; + }; + Switch.prototype.setEnabled = function (enabled) { + if (enabled) + this["switch"].classList.add("active"); + else + this["switch"].classList.remove("active"); + this.enabled = enabled; + }; + Switch.prototype.isEnabled = function () { + return this.enabled; + }; + return Switch; + }()); + var Slider = (function () { + function Slider() { + } + Slider.prototype.render = function () { + var _this = this; + this.slider = createElement("\n\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t"); + this.value = findWithClass(this.slider, "spine-player-slider-value")[0]; + this.setValue(0); + var input = new spine.webgl.Input(this.slider); + var dragging = false; + input.addListener({ + down: function (x, y) { + dragging = true; + }, + up: function (x, y) { + dragging = false; + var percentage = x / _this.slider.clientWidth; + percentage = Math.max(0, Math.min(percentage, 1)); + _this.setValue(x / _this.slider.clientWidth); + if (_this.change) + _this.change(percentage); + }, + moved: function (x, y) { + if (dragging) { + var percentage = x / _this.slider.clientWidth; + percentage = Math.max(0, Math.min(percentage, 1)); + _this.setValue(x / _this.slider.clientWidth); + if (_this.change) + _this.change(percentage); + } + }, + dragged: function (x, y) { + var percentage = x / _this.slider.clientWidth; + percentage = Math.max(0, Math.min(percentage, 1)); + _this.setValue(x / _this.slider.clientWidth); + if (_this.change) + _this.change(percentage); + } + }); + return this.slider; + }; + Slider.prototype.setValue = function (percentage) { + percentage = Math.max(0, Math.min(1, percentage)); + this.value.style.width = "" + (percentage * 100) + "%"; + }; + return Slider; + }()); + var SpinePlayer = (function () { + function SpinePlayer(parent, config) { + this.config = config; + this.time = new spine.TimeKeeper(); + this.paused = true; + this.playTime = 0; + this.speed = 1; + this.config = this.validateConfig(config); + parent.appendChild(this.render()); + } + 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.atlasUrl) + throw new Error("Please specify the URL of the atlas file."); + if (!config.alpha) + config.alpha = false; + if (!config.backgroundColor) + config.backgroundColor = "#000000"; + if (!config.premultipliedAlpha) + config.premultipliedAlpha = false; + if (!config.success) + config.success = function (widget) { }; + if (!config.error) + config.error = function (widget, msg) { }; + if (!config.debug) + config.debug = { + bones: false, + regions: false, + meshes: false, + bounds: false, + clipping: false, + paths: false, + points: false, + hulls: false + }; + if (!config.debug.bones) + config.debug.bones = false; + if (!config.debug.bounds) + config.debug.bounds = false; + if (!config.debug.clipping) + config.debug.clipping = false; + if (!config.debug.hulls) + config.debug.hulls = false; + if (!config.debug.paths) + config.debug.paths = false; + if (!config.debug.points) + config.debug.points = false; + if (!config.debug.regions) + config.debug.regions = false; + if (!config.debug.meshes) + config.debug.meshes = false; + if (config.animations && config.animation) { + if (config.animations.indexOf(config.animation) < 0) + throw new Error("Default animation " + config.animation + " is not contained in the list of selectable animations."); + } + if (config.skins && config.skin) { + if (config.skins.indexOf(config.skin) < 0) + throw new Error("Default skin " + config.skin + " is not contained in the list of selectable skins."); + } + return config; + }; + SpinePlayer.prototype.render = function () { + var _this = this; + var config = this.config; + var dom = this.dom = createElement("\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t"); + this.canvas = findWithClass(dom, "spine-player-canvas")[0]; + var webglConfig = { alpha: config.alpha }; + this.context = new spine.webgl.ManagedWebGLRenderingContext(this.canvas, webglConfig); + this.sceneRenderer = new spine.webgl.SceneRenderer(this.canvas, this.context, true); + this.loadingScreen = new spine.webgl.LoadingScreen(this.sceneRenderer); + this.assetManager = new spine.webgl.AssetManager(this.context); + this.assetManager.loadText(config.jsonUrl); + this.assetManager.loadTextureAtlas(config.atlasUrl); + if (config.backgroundImage && config.backgroundImage.url) + this.assetManager.loadTexture(config.backgroundImage.url); + requestAnimationFrame(function () { return _this.drawFrame(); }); + this.playerControls = findWithClass(dom, "spine-player-controls")[0]; + var timeline = findWithClass(dom, "spine-player-timeline")[0]; + this.timelineSlider = new Slider(); + timeline.appendChild(this.timelineSlider.render()); + this.playButton = findWithId(dom, "spine-player-button-play-pause")[0]; + var speedButton = findWithId(dom, "spine-player-button-speed")[0]; + var animationButton = findWithId(dom, "spine-player-button-animation")[0]; + var skinButton = findWithId(dom, "spine-player-button-skin")[0]; + var settingsButton = findWithId(dom, "spine-player-button-settings")[0]; + var fullscreenButton = findWithId(dom, "spine-player-button-fullscreen")[0]; + this.playButton.onclick = function () { + if (_this.paused) + _this.play(); + else + _this.pause(); + }; + speedButton.onclick = function () { + _this.showSpeedDialog(); + }; + animationButton.onclick = function () { + _this.showAnimationsDialog(); + }; + skinButton.onclick = function () { + _this.showSkinsDialog(); + }; + settingsButton.onclick = function () { + _this.showSettingsDialog(); + }; + fullscreenButton.onclick = function () { + var doc = document; + if (doc.fullscreenElement || doc.webkitFullscreenElement || doc.mozFullScreenElement || doc.msFullscreenElement) { + if (doc.exitFullscreen) + doc.exitFullscreen(); + else if (doc.mozCancelFullScreen) + doc.mozCancelFullScreen(); + else if (doc.webkitExitFullscreen) + doc.webkitExitFullscreen(); + else if (doc.msExitFullscreen) + doc.msExitFullscreen(); + } + else { + var player = dom; + if (player.requestFullscreen) + player.requestFullscreen(); + else if (player.webkitRequestFullScreen) + player.webkitRequestFullScreen(); + else if (player.mozRequestFullScreen) + player.mozRequestFullScreen(); + else if (player.msRequestFullscreen) + player.msRequestFullscreen(); + } + }; + window.onresize = function () { + _this.drawFrame(false); + }; + return dom; + }; + SpinePlayer.prototype.showSpeedDialog = function () { + var _this = this; + var popup = new Popup(this.playerControls, "\n\t\t\t\t
\n\t\t\t\t\t
Speed
\n\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
0.1x
\n\t\t\t\t\t\t\t
1x
\n\t\t\t\t\t\t\t
2x
\n\t\t\t\t\t\t
\n\t\t\t\t\t
\n\t\t\t\t
\n\t\t\t"); + var sliderParent = findWithClass(popup.dom, "spine-player-speed-slider")[0]; + var slider = new Slider(); + sliderParent.appendChild(slider.render()); + slider.setValue(this.speed / 2); + slider.change = function (percentage) { + _this.speed = percentage * 2; + }; + popup.show(); + }; + SpinePlayer.prototype.showAnimationsDialog = function () { + var _this = this; + if (!this.skeleton || this.skeleton.data.animations.length == 0) + return; + var popup = new Popup(this.playerControls, "\n\t\t\t\t
Animations
\n\t\t\t\t
\n\t\t\t\t\n\t\t\t"); + var rows = findWithClass(popup.dom, "spine-player-list")[0]; + this.skeleton.data.animations.forEach(function (animation) { + if (_this.config.animations && _this.config.animations.indexOf(animation.name) < 0) { + return; + } + var row = createElement("\n\t\t\t\t\t
  • \n\t\t\t\t\t\t
    \n\t\t\t\t\t\t
    \n\t\t\t\t\t\t
    \n\t\t\t\t\t\t
    \n\t\t\t\t\t
  • \n\t\t\t\t"); + if (animation.name == _this.config.animation) + row.classList.add("selected"); + findWithClass(row, "selectable-text")[0].innerText = animation.name; + rows.appendChild(row); + row.onclick = function () { + removeClass(rows.children, "selected"); + row.classList.add("selected"); + _this.config.animation = animation.name; + _this.playTime = 0; + _this.animationState.setAnimation(0, _this.config.animation, true); + }; + }); + popup.show(); + }; + SpinePlayer.prototype.showSkinsDialog = function () { + var _this = this; + if (!this.skeleton || this.skeleton.data.animations.length == 0) + return; + var popup = new Popup(this.playerControls, "\n\t\t\t\t
    Skins
    \n\t\t\t\t
    \n\t\t\t\t\n\t\t\t"); + var rows = findWithClass(popup.dom, "spine-player-list")[0]; + this.skeleton.data.skins.forEach(function (skin) { + if (_this.config.skins && _this.config.skins.indexOf(skin.name) < 0) { + return; + } + var row = createElement("\n\t\t\t\t\t
  • \n\t\t\t\t\t\t
    \n\t\t\t\t\t\t
    \n\t\t\t\t\t\t
    \n\t\t\t\t\t\t
    \n\t\t\t\t\t
  • \n\t\t\t\t"); + if (skin.name == _this.config.skin) + row.classList.add("selected"); + findWithClass(row, "selectable-text")[0].innerText = skin.name; + rows.appendChild(row); + row.onclick = function () { + removeClass(rows.children, "selected"); + row.classList.add("selected"); + _this.config.skin = skin.name; + _this.skeleton.setSkinByName(_this.config.skin); + _this.skeleton.setSlotsToSetupPose(); + }; + }); + popup.show(); + }; + SpinePlayer.prototype.showSettingsDialog = function () { + var _this = this; + if (!this.skeleton || this.skeleton.data.animations.length == 0) + return; + var popup = new Popup(this.playerControls, "\n\t\t\t\t
    Debug
    \n\t\t\t\t
    \n\t\t\t\t