From c45644fe4013b39d2d31e1410e92b30ebcac0360 Mon Sep 17 00:00:00 2001 From: krmbn0576 Date: Mon, 12 Nov 2018 18:35:53 +0900 Subject: [PATCH 1/3] Merge RMMV version 1.6.1 --- js/libs/pixi-picture.js | 1077 +- js/libs/pixi-tilemap.js | 1761 ++- js/libs/pixi.js | 19145 +++++++++++++++--------- js/rpg_core/Graphics.js | 6 +- js/rpg_core/Patch.js | 28 - js/rpg_core/ShaderTilemap.js | 9 +- js/rpg_core/Sprite.js | 6 +- js/rpg_core/Utils.js | 8 +- js/rpg_core/WebAudio.js | 26 +- js/rpg_core/_header.js | 2 +- js/rpg_managers/BattleManager.js | 19 +- js/rpg_managers/ImageManager.js | 2 +- js/rpg_managers/_header.js | 2 +- js/rpg_objects/Game_Battler.js | 6 +- js/rpg_objects/Game_Interpreter.js | 48 +- js/rpg_objects/_header.js | 2 +- js/rpg_scenes/_header.js | 2 +- js/rpg_sprites/Spriteset_Battle.js | 2 + js/rpg_sprites/_header.js | 2 +- js/rpg_windows/Window_DebugRange.js | 1 - js/rpg_windows/Window_EquipSlot.js | 1 - js/rpg_windows/Window_ItemCategory.js | 1 - js/rpg_windows/Window_SkillType.js | 1 - js/rpg_windows/_header.js | 2 +- rpg_core.json | 1 - 25 files changed, 13459 insertions(+), 8701 deletions(-) delete mode 100644 js/rpg_core/Patch.js diff --git a/js/libs/pixi-picture.js b/js/libs/pixi-picture.js index 248bf477..6eb8ee6c 100644 --- a/js/libs/pixi-picture.js +++ b/js/libs/pixi-picture.js @@ -1,659 +1,428 @@ -/*! - * pixi-picture - v1.0.3 - * Compiled Wed Oct 12 2016 22:33:16 GMT+0300 (RTZ 2 (зима)) - * - * pixi-picture is licensed under the MIT License. - * http://www.opensource.org/licenses/mit-license - */ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pixiPicture = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0.0) {\n Cs = target.rgb / target.a;\n }\n vec3 multiply = Cb * Cs * 2.0;\n vec3 Cs2 = Cs * 2.0 - 1.0;\n vec3 screen = Cb + Cs2 - Cb * Cs2;\n vec3 B;\n if (Cb.r <= 0.5) {\n B.r = multiply.r;\n } else {\n B.r = screen.r;\n }\n if (Cb.g <= 0.5) {\n B.g = multiply.g;\n } else {\n B.g = screen.g;\n }\n if (Cb.b <= 0.5) {\n B.b = multiply.b;\n } else {\n B.b = screen.b;\n }\n vec4 res;\n res.xyz = (1.0 - source.a) * Cs + source.a * B;\n res.a = source.a + target.a * (1.0-source.a);\n gl_FragColor = vec4(res.xyz * res.a, res.a);\n}\n", - tilingMode - ); - this.bind(); - this.uniforms.uSampler = [0, 1]; -} - -HardLightShader.prototype = Object.create(PictureShader.prototype); -HardLightShader.prototype.constructor = HardLightShader; -module.exports = HardLightShader; - -},{"./PictureShader":5}],2:[function(require,module,exports){ - -var PictureShader = require('./PictureShader'); - -/** - * @class - * @extends PIXI.Shader - * @memberof PIXI.extras - * @param gl {PIXI.Shader} The WebGL shader manager this shader works for. - * @param tilingMode {number} 0 for default, 1 for simple tiling, 2 for tiling - */ -function NormalShader(gl, tilingMode) -{ - PictureShader.call(this, - gl, - "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\nattribute vec4 aColor;\n\nuniform mat3 projectionMatrix;\n\nvarying vec2 vTextureCoord;\n%SPRITE_UNIFORMS%\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n %SPRITE_CODE%\n}\n", - "#define GLSLIFY 1\nvarying vec2 vTextureCoord;\nvarying vec4 vColor;\n\nuniform sampler2D uSampler;\nuniform vec4 uColor;\n%SPRITE_UNIFORMS%\n\nvoid main(void)\n{\n %SPRITE_CODE%\n\n vec4 sample = texture2D(uSampler, textureCoord);\n gl_FragColor = sample * uColor;\n}\n", - tilingMode - ); - //do some stuff, like default values for shader - //dont forget to bind it if you really are changing the uniforms - this.bind(); - //default tint - //Its an example, actually PictureRenderer takes care of this stuff - this.uniforms.uColor = new Float32Array(1,1,1,1); -} - -NormalShader.prototype = Object.create(PictureShader.prototype); -NormalShader.prototype.constructor = NormalShader; -module.exports = NormalShader; - -},{"./PictureShader":5}],3:[function(require,module,exports){ - -var PictureShader = require('./PictureShader'); - -/** - * @class - * @extends PIXI.Shader - * @memberof PIXI.extras - * @param gl {PIXI.Shader} The WebGL shader manager this shader works for. - * @param tilingMode {number} 0 for default, 1 for simple tiling, 2 for tiling - */ -function OverlayShader(gl, tilingMode) -{ - PictureShader.call(this, - gl, - "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\nattribute vec4 aColor;\n\nuniform mat3 projectionMatrix;\nuniform mat3 mapMatrix;\n\nvarying vec2 vTextureCoord;\nvarying vec2 vMapCoord;\n%SPRITE_UNIFORMS%\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n %SPRITE_CODE%\n vMapCoord = (mapMatrix * vec3(aVertexPosition, 1.0)).xy;\n}\n", - "#define GLSLIFY 1\nvarying vec2 vTextureCoord;\nvarying vec2 vMapCoord;\nvarying vec4 vColor;\n\nuniform sampler2D uSampler[2];\nuniform vec4 uColor;\n%SPRITE_UNIFORMS%\n\nvoid main(void)\n{\n %SPRITE_CODE%\n vec4 source = texture2D(uSampler[0], textureCoord) * uColor;\n vec4 target = texture2D(uSampler[1], vMapCoord);\n\n //reverse hardlight\n if (source.a == 0.0) {\n gl_FragColor = vec4(0, 0, 0, 0);\n return;\n }\n //yeah, premultiplied\n vec3 Cb = source.rgb/source.a, Cs;\n if (target.a > 0.0) {\n Cs = target.rgb / target.a;\n }\n vec3 multiply = Cb * Cs * 2.0;\n vec3 Cb2 = Cb * 2.0 - 1.0;\n vec3 screen = Cb2 + Cs - Cb2 * Cs;\n vec3 B;\n if (Cs.r <= 0.5) {\n B.r = multiply.r;\n } else {\n B.r = screen.r;\n }\n if (Cs.g <= 0.5) {\n B.g = multiply.g;\n } else {\n B.g = screen.g;\n }\n if (Cs.b <= 0.5) {\n B.b = multiply.b;\n } else {\n B.b = screen.b;\n }\n vec4 res;\n res.xyz = (1.0 - source.a) * Cs + source.a * B;\n res.a = source.a + target.a * (1.0-source.a);\n gl_FragColor = vec4(res.xyz * res.a, res.a);\n}\n", - tilingMode - ); - this.bind(); - this.uniforms.uSampler = [0, 1]; -} - -OverlayShader.prototype = Object.create(PictureShader.prototype); -OverlayShader.prototype.constructor = OverlayShader; -module.exports = OverlayShader; - -},{"./PictureShader":5}],4:[function(require,module,exports){ -var NormalShader = require('./NormalShader'), - mapFilterBlendModesToPixi = require('./mapFilterBlendModesToPixi'), - glCore = PIXI.glCore, - WRAP_MODES = PIXI.WRAP_MODES; - -/** - * Renderer that clamps the texture so neighbour frames wont bleed on it - * immitates context2d drawImage behaviour - * - * @class - * @memberof PIXI.extras - * @extends PIXI.ObjectRenderer - * @param renderer {PIXI.WebGLRenderer} The renderer this plugin works for - */ -function PictureRenderer(renderer) { - PIXI.ObjectRenderer.call(this, renderer); -} - -PictureRenderer.prototype = Object.create(PIXI.ObjectRenderer.prototype); -PictureRenderer.prototype.constructor = PictureRenderer; - -PictureRenderer.prototype.onContextChange = function () { - var gl = this.renderer.gl; - this.quad = new PIXI.Quad(gl); - this.drawModes = mapFilterBlendModesToPixi(gl); - this.normalShader = [new NormalShader(gl, 0), new NormalShader(gl, 1), new NormalShader(gl, 2)]; - this.quad.initVao(this.normalShader[0]); - this._tempClamp = new Float32Array(4); - this._tempColor = new Float32Array(4); - this._tempRect = new PIXI.Rectangle(); - this._tempRect2 = new PIXI.Rectangle(); - this._tempRect3 = new PIXI.Rectangle(); - this._tempMatrix = new PIXI.Matrix(); - this._tempMatrix2 = new PIXI.Matrix(); - this._bigBuf = new Uint8Array(1 << 20); - this._renderTexture = new PIXI.BaseRenderTexture(1024, 1024); +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; - -PictureRenderer.prototype.start = function () { - //noop -}; - -PictureRenderer.prototype.flush = function () { - //noop -}; - -function nextPow2(v) { - v += v === 0; - --v; - v |= v >>> 1; - v |= v >>> 2; - v |= v >>> 4; - v |= v >>> 8; - v |= v >>> 16; - return v + 1; -} - -PictureRenderer.prototype._getRenderTexture = function (minWidth, minHeight) { - if (this._renderTexture.width < minWidth || - this._renderTexture.height < minHeight) { - minHeight = nextPow2(minWidth); - minHeight = nextPow2(minHeight); - this._renderTexture.resize(minWidth, minHeight); - } - return this._renderTexture; -}; - -PictureRenderer.prototype._getBuf = function (size) { - var buf = this._bigBuf; - if (buf.length < size) { - size = nextPow2(size); - buf = new Uint8Array(size); - this._bigBuf = buf; - } - return buf; -}; - -/** - * Renders the picture object. - * - * @param sprite {PIXI.tilemap.PictureSprite} the picture to render - */ -PictureRenderer.prototype.render = function (sprite) { - if (!sprite.texture.valid) { - return; - } - var tilingMode = 0; - if (sprite.tileTransform) { - //for TilingSprite - tilingMode = this._isSimpleSprite(sprite) ? 1 : 2; - } - - var blendShader = this.drawModes[sprite.blendMode]; - if (blendShader) { - this._renderBlend(sprite, blendShader[tilingMode]); - } else { - this._renderNormal(sprite, this.normalShader[tilingMode]); - } -}; - -PictureRenderer.prototype._renderNormal = function (sprite, shader) { - var renderer = this.renderer; - renderer.bindShader(shader); - renderer.state.setBlendMode(sprite.blendMode); - this._renderInner(sprite, shader); -}; - -PictureRenderer.prototype._renderBlend = function (sprite, shader) { - //nothing there yet - var renderer = this.renderer; - var spriteBounds = sprite.getBounds(); - var renderTarget = renderer._activeRenderTarget; - var matrix = renderTarget.projectionMatrix; - var flipX = matrix.a < 0; - var flipY = matrix.d < 0; - var resolution = renderTarget.resolution; - var screen = this._tempRect; - var fr = renderTarget.sourceFrame || renderTarget.destinationFrame; - screen.x = 0; - screen.y = 0; - screen.width = fr.width; - screen.height = fr.height; - - var bounds = this._tempRect2; - var fbw = fr.width * resolution, fbh = fr.height * resolution; - bounds.x = (spriteBounds.x + matrix.tx / matrix.a) * resolution + fbw / 2; - bounds.y = (spriteBounds.y + matrix.ty / matrix.d) * resolution + fbh / 2; - bounds.width = spriteBounds.width * resolution; - bounds.height = spriteBounds.height * resolution; - if (flipX) { - bounds.y = fbw - bounds.width - bounds.x; - } - if (flipY) { - bounds.y = fbh - bounds.height - bounds.y; - } - - var screenBounds = this._tempRect3; - var x_1 = Math.floor(Math.max(screen.x, bounds.x)); - var x_2 = Math.ceil(Math.min(screen.x + screen.width, bounds.x + bounds.width)); - var y_1 = Math.floor(Math.max(screen.y, bounds.y)); - var y_2 = Math.ceil(Math.min(screen.y + screen.height, bounds.y + bounds.height)); - var pixelsWidth = x_2 - x_1; - var pixelsHeight = y_2 - y_1; - if (pixelsWidth <= 0 || pixelsHeight <= 0) { - //culling - return; - } - //TODO: padding - var rt = this._getRenderTexture(pixelsWidth, pixelsHeight); - renderer.bindTexture(rt, 1); - var gl = renderer.gl; - if (renderer.renderingToScreen && renderTarget.root) { - var buf = this._getBuf(pixelsWidth * pixelsHeight * 4); - gl.readPixels(x_1, y_1, pixelsWidth, pixelsHeight, gl.RGBA, gl.UNSIGNED_BYTE, this._bigBuf); - //REVERT Y? - gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, pixelsWidth, pixelsHeight, gl.RGBA, gl.UNSIGNED_BYTE, this._bigBuf); - } else { - gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, x_1, y_1, pixelsWidth, pixelsHeight); - } - - renderer.bindShader(shader); - renderer.state.setBlendMode(PIXI.BLEND_MODES.NORMAL); - if (shader.uniforms.mapMatrix) { - var mapMatrix = this._tempMatrix; - mapMatrix.a = bounds.width / rt.width / spriteBounds.width; - if (flipX) { - mapMatrix.a = -mapMatrix.a; - mapMatrix.tx = (bounds.x - x_1) / rt.width - (spriteBounds.x + spriteBounds.width) * mapMatrix.a; - } else { - mapMatrix.tx = (bounds.x - x_1) / rt.width - spriteBounds.x * mapMatrix.a; - } - mapMatrix.d = bounds.height / rt.height / spriteBounds.height; - if (flipY) { - mapMatrix.d = -mapMatrix.d; - mapMatrix.ty = (bounds.y - y_1) / rt.height - (spriteBounds.y + spriteBounds.height) * mapMatrix.d; - } else { - mapMatrix.ty = (bounds.y - y_1) / rt.height - spriteBounds.y * mapMatrix.d; - } - - shader.uniforms.mapMatrix = mapMatrix.toArray(true); - } - - this._renderInner(sprite, shader); -}; - -PictureRenderer.prototype._renderInner = function (sprite, shader) { - var renderer = this.renderer; - if (shader.tilingMode > 0) { - this._renderWithShader(sprite, shader.tilingMode === 1, shader); - } else { - this._renderSprite(sprite, shader); - } -}; - -PictureRenderer.prototype._renderSprite = function(sprite, shader) { - var renderer = this.renderer; - var quad = this.quad; - var uvs = sprite.texture._uvs; - - //sprite already has calculated the vertices. lets transfer them to quad - - var vertices = quad.vertices; - var vd = sprite.computedGeometry ? sprite.computedGeometry.vertices : sprite.vertexData; - for (var i = 0; i < 8; i++) { - quad.vertices[i] = vd[i]; - } - - //SpriteRenderer works differently, with uint32 UVS - //but for our demo float uvs are just fine - quad.uvs[0] = uvs.x0; - quad.uvs[1] = uvs.y0; - quad.uvs[2] = uvs.x1; - quad.uvs[3] = uvs.y1; - quad.uvs[4] = uvs.x2; - quad.uvs[5] = uvs.y2; - quad.uvs[6] = uvs.x3; - quad.uvs[7] = uvs.y3; - - //TODO: add baricentric coords here - quad.upload(); - - var frame = sprite.texture.frame; - var base = sprite.texture.baseTexture; - var clamp = this._tempClamp; - //clamping 0.5 pixel from each side to reduce border artifact - //this is our plugin main purpose - var eps = 0.5 / base.resolution; - clamp[0] = (frame.x + eps) / base.width; - clamp[1] = (frame.y + eps) / base.height; - clamp[2] = (frame.x + frame.width - eps) / base.width; - clamp[3] = (frame.y + frame.height - eps) / base.height; - //take a notice that size in pixels is realWidth,realHeight - //width and height are divided by resolution - shader.uniforms.uTextureClamp = clamp; - - var color = this._tempColor; - PIXI.utils.hex2rgb(sprite.tint, color); - var alpha = sprite.worldAlpha; - //premultiplied alpha tint - //of course we could do that in shader too - color[0] *= alpha; - color[1] *= alpha; - color[2] *= alpha; - color[3] = alpha; - shader.uniforms.uColor = color; - - //bind texture to unit 0, our default sampler unit - renderer.bindTexture(base, 0); - quad.draw(); -}; - -/** - * this is a part of PIXI.extras.TilingSprite. It will be refactored later - * @param ts - * @returns {boolean} - * @private - */ -PictureRenderer.prototype._isSimpleSprite = function(ts) { - var renderer = this.renderer; - var tex = ts._texture; - var baseTex = tex.baseTexture; - var isSimple = baseTex.isPowerOfTwo && tex.frame.width === baseTex.width && tex.frame.height === baseTex.height; - - // auto, force repeat wrapMode for big tiling textures - if (isSimple) - { - if (!baseTex._glTextures[renderer.CONTEXT_UID]) - { - if (baseTex.wrapMode === WRAP_MODES.CLAMP) +var PIXI; +(function (PIXI) { + var extras; + (function (extras) { + var shaderLib = [ + { + vertUniforms: "", + vertCode: "vTextureCoord = aTextureCoord;", + fragUniforms: "uniform vec4 uTextureClamp;", + fragCode: "vec2 textureCoord = clamp(vTextureCoord, uTextureClamp.xy, uTextureClamp.zw);" + }, + { + vertUniforms: "uniform mat3 uTransform;", + vertCode: "vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;", + fragUniforms: "", + fragCode: "vec2 textureCoord = vTextureCoord;" + }, { - baseTex.wrapMode = WRAP_MODES.REPEAT; + vertUniforms: "uniform mat3 uTransform;", + vertCode: "vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;", + fragUniforms: "uniform mat3 uMapCoord;\nuniform vec4 uClampFrame;\nuniform vec2 uClampOffset;", + fragCode: "vec2 textureCoord = mod(vTextureCoord - uClampOffset, vec2(1.0, 1.0)) + uClampOffset;" + + "\ntextureCoord = (uMapCoord * vec3(textureCoord, 1.0)).xy;" + + "\ntextureCoord = clamp(textureCoord, uClampFrame.xy, uClampFrame.zw);" } + ]; + var PictureShader = (function (_super) { + __extends(PictureShader, _super); + function PictureShader(gl, vert, frag, tilingMode) { + var lib = shaderLib[tilingMode]; + _super.call(this, gl, vert.replace(/%SPRITE_UNIFORMS%/gi, lib.vertUniforms) + .replace(/%SPRITE_CODE%/gi, lib.vertCode), frag.replace(/%SPRITE_UNIFORMS%/gi, lib.fragUniforms) + .replace(/%SPRITE_CODE%/gi, lib.fragCode)); + this.bind(); + this.tilingMode = tilingMode; + this.tempQuad = new PIXI.Quad(gl); + this.tempQuad.initVao(this); + this.uniforms.uColor = new Float32Array([1, 1, 1, 1]); + this.uniforms.uSampler = [0, 1]; + } + PictureShader.blendVert = "\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\nattribute vec4 aColor;\n\nuniform mat3 projectionMatrix;\nuniform mat3 mapMatrix;\n\nvarying vec2 vTextureCoord;\nvarying vec2 vMapCoord;\n%SPRITE_UNIFORMS%\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n %SPRITE_CODE%\n vMapCoord = (mapMatrix * vec3(aVertexPosition, 1.0)).xy;\n}\n"; + return PictureShader; + }(PIXI.Shader)); + extras.PictureShader = PictureShader; + })(extras = PIXI.extras || (PIXI.extras = {})); +})(PIXI || (PIXI = {})); +var PIXI; +(function (PIXI) { + var extras; + (function (extras) { + var overlayFrag = "\nvarying vec2 vTextureCoord;\nvarying vec2 vMapCoord;\nvarying vec4 vColor;\n\nuniform sampler2D uSampler[2];\nuniform vec4 uColor;\n%SPRITE_UNIFORMS%\n\nvoid main(void)\n{\n %SPRITE_CODE%\n vec4 source = texture2D(uSampler[0], textureCoord) * uColor;\n vec4 target = texture2D(uSampler[1], vMapCoord);\n\n //reverse hardlight\n if (source.a == 0.0) {\n gl_FragColor = vec4(0, 0, 0, 0);\n return;\n }\n //yeah, premultiplied\n vec3 Cb = source.rgb/source.a, Cs;\n if (target.a > 0.0) {\n Cs = target.rgb / target.a;\n }\n vec3 multiply = Cb * Cs * 2.0;\n vec3 Cs2 = Cs * 2.0 - 1.0;\n vec3 screen = Cb + Cs2 - Cb * Cs2;\n vec3 B;\n if (Cb.r <= 0.5) {\n B.r = multiply.r;\n } else {\n B.r = screen.r;\n }\n if (Cb.g <= 0.5) {\n B.g = multiply.g;\n } else {\n B.g = screen.g;\n }\n if (Cb.b <= 0.5) {\n B.b = multiply.b;\n } else {\n B.b = screen.b;\n }\n vec4 res;\n res.xyz = (1.0 - source.a) * Cs + source.a * B;\n res.a = source.a + target.a * (1.0-source.a);\n gl_FragColor = vec4(res.xyz * res.a, res.a);\n}\n"; + var HardLightShader = (function (_super) { + __extends(HardLightShader, _super); + function HardLightShader(gl, tilingMode) { + _super.call(this, gl, extras.PictureShader.blendVert, overlayFrag, tilingMode); + } + return HardLightShader; + }(extras.PictureShader)); + extras.HardLightShader = HardLightShader; + })(extras = PIXI.extras || (PIXI.extras = {})); +})(PIXI || (PIXI = {})); +var PIXI; +(function (PIXI) { + var extras; + (function (extras) { + function mapFilterBlendModesToPixi(gl, array) { + if (array === void 0) { array = []; } + array[PIXI.BLEND_MODES.OVERLAY] = [new extras.OverlayShader(gl, 0), new extras.OverlayShader(gl, 1), new extras.OverlayShader(gl, 2)]; + array[PIXI.BLEND_MODES.HARD_LIGHT] = [new extras.HardLightShader(gl, 0), new extras.HardLightShader(gl, 1), new extras.HardLightShader(gl, 2)]; + return array; } - else - { - isSimple = baseTex.wrapMode !== WRAP_MODES.CLAMP; + extras.mapFilterBlendModesToPixi = mapFilterBlendModesToPixi; + })(extras = PIXI.extras || (PIXI.extras = {})); +})(PIXI || (PIXI = {})); +var PIXI; +(function (PIXI) { + var extras; + (function (extras) { + var normalFrag = "\nvarying vec2 vTextureCoord;\nvarying vec4 vColor;\n\nuniform sampler2D uSampler[2];\nuniform vec4 uColor;\n%SPRITE_UNIFORMS%\n\nvoid main(void)\n{\n %SPRITE_CODE%\n\n vec4 sample = texture2D(uSampler[0], textureCoord);\n gl_FragColor = sample * uColor;\n}\n"; + var normalVert = "\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\nattribute vec4 aColor;\n\nuniform mat3 projectionMatrix;\n\nvarying vec2 vTextureCoord;\n%SPRITE_UNIFORMS%\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n %SPRITE_CODE%\n}\n"; + var NormalShader = (function (_super) { + __extends(NormalShader, _super); + function NormalShader(gl, tilingMode) { + _super.call(this, gl, normalVert, normalFrag, tilingMode); + } + return NormalShader; + }(extras.PictureShader)); + extras.NormalShader = NormalShader; + })(extras = PIXI.extras || (PIXI.extras = {})); +})(PIXI || (PIXI = {})); +var PIXI; +(function (PIXI) { + var extras; + (function (extras) { + var overlayFrag = "\nvarying vec2 vTextureCoord;\nvarying vec2 vMapCoord;\nvarying vec4 vColor;\n\nuniform sampler2D uSampler[2];\nuniform vec4 uColor;\n%SPRITE_UNIFORMS%\n\nvoid main(void)\n{\n %SPRITE_CODE%\n vec4 source = texture2D(uSampler[0], textureCoord) * uColor;\n vec4 target = texture2D(uSampler[1], vMapCoord);\n\n //reverse hardlight\n if (source.a == 0.0) {\n gl_FragColor = vec4(0, 0, 0, 0);\n return;\n }\n //yeah, premultiplied\n vec3 Cb = source.rgb/source.a, Cs;\n if (target.a > 0.0) {\n Cs = target.rgb / target.a;\n }\n vec3 multiply = Cb * Cs * 2.0;\n vec3 Cb2 = Cb * 2.0 - 1.0;\n vec3 screen = Cb2 + Cs - Cb2 * Cs;\n vec3 B;\n if (Cs.r <= 0.5) {\n B.r = multiply.r;\n } else {\n B.r = screen.r;\n }\n if (Cs.g <= 0.5) {\n B.g = multiply.g;\n } else {\n B.g = screen.g;\n }\n if (Cs.b <= 0.5) {\n B.b = multiply.b;\n } else {\n B.b = screen.b;\n }\n vec4 res;\n res.xyz = (1.0 - source.a) * Cs + source.a * B;\n res.a = source.a + target.a * (1.0-source.a);\n gl_FragColor = vec4(res.xyz * res.a, res.a);\n}\n"; + var OverlayShader = (function (_super) { + __extends(OverlayShader, _super); + function OverlayShader(gl, tilingMode) { + _super.call(this, gl, extras.PictureShader.blendVert, overlayFrag, tilingMode); + } + return OverlayShader; + }(extras.PictureShader)); + extras.OverlayShader = OverlayShader; + })(extras = PIXI.extras || (PIXI.extras = {})); +})(PIXI || (PIXI = {})); +var PIXI; +(function (PIXI) { + var extras; + (function (extras) { + function nextPow2(v) { + v += (v === 0) ? 1 : 0; + --v; + v |= v >>> 1; + v |= v >>> 2; + v |= v >>> 4; + v |= v >>> 8; + v |= v >>> 16; + return v + 1; } - } - - return isSimple; -}; - -/** - * this is a part of PIXI.extras.TilingSprite. It will be refactored later - * @param ts - * @returns {boolean} - * @private - */ -PictureRenderer.prototype._renderWithShader = function(ts, isSimple, shader) -{ - var quad = this.quad; - var vertices = quad.vertices; - - var w0 = ts._width * (1 - ts._anchor._x); - var w1 = ts._width * -ts._anchor._x; - - var h0 = ts._height * (1 - ts._anchor._y); - var h1 = ts._height * -ts._anchor._y; - - var wt = ts.transform.worldTransform; - - var a = wt.a; - var b = wt.b; - var c = wt.c; - var d = wt.d; - var tx = wt.tx; - var ty = wt.ty; - - vertices[0] = (a * w1) + (c * h1) + tx; - vertices[1] = (d * h1) + (b * w1) + ty; - - vertices[2] = (a * w0) + (c * h1) + tx; - vertices[3] = (d * h1) + (b * w0) + ty; - - vertices[4] = (a * w0) + (c * h0) + tx; - vertices[5] = (d * h0) + (b * w0) + ty; - - vertices[6] = (a * w1) + (c * h0) + tx; - vertices[7] = (d * h0) + (b * w1) + ty; - - vertices = quad.uvs; - - vertices[0] = vertices[6] = -ts.anchor.x; - vertices[1] = vertices[3] = -ts.anchor.y; - - vertices[2] = vertices[4] = 1.0 - ts.anchor.x; - vertices[5] = vertices[7] = 1.0 - ts.anchor.y; - - quad.upload(); - - var renderer = this.renderer; - var tex = ts._texture; - var lt = ts.tileTransform.localTransform; - var uv = ts.uvTransform; - - var w = tex.width; - var h = tex.height; - var W = ts._width; - var H = ts._height; - - var tempMat = this._tempMatrix2; - - tempMat.set(lt.a * w / W, - lt.b * w / H, - lt.c * h / W, - lt.d * h / H, - lt.tx / W, - lt.ty / H); - - // that part is the same as above: - // tempMat.identity(); - // tempMat.scale(tex.width, tex.height); - // tempMat.prepend(lt); - // tempMat.scale(1.0 / ts._width, 1.0 / ts._height); - - tempMat.invert(); - if (isSimple) - { - tempMat.append(uv.mapCoord); - } - else - { - shader.uniforms.uMapCoord = uv.mapCoord.toArray(true); - shader.uniforms.uClampFrame = uv.uClampFrame; - shader.uniforms.uClampOffset = uv.uClampOffset; - } - shader.uniforms.uTransform = tempMat.toArray(true); - - var color = this._tempColor; - var alpha = ts.worldAlpha; - - PIXI.utils.hex2rgb(ts.tint, color); - color[0] *= alpha; - color[1] *= alpha; - color[2] *= alpha; - color[3] = alpha; - shader.uniforms.uColor = color; - - renderer.bindTexture(tex); - - quad.draw(); -}; - -PIXI.WebGLRenderer.registerPlugin('picture', PictureRenderer); - -module.exports = PictureRenderer; - -},{"./NormalShader":2,"./mapFilterBlendModesToPixi":8}],5:[function(require,module,exports){ -/** - * @class - * @extends PIXI.Shader - * @memberof PIXI.extras - * @param gl {PIXI.Shader} The WebGL shader manager this shader works for. - * @param vert {string} - * @param frag {string} - * @param tilingMode {number} 0 for default, 1 for simple tiling, 2 for tiling - */ -function PictureShader(gl, vert, frag, tilingMode) { - var lib = shaderLib[tilingMode]; - PIXI.Shader.call(this, - gl, - vert.replace(/%SPRITE_UNIFORMS%/gi, lib.vertUniforms) - .replace(/%SPRITE_CODE%/gi, lib.vertCode), - frag.replace(/%SPRITE_UNIFORMS%/gi, lib.fragUniforms) - .replace(/%SPRITE_CODE%/gi, lib.fragCode) - ); - - this.tilingMode = tilingMode; -} - - -var shaderLib = [ - { - //DOES NOT HAVE translationMatrix - vertUniforms: "", - vertCode: "vTextureCoord = aTextureCoord;", - fragUniforms: "uniform vec4 uTextureClamp;", - fragCode: "vec2 textureCoord = clamp(vTextureCoord, uTextureClamp.xy, uTextureClamp.zw);" - }, - { - //DOES HAVE translationMatrix - vertUniforms: "uniform mat3 uTransform;", - vertCode: "vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;", - fragUniforms: "", - fragCode: "vec2 textureCoord = vTextureCoord;" - }, - { - //DOES HAVE translationMatrix - vertUniforms: "uniform mat3 uTransform;", - vertCode: "vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;", - fragUniforms: "uniform mat3 uMapCoord;\nuniform vec4 uClampFrame;\nuniform vec2 uClampOffset;", - fragCode: "vec2 textureCoord = mod(vTextureCoord - uClampOffset, vec2(1.0, 1.0)) + uClampOffset;" + - "\ntextureCoord = (uMapCoord * vec3(textureCoord, 1.0)).xy;" + - "\ntextureCoord = clamp(textureCoord, uClampFrame.xy, uClampFrame.zw);" - } -]; - -PictureShader.prototype = Object.create(PIXI.Shader.prototype); -PictureShader.prototype.constructor = PictureShader; -module.exports = PictureShader; - -},{}],6:[function(require,module,exports){ -/** - * A Sprite with reduced border artifacts - * - * @class - * @extends PIXI.Sprite - * @memberof PIXI.extras - * @param texture {PIXI.Texture} the texture for this sprite - */ -function PictureSprite(texture) -{ - PIXI.Sprite.call(this, texture); -} - -PictureSprite.prototype = Object.create(PIXI.Sprite.prototype); -PictureSprite.prototype.constructor = PictureSprite; -module.exports = PictureSprite; - -/** - * Renders the object using the WebGL renderer - * - * @param renderer {PIXI.WebGLRenderer} - * @private - */ -PictureSprite.prototype._renderWebGL = function (renderer) -{ - if (this.updateGeometry) { - this.updateGeometry(); - } else { - this.calculateVertices(); - } - - //use different plugin for rendering - renderer.setObjectRenderer(renderer.plugins.picture); - renderer.plugins.picture.render(this); -}; - -},{}],7:[function(require,module,exports){ -/** - * A TilingSprite with support of additional blendModes - * - * @class - * @extends PIXI.extras.TilingSprite - * @memberof PIXI.extras - * @param texture {PIXI.Texture} the texture for this sprite - * @param {number} width width - * @param {number} height height - */ -function PictureTilingSprite(texture, width, height) -{ - PIXI.extras.TilingSprite.call(this, texture, width, height); -} - -PictureTilingSprite.prototype = Object.create(PIXI.extras.TilingSprite.prototype); -PictureTilingSprite.prototype.constructor = PictureTilingSprite; -module.exports = PictureTilingSprite; - -/** - * Renders the object using the WebGL renderer - * - * @param renderer {PIXI.WebGLRenderer} - * @private - */ -PictureTilingSprite.prototype._renderWebGL = function (renderer) -{ - if (this.updateGeometry) { - this.updateGeometry(); - } - - const texture = this._texture; - - if (!texture || !texture.valid) - { - return; - } - - this.tileTransform.updateLocalTransform(); - this.uvTransform.update(); - - renderer.setObjectRenderer(renderer.plugins.picture); - renderer.plugins.picture.render(this); -}; - -},{}],8:[function(require,module,exports){ -var CONST = PIXI, - OverlayShader = require('./OverlayShader'), - HardLightShader = require('./HardLightShader'); - -/** - * Maps gl blend combinations to WebGL - * @class - * @memberof PIXI.extras - */ -function mapFilterBlendModesToPixi(gl, array) -{ - array = array || []; - - //TODO - premultiply alpha would be different. - //add a boolean for that! - array[CONST.BLEND_MODES.OVERLAY] = [new OverlayShader(gl, 0), new OverlayShader(gl, 1), new OverlayShader(gl, 2)]; - array[CONST.BLEND_MODES.HARD_LIGHT] = [new HardLightShader(gl, 0), new HardLightShader(gl, 1), new HardLightShader(gl, 2)]; - - return array; -} - -module.exports = mapFilterBlendModesToPixi; - -},{"./HardLightShader":1,"./OverlayShader":3}],9:[function(require,module,exports){ -var myPlugin = { - PictureSprite: require('./PictureSprite'), - PictureTilingSprite: require('./PictureTilingSprite'), - PictureRenderer: require('./PictureRenderer') -}; - -//dump everything into extras - -Object.assign(PIXI.extras, myPlugin); - -module.exports = myPlugin; - -},{"./PictureRenderer":4,"./PictureSprite":6,"./PictureTilingSprite":7}]},{},[9])(9) -}); - - -//# sourceMappingURL=pixi-picture.js.map + var PictureRenderer = (function (_super) { + __extends(PictureRenderer, _super); + function PictureRenderer(renderer) { + _super.call(this, renderer); + } + PictureRenderer.prototype.onContextChange = function () { + var gl = this.renderer.gl; + this.drawModes = extras.mapFilterBlendModesToPixi(gl); + this.normalShader = [new extras.NormalShader(gl, 0), new extras.NormalShader(gl, 1), new extras.NormalShader(gl, 2)]; + this._tempClamp = new Float32Array(4); + this._tempColor = new Float32Array(4); + this._tempRect = new PIXI.Rectangle(); + this._tempRect2 = new PIXI.Rectangle(); + this._tempRect3 = new PIXI.Rectangle(); + this._tempMatrix = new PIXI.Matrix(); + this._tempMatrix2 = new PIXI.Matrix(); + this._bigBuf = new Uint8Array(1 << 20); + this._renderTexture = new PIXI.BaseRenderTexture(1024, 1024); + }; + PictureRenderer.prototype.start = function () { + }; + PictureRenderer.prototype.flush = function () { + }; + PictureRenderer.prototype._getRenderTexture = function (minWidth, minHeight) { + if (this._renderTexture.width < minWidth || + this._renderTexture.height < minHeight) { + minHeight = nextPow2(minWidth); + minHeight = nextPow2(minHeight); + this._renderTexture.resize(minWidth, minHeight); + } + return this._renderTexture; + }; + PictureRenderer.prototype._getBuf = function (size) { + var buf = this._bigBuf; + if (buf.length < size) { + size = nextPow2(size); + buf = new Uint8Array(size); + this._bigBuf = buf; + } + return buf; + }; + PictureRenderer.prototype.render = function (sprite) { + if (!sprite.texture.valid) { + return; + } + var tilingMode = 0; + if (sprite.tileTransform) { + tilingMode = this._isSimpleSprite(sprite) ? 1 : 2; + } + var blendShader = this.drawModes[sprite.blendMode]; + if (blendShader) { + this._renderBlend(sprite, blendShader[tilingMode]); + } + else { + this._renderNormal(sprite, this.normalShader[tilingMode]); + } + }; + PictureRenderer.prototype._renderNormal = function (sprite, shader) { + var renderer = this.renderer; + renderer.bindShader(shader); + renderer.state.setBlendMode(sprite.blendMode); + this._renderInner(sprite, shader); + }; + PictureRenderer.prototype._renderBlend = function (sprite, shader) { + var renderer = this.renderer; + var spriteBounds = sprite.getBounds(); + var renderTarget = renderer._activeRenderTarget; + var matrix = renderTarget.projectionMatrix; + var flipX = matrix.a < 0; + var flipY = matrix.d < 0; + var resolution = renderTarget.resolution; + var screen = this._tempRect; + var fr = renderTarget.sourceFrame || renderTarget.destinationFrame; + screen.x = 0; + screen.y = 0; + screen.width = fr.width; + screen.height = fr.height; + var bounds = this._tempRect2; + var fbw = fr.width * resolution, fbh = fr.height * resolution; + bounds.x = (spriteBounds.x + matrix.tx / matrix.a) * resolution + fbw / 2; + bounds.y = (spriteBounds.y + matrix.ty / matrix.d) * resolution + fbh / 2; + bounds.width = spriteBounds.width * resolution; + bounds.height = spriteBounds.height * resolution; + if (flipX) { + bounds.y = fbw - bounds.width - bounds.x; + } + if (flipY) { + bounds.y = fbh - bounds.height - bounds.y; + } + var screenBounds = this._tempRect3; + var x_1 = Math.floor(Math.max(screen.x, bounds.x)); + var x_2 = Math.ceil(Math.min(screen.x + screen.width, bounds.x + bounds.width)); + var y_1 = Math.floor(Math.max(screen.y, bounds.y)); + var y_2 = Math.ceil(Math.min(screen.y + screen.height, bounds.y + bounds.height)); + var pixelsWidth = x_2 - x_1; + var pixelsHeight = y_2 - y_1; + if (pixelsWidth <= 0 || pixelsHeight <= 0) { + return; + } + var rt = this._getRenderTexture(pixelsWidth, pixelsHeight); + renderer.bindTexture(rt, 1, true); + var gl = renderer.gl; + if (renderer.renderingToScreen && renderTarget.root) { + var buf = this._getBuf(pixelsWidth * pixelsHeight * 4); + gl.readPixels(x_1, y_1, pixelsWidth, pixelsHeight, gl.RGBA, gl.UNSIGNED_BYTE, this._bigBuf); + gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, pixelsWidth, pixelsHeight, gl.RGBA, gl.UNSIGNED_BYTE, this._bigBuf); + } + else { + gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, x_1, y_1, pixelsWidth, pixelsHeight); + } + renderer.bindShader(shader); + renderer.state.setBlendMode(PIXI.BLEND_MODES.NORMAL); + if (shader.uniforms.mapMatrix) { + var mapMatrix = this._tempMatrix; + mapMatrix.a = bounds.width / rt.width / spriteBounds.width; + if (flipX) { + mapMatrix.a = -mapMatrix.a; + mapMatrix.tx = (bounds.x - x_1) / rt.width - (spriteBounds.x + spriteBounds.width) * mapMatrix.a; + } + else { + mapMatrix.tx = (bounds.x - x_1) / rt.width - spriteBounds.x * mapMatrix.a; + } + mapMatrix.d = bounds.height / rt.height / spriteBounds.height; + if (flipY) { + mapMatrix.d = -mapMatrix.d; + mapMatrix.ty = (bounds.y - y_1) / rt.height - (spriteBounds.y + spriteBounds.height) * mapMatrix.d; + } + else { + mapMatrix.ty = (bounds.y - y_1) / rt.height - spriteBounds.y * mapMatrix.d; + } + shader.uniforms.mapMatrix = mapMatrix.toArray(true); + } + this._renderInner(sprite, shader); + }; + PictureRenderer.prototype._renderInner = function (sprite, shader) { + var renderer = this.renderer; + if (shader.tilingMode > 0) { + this._renderWithShader(sprite, shader.tilingMode === 1, shader); + } + else { + this._renderSprite(sprite, shader); + } + }; + PictureRenderer.prototype._renderWithShader = function (ts, isSimple, shader) { + var quad = shader.tempQuad; + var renderer = this.renderer; + renderer.bindVao(quad.vao); + var vertices = quad.vertices; + var _width = ts._width; + var _height = ts._height; + var _anchorX = ts._anchor._x; + var _anchorY = ts._anchor._y; + var w0 = _width * (1 - _anchorX); + var w1 = _width * -_anchorX; + var h0 = _height * (1 - _anchorY); + var h1 = _height * -_anchorY; + var wt = ts.transform.worldTransform; + var a = wt.a; + var b = wt.b; + var c = wt.c; + var d = wt.d; + var tx = wt.tx; + var ty = wt.ty; + vertices[0] = (a * w1) + (c * h1) + tx; + vertices[1] = (d * h1) + (b * w1) + ty; + vertices[2] = (a * w0) + (c * h1) + tx; + vertices[3] = (d * h1) + (b * w0) + ty; + vertices[4] = (a * w0) + (c * h0) + tx; + vertices[5] = (d * h0) + (b * w0) + ty; + vertices[6] = (a * w1) + (c * h0) + tx; + vertices[7] = (d * h0) + (b * w1) + ty; + vertices = quad.uvs; + vertices[0] = vertices[6] = -ts.anchor.x; + vertices[1] = vertices[3] = -ts.anchor.y; + vertices[2] = vertices[4] = 1.0 - ts.anchor.x; + vertices[5] = vertices[7] = 1.0 - ts.anchor.y; + quad.upload(); + var tex = ts._texture; + var lt = ts.tileTransform.localTransform; + var uv = ts.uvTransform; + var mapCoord = uv.mapCoord; + var uClampFrame = uv.uClampFrame; + var uClampOffset = uv.uClampOffset; + var w = tex.width; + var h = tex.height; + var W = _width; + var H = _height; + var tempMat = this._tempMatrix2; + tempMat.set(lt.a * w / W, lt.b * w / H, lt.c * h / W, lt.d * h / H, lt.tx / W, lt.ty / H); + tempMat.invert(); + if (isSimple) { + tempMat.append(mapCoord); + } + else { + shader.uniforms.uMapCoord = mapCoord.toArray(true); + shader.uniforms.uClampFrame = uClampFrame; + shader.uniforms.uClampOffset = uClampOffset; + } + shader.uniforms.uTransform = tempMat.toArray(true); + var color = this._tempColor; + var alpha = ts.worldAlpha; + PIXI.utils.hex2rgb(ts.tint, color); + color[0] *= alpha; + color[1] *= alpha; + color[2] *= alpha; + color[3] = alpha; + shader.uniforms.uColor = color; + renderer.bindTexture(tex, 0, true); + quad.vao.draw(this.renderer.gl.TRIANGLES, 6, 0); + }; + PictureRenderer.prototype._renderSprite = function (sprite, shader) { + var renderer = this.renderer; + var quad = shader.tempQuad; + renderer.bindVao(quad.vao); + var uvs = sprite.texture._uvs; + var vertices = quad.vertices; + var vd = sprite.vertexData; + for (var i = 0; i < 8; i++) { + quad.vertices[i] = vd[i]; + } + quad.uvs[0] = uvs.x0; + quad.uvs[1] = uvs.y0; + quad.uvs[2] = uvs.x1; + quad.uvs[3] = uvs.y1; + quad.uvs[4] = uvs.x2; + quad.uvs[5] = uvs.y2; + quad.uvs[6] = uvs.x3; + quad.uvs[7] = uvs.y3; + quad.upload(); + var frame = sprite.texture.frame; + var base = sprite.texture.baseTexture; + var clamp = this._tempClamp; + var eps = 0.5 / base.resolution; + clamp[0] = (frame.x + eps) / base.width; + clamp[1] = (frame.y + eps) / base.height; + clamp[2] = (frame.x + frame.width - eps) / base.width; + clamp[3] = (frame.y + frame.height - eps) / base.height; + shader.uniforms.uTextureClamp = clamp; + var color = this._tempColor; + PIXI.utils.hex2rgb(sprite.tint, color); + var alpha = sprite.worldAlpha; + color[0] *= alpha; + color[1] *= alpha; + color[2] *= alpha; + color[3] = alpha; + shader.uniforms.uColor = color; + renderer.bindTexture(base, 0, true); + quad.vao.draw(this.renderer.gl.TRIANGLES, 6, 0); + }; + PictureRenderer.prototype._isSimpleSprite = function (ts) { + var renderer = this.renderer; + var tex = ts._texture; + var baseTex = tex.baseTexture; + var isSimple = baseTex.isPowerOfTwo && tex.frame.width === baseTex.width && tex.frame.height === baseTex.height; + if (isSimple) { + if (!baseTex._glTextures[renderer.CONTEXT_UID]) { + if (baseTex.wrapMode === PIXI.WRAP_MODES.CLAMP) { + baseTex.wrapMode = PIXI.WRAP_MODES.REPEAT; + } + } + else { + isSimple = baseTex.wrapMode !== PIXI.WRAP_MODES.CLAMP; + } + } + return isSimple; + }; + return PictureRenderer; + }(PIXI.ObjectRenderer)); + extras.PictureRenderer = PictureRenderer; + PIXI.WebGLRenderer.registerPlugin('picture', PictureRenderer); + PIXI.CanvasRenderer.registerPlugin('picture', PIXI.CanvasSpriteRenderer); + })(extras = PIXI.extras || (PIXI.extras = {})); +})(PIXI || (PIXI = {})); +var PIXI; +(function (PIXI) { + var extras; + (function (extras) { + var PictureSprite = (function (_super) { + __extends(PictureSprite, _super); + function PictureSprite(texture) { + _super.call(this, texture); + this.pluginName = 'picture'; + } + return PictureSprite; + }(PIXI.Sprite)); + extras.PictureSprite = PictureSprite; + })(extras = PIXI.extras || (PIXI.extras = {})); +})(PIXI || (PIXI = {})); +var PIXI; +(function (PIXI) { + var extras; + (function (extras) { + var PictureTilingSprite = (function (_super) { + __extends(PictureTilingSprite, _super); + function PictureTilingSprite(texture) { + _super.call(this, texture); + this.pluginName = 'picture'; + } + return PictureTilingSprite; + }(extras.TilingSprite)); + extras.PictureTilingSprite = PictureTilingSprite; + })(extras = PIXI.extras || (PIXI.extras = {})); +})(PIXI || (PIXI = {})); +//# sourceMappingURL=pixi-picture.js.map \ No newline at end of file diff --git a/js/libs/pixi-tilemap.js b/js/libs/pixi-tilemap.js index 3857240a..c6cc109d 100644 --- a/js/libs/pixi-tilemap.js +++ b/js/libs/pixi-tilemap.js @@ -1,896 +1,887 @@ -/*! - * pixi-tilemap - v1.0.1 - * Compiled Sun Oct 09 2016 01:20:09 GMT+0300 (RTZ 2 (зима)) - * - * pixi-tilemap is licensed under the MIT License. - * http://www.opensource.org/licenses/mit-license - */ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pixiTilemap = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 0 ? 1 : -1; - tempScale[1] = this._globalMat.d < 0 ? 1 : -1; - var ps = shader.uniforms.pointScale = tempScale; - shader.uniforms.projectionScale = Math.abs(this.worldTransform.a) * renderer.resolution; - } - var af = shader.uniforms.animationFrame = renderer.plugins.tile.tileAnim; - //shader.syncUniform(shader.uniforms.animationFrame); - var layers = this.children; - for (var i = 0; i < layers.length; i++) - layers[i].renderWebGL(renderer, this.useSquare); -}; - - -CompositeRectTileLayer.prototype.isModified = function (anim) { - var layers = this.children; - if (this.modificationMarker != layers.length) { - return true; - } - for (var i = 0; i < layers.length; i++) { - if (layers[i].modificationMarker != layers[i].pointsBuf.length || - anim && layers[i].hasAnim) { - return true; - } - } - return false; -}; - -CompositeRectTileLayer.prototype.clearModify = function () { - var layers = this.children; - this.modificationMarker = layers.length; - for (var i = 0; i < layers.length; i++) { - layers[i].modificationMarker = layers[i].pointsBuf.length; - } -}; - -module.exports = CompositeRectTileLayer; - -},{"./RectTileLayer":4}],3:[function(require,module,exports){ -function GraphicsLayer(zIndex) { - PIXI.Graphics.apply(this, arguments); - this.z = this.zIndex = zIndex; -} - -GraphicsLayer.prototype = Object.create(PIXI.Graphics.prototype); -GraphicsLayer.prototype.constructor = GraphicsLayer; -GraphicsLayer.prototype.renderCanvas = function (renderer) { - var wt = null; - if (renderer.dontUseTransform) { - wt = this.transform.worldTransform; - this.transform.worldTransform = PIXI.Matrix.IDENTITY; - } - renderer.plugins.graphics.render(this); - if (renderer.dontUseTransform) { - this.transform.worldTransform = wt; - } - renderer.context.globalAlpha = 1.0; -}; -GraphicsLayer.prototype.renderWebGL = function(renderer) { - if (!this._webGL[renderer.gl.id]) - this.dirty = true; - PIXI.Graphics.prototype.renderWebGL.call(this, renderer); -}; - -GraphicsLayer.prototype.isModified = function(anim) { - return false; -}; - -GraphicsLayer.prototype.clearModify = function() { -}; - -module.exports = GraphicsLayer; - -},{}],4:[function(require,module,exports){ -function RectTileLayer(zIndex, texture) { - PIXI.DisplayObject.apply(this, arguments); - this.initialize.apply(this, arguments); -} - -RectTileLayer.prototype = Object.create(PIXI.DisplayObject.prototype); -RectTileLayer.prototype.constructor = RectTileLayer; - -RectTileLayer.prototype.initialize = function(zIndex, textures) { - if (!textures) { - textures = []; - } else if (!(textures instanceof Array) && textures.baseTexture) { - textures = [textures]; - } - this.textures = textures; - this.z = this.zIndex = zIndex; - this.pointsBuf = []; - this.visible = false; - this._tempSize = new Float32Array([0, 0]); - this._tempTexSize = 1; -}; - -RectTileLayer.prototype.clear = function () { - this.pointsBuf.length = 0; - this.modificationMarker = 0; - this.hasAnim = false; -}; - -RectTileLayer.prototype.renderCanvas = function (renderer) { - if (this.textures.length === 0) return; - var points = this.pointsBuf; - renderer.context.fillStyle = '#000000'; - for (var i = 0, n = points.length; i < n; i += 9) { - var x1 = points[i], y1 = points[i+1]; - var x2 = points[i+2], y2 = points[i+3]; - var w = points[i+4]; - var h = points[i+5]; - x1 += points[i+6] * renderer.plugins.tile.tileAnim[0]; - y1 += points[i+7] * renderer.plugins.tile.tileAnim[1]; - var textureId = points[i+8]; - if (textureId >= 0) { - renderer.context.drawImage(this.textures[textureId].baseTexture.source, x1, y1, w, h, x2, y2, w, h); - } else { - renderer.context.globalAlpha = 0.5; - renderer.context.fillRect(x2, y2, w, h); - renderer.context.globalAlpha = 1; - } - } -}; - -RectTileLayer.prototype.addRect = function (textureId, u, v, x, y, tileWidth, tileHeight, animX, animY) { - var pb = this.pointsBuf; - this.hasAnim = this.hasAnim || animX > 0 || animY > 0; - if (tileWidth == tileHeight) { - pb.push(u); - pb.push(v); - pb.push(x); - pb.push(y); - pb.push(tileWidth); - pb.push(tileHeight); - pb.push(animX | 0); - pb.push(animY | 0); - pb.push(textureId); - } else { - var i; - if (tileWidth % tileHeight === 0) { - //horizontal line on squares - for (i=0;i> 0; + layer = children[childIndex]; + if (!layer) { + layer = children[0]; + if (!layer) { + return false; + } + ind = 0; + } + else { + ind = texture_ % this.texPerChild; + } + texture = layer.textures[ind]; + } + else if (typeof texture_ === "string") { + texture = PIXI.Texture.fromImage(texture_); + } + else { + texture = texture_; + for (var i = 0; i < children.length; i++) { + var child = children[i]; + var tex = child.textures; + for (var j = 0; j < tex.length; j++) { + if (tex[j].baseTexture == texture.baseTexture) { + layer = child; + ind = j; + break; + } + } + if (layer) { + break; + } + } + if (!layer) { + for (i = 0; i < children.length; i++) { + var child = children[i]; + if (child.textures.length < this.texPerChild) { + layer = child; + ind = child.textures.length; + child.textures.push(texture); + break; + } + } + if (!layer) { + children.push(layer = new tilemap.RectTileLayer(this.zIndex, texture)); + ind = 0; + } + } + } + layer.addRect(ind, texture.frame.x, texture.frame.y, x, y, texture.frame.width, texture.frame.height, animX, animY); + return true; + }; + ; + CompositeRectTileLayer.prototype.renderCanvas = function (renderer) { + if (!renderer.plugins.tilemap.dontUseTransform) { + var wt = this.worldTransform; + renderer.context.setTransform(wt.a, wt.b, wt.c, wt.d, wt.tx * renderer.resolution, wt.ty * renderer.resolution); + } + var layers = this.children; + for (var i = 0; i < layers.length; i++) + layers[i].renderCanvas(renderer); + }; + ; + CompositeRectTileLayer.prototype.renderWebGL = function (renderer) { + var gl = renderer.gl; + var shader = renderer.plugins.tilemap.getShader(this.useSquare); + renderer.setObjectRenderer(renderer.plugins.tilemap); + renderer.bindShader(shader); + this._globalMat = this._globalMat || new PIXI.Matrix(); + renderer._activeRenderTarget.projectionMatrix.copy(this._globalMat).append(this.worldTransform); + shader.uniforms.projectionMatrix = this._globalMat.toArray(true); + shader.uniforms.shadowColor = this.shadowColor; + if (this.useSquare) { + var tempScale = this._tempScale = (this._tempScale || [0, 0]); + tempScale[0] = this._globalMat.a >= 0 ? 1 : -1; + tempScale[1] = this._globalMat.d < 0 ? 1 : -1; + var ps = shader.uniforms.pointScale = tempScale; + shader.uniforms.projectionScale = Math.abs(this.worldTransform.a) * renderer.resolution; + } + var af = shader.uniforms.animationFrame = renderer.plugins.tilemap.tileAnim; + var layers = this.children; + for (var i = 0; i < layers.length; i++) + layers[i].renderWebGL(renderer, this.useSquare); + }; + CompositeRectTileLayer.prototype.isModified = function (anim) { + var layers = this.children; + if (this.modificationMarker != layers.length) { + return true; + } + for (var i = 0; i < layers.length; i++) { + var layer = layers[i]; + if (layer.modificationMarker != layer.pointsBuf.length || + anim && layer.hasAnim) { + return true; + } + } + return false; + }; + CompositeRectTileLayer.prototype.clearModify = function () { + var layers = this.children; + this.modificationMarker = layers.length; + for (var i = 0; i < layers.length; i++) { + var layer = layers[i]; + layer.modificationMarker = layer.pointsBuf.length; + } + }; + return CompositeRectTileLayer; + }(PIXI.Container)); + tilemap.CompositeRectTileLayer = CompositeRectTileLayer; + })(tilemap = PIXI.tilemap || (PIXI.tilemap = {})); +})(PIXI || (PIXI = {})); +var PIXI; +(function (PIXI) { + var tilemap; + (function (tilemap) { + var GraphicsLayer = (function (_super) { + __extends(GraphicsLayer, _super); + function GraphicsLayer(zIndex) { + var _this = _super.call(this) || this; + _this.z = _this.zIndex = zIndex; + return _this; } - } else if (tileHeight % tileWidth === 0) { - //vertical line on squares - for (i=0;i= 0) { + renderer.context.drawImage(this.textures[textureId].baseTexture.source, x1, y1, w, h, x2, y2, w, h); + } + else { + renderer.context.globalAlpha = 0.5; + renderer.context.fillRect(x2, y2, w, h); + renderer.context.globalAlpha = 1; + } + } + }; + RectTileLayer.prototype.addRect = function (textureId, u, v, x, y, tileWidth, tileHeight, animX, animY) { + if (animX === void 0) { animX = 0; } + if (animY === void 0) { animY = 0; } + var pb = this.pointsBuf; + this.hasAnim = this.hasAnim || animX > 0 || animY > 0; + if (tileWidth == tileHeight) { + pb.push(u); + pb.push(v); + pb.push(x); + pb.push(y); + pb.push(tileWidth); + pb.push(tileHeight); + pb.push(animX | 0); + pb.push(animY | 0); + pb.push(textureId); + } + else { + var i; + if (tileWidth % tileHeight === 0) { + for (i = 0; i < tileWidth / tileHeight; i++) { + pb.push(u + i * tileHeight); + pb.push(v); + pb.push(x + i * tileHeight); + pb.push(y); + pb.push(tileHeight); + pb.push(tileHeight); + pb.push(animX | 0); + pb.push(animY | 0); + pb.push(textureId); + } + } + else if (tileHeight % tileWidth === 0) { + for (i = 0; i < tileHeight / tileWidth; i++) { + pb.push(u); + pb.push(v + i * tileWidth); + pb.push(x); + pb.push(y + i * tileWidth); + pb.push(tileWidth); + pb.push(tileWidth); + pb.push(animX | 0); + pb.push(animY | 0); + pb.push(textureId); + } + } + else { + pb.push(u); + pb.push(v); + pb.push(x); + pb.push(y); + pb.push(tileWidth); + pb.push(tileHeight); + pb.push(animX | 0); + pb.push(animY | 0); + pb.push(textureId); + } + } + }; + ; + RectTileLayer.prototype.renderWebGL = function (renderer, useSquare) { + if (useSquare === void 0) { useSquare = false; } + var points = this.pointsBuf; + if (points.length === 0) + return; + var rectsCount = points.length / 9; + var tile = renderer.plugins.tilemap; + var gl = renderer.gl; + if (!useSquare) { + tile.checkIndexBuffer(rectsCount); + } + var shader = tile.getShader(useSquare); + var textures = this.textures; + if (textures.length === 0) + return; + var len = textures.length; + if (this._tempTexSize < shader.maxTextures) { + this._tempTexSize = shader.maxTextures; + this._tempSize = new Float32Array(2 * shader.maxTextures); + } + for (var i = 0; i < len; i++) { + if (!textures[i] || !textures[i].valid) + return; + var texture = textures[i].baseTexture; + } + tile.bindTextures(renderer, shader, textures); + var vb = tile.getVb(this.vbId); + if (!vb) { + vb = tile.createVb(useSquare); + this.vbId = vb.id; + this.vbBuffer = null; + this.modificationMarker = 0; + } + var vao = vb.vao; + renderer.bindVao(vao); + var vertexBuf = vb.vb; + vertexBuf.bind(); + var vertices = rectsCount * shader.vertPerQuad; + if (vertices === 0) + return; + if (this.modificationMarker != vertices) { + this.modificationMarker = vertices; + var vs = shader.stride * vertices; + if (!this.vbBuffer || this.vbBuffer.byteLength < vs) { + var bk = shader.stride; + while (bk < vs) { + bk *= 2; + } + this.vbBuffer = new ArrayBuffer(bk); + this.vbArray = new Float32Array(this.vbBuffer); + this.vbInts = new Uint32Array(this.vbBuffer); + vertexBuf.upload(this.vbBuffer, 0, true); + } + var arr = this.vbArray, ints = this.vbInts; + var sz = 0; + var textureId, shiftU, shiftV; + if (useSquare) { + for (i = 0; i < points.length; i += 9) { + textureId = (points[i + 8] >> 2); + shiftU = 1024 * (points[i + 8] & 1); + shiftV = 1024 * ((points[i + 8] >> 1) & 1); + arr[sz++] = points[i + 2]; + arr[sz++] = points[i + 3]; + arr[sz++] = points[i + 0] + shiftU; + arr[sz++] = points[i + 1] + shiftV; + arr[sz++] = points[i + 4]; + arr[sz++] = points[i + 6]; + arr[sz++] = points[i + 7]; + arr[sz++] = textureId; + } + } + else { + var tint = -1; + for (i = 0; i < points.length; i += 9) { + var eps = 0.5; + textureId = (points[i + 8] >> 2); + shiftU = 1024 * (points[i + 8] & 1); + shiftV = 1024 * ((points[i + 8] >> 1) & 1); + var x = points[i + 2], y = points[i + 3]; + var w = points[i + 4], h = points[i + 5]; + var u = points[i] + shiftU, v = points[i + 1] + shiftV; + var animX = points[i + 6], animY = points[i + 7]; + arr[sz++] = x; + arr[sz++] = y; + arr[sz++] = u; + arr[sz++] = v; + arr[sz++] = u + eps; + arr[sz++] = v + eps; + arr[sz++] = u + w - eps; + arr[sz++] = v + h - eps; + arr[sz++] = animX; + arr[sz++] = animY; + arr[sz++] = textureId; + arr[sz++] = x + w; + arr[sz++] = y; + arr[sz++] = u + w; + arr[sz++] = v; + arr[sz++] = u + eps; + arr[sz++] = v + eps; + arr[sz++] = u + w - eps; + arr[sz++] = v + h - eps; + arr[sz++] = animX; + arr[sz++] = animY; + arr[sz++] = textureId; + arr[sz++] = x + w; + arr[sz++] = y + h; + arr[sz++] = u + w; + arr[sz++] = v + h; + arr[sz++] = u + eps; + arr[sz++] = v + eps; + arr[sz++] = u + w - eps; + arr[sz++] = v + h - eps; + arr[sz++] = animX; + arr[sz++] = animY; + arr[sz++] = textureId; + arr[sz++] = x; + arr[sz++] = y + h; + arr[sz++] = u; + arr[sz++] = v + h; + arr[sz++] = u + eps; + arr[sz++] = v + eps; + arr[sz++] = u + w - eps; + arr[sz++] = v + h - eps; + arr[sz++] = animX; + arr[sz++] = animY; + arr[sz++] = textureId; + } + } + vertexBuf.upload(arr, 0, true); + } + if (useSquare) + gl.drawArrays(gl.POINTS, 0, vertices); + else + gl.drawElements(gl.TRIANGLES, rectsCount * 6, gl.UNSIGNED_SHORT, 0); + }; + return RectTileLayer; + }(PIXI.Container)); + tilemap.RectTileLayer = RectTileLayer; + })(tilemap = PIXI.tilemap || (PIXI.tilemap = {})); +})(PIXI || (PIXI = {})); +var PIXI; +(function (PIXI) { + var tilemap; + (function (tilemap) { + var rectShaderFrag = "varying vec2 vTextureCoord;\nvarying vec4 vFrame;\nvarying float vTextureId;\nuniform vec4 shadowColor;\nuniform sampler2D uSamplers[%count%];\nuniform vec2 uSamplerSize[%count%];\n\nvoid main(void){\n vec2 textureCoord = clamp(vTextureCoord, vFrame.xy, vFrame.zw);\n float textureId = floor(vTextureId + 0.5);\n\n vec4 color;\n %forloop%\n gl_FragColor = color;\n}"; + var rectShaderVert = "\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\nattribute vec4 aFrame;\nattribute vec2 aAnim;\nattribute float aTextureId;\n\nuniform mat3 projectionMatrix;\nuniform vec2 animationFrame;\n\nvarying vec2 vTextureCoord;\nvarying float vTextureId;\nvarying vec4 vFrame;\n\nvoid main(void){\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n vec2 anim = aAnim * animationFrame;\n vTextureCoord = aTextureCoord + anim;\n vFrame = aFrame + vec4(anim, anim);\n vTextureId = aTextureId;\n}\n"; + var TilemapShader = (function (_super) { + __extends(TilemapShader, _super); + function TilemapShader(gl, maxTextures, shaderVert, shaderFrag) { + var _this = _super.call(this, gl, shaderVert, shaderFrag) || this; + _this.maxTextures = 0; + _this.maxTextures = maxTextures; + tilemap.shaderGenerator.fillSamplers(_this, _this.maxTextures); + return _this; } - this.vbBuffer = new ArrayBuffer(bk); - this.vbArray = new Float32Array(this.vbBuffer); - this.vbInts = new Uint32Array(this.vbBuffer); - vb.upload(this.vbBuffer, 0, true); - } - - var arr = this.vbArray, ints = this.vbInts; - //upload vertices! - var sz = 0; - //var tint = 0xffffffff; - var textureId, shiftU, shiftV; - if (useSquare) { - for (i = 0; i < points.length; i += 9) { - textureId = (points[i+8] >> 2); - shiftU = 1024 * (points[i+8] & 1); - shiftV = 1024 * ((points[i+8] >> 1) & 1); - arr[sz++] = points[i + 2]; - arr[sz++] = points[i + 3]; - arr[sz++] = points[i + 0] + shiftU; - arr[sz++] = points[i + 1] + shiftV; - arr[sz++] = points[i + 4]; - arr[sz++] = points[i + 6]; - arr[sz++] = points[i + 7]; - arr[sz++] = textureId; + return TilemapShader; + }(PIXI.Shader)); + tilemap.TilemapShader = TilemapShader; + var RectTileShader = (function (_super) { + __extends(RectTileShader, _super); + function RectTileShader(gl, maxTextures) { + var _this = _super.call(this, gl, maxTextures, rectShaderVert, tilemap.shaderGenerator.generateFragmentSrc(maxTextures, rectShaderFrag)) || this; + _this.vertSize = 11; + _this.vertPerQuad = 4; + _this.stride = _this.vertSize * 4; + tilemap.shaderGenerator.fillSamplers(_this, _this.maxTextures); + return _this; } - } else { - //var tint = 0xffffffff; - var tint = -1; - for (i = 0;i> 2); - shiftU = 1024 * (points[i+8] & 1); - shiftV = 1024 * ((points[i+8] >> 1) & 1); - var x = points[i+2], y = points[i+3]; - var w = points[i+4], h = points[i+5]; - var u = points[i] + shiftU, v = points[i+1] + shiftV; - var animX = points[i+6], animY = points[i+7]; - arr[sz++] = x; - arr[sz++] = y; - arr[sz++] = u; - arr[sz++] = v; - arr[sz++] = u + eps; - arr[sz++] = v + eps; - arr[sz++] = u + w - eps; - arr[sz++] = v + h - eps; - arr[sz++] = animX; - arr[sz++] = animY; - arr[sz++] = textureId; - arr[sz++] = x + w; - arr[sz++] = y; - arr[sz++] = u + w; - arr[sz++] = v; - arr[sz++] = u + eps; - arr[sz++] = v + eps; - arr[sz++] = u + w - eps; - arr[sz++] = v + h - eps; - arr[sz++] = animX; - arr[sz++] = animY; - arr[sz++] = textureId; - arr[sz++] = x + w; - arr[sz++] = y + h; - arr[sz++] = u + w; - arr[sz++] = v + h; - arr[sz++] = u + eps; - arr[sz++] = v + eps; - arr[sz++] = u + w - eps; - arr[sz++] = v + h - eps; - arr[sz++] = animX; - arr[sz++] = animY; - arr[sz++] = textureId; - arr[sz++] = x; - arr[sz++] = y + h; - arr[sz++] = u; - arr[sz++] = v + h; - arr[sz++] = u + eps; - arr[sz++] = v + eps; - arr[sz++] = u + w - eps; - arr[sz++] = v + h - eps; - arr[sz++] = animX; - arr[sz++] = animY; - arr[sz++] = textureId; + RectTileShader.prototype.createVao = function (renderer, vb) { + var gl = renderer.gl; + return renderer.createVao() + .addIndex(this.indexBuffer) + .addAttribute(vb, this.attributes.aVertexPosition, gl.FLOAT, false, this.stride, 0) + .addAttribute(vb, this.attributes.aTextureCoord, gl.FLOAT, false, this.stride, 2 * 4) + .addAttribute(vb, this.attributes.aFrame, gl.FLOAT, false, this.stride, 4 * 4) + .addAttribute(vb, this.attributes.aAnim, gl.FLOAT, false, this.stride, 8 * 4) + .addAttribute(vb, this.attributes.aTextureId, gl.FLOAT, false, this.stride, 10 * 4); + }; + return RectTileShader; + }(TilemapShader)); + tilemap.RectTileShader = RectTileShader; + })(tilemap = PIXI.tilemap || (PIXI.tilemap = {})); +})(PIXI || (PIXI = {})); +var PIXI; +(function (PIXI) { + var tilemap; + (function (tilemap) { + var shaderGenerator; + (function (shaderGenerator) { + function fillSamplers(shader, maxTextures) { + var sampleValues = []; + for (var i = 0; i < maxTextures; i++) { + sampleValues[i] = i; + } + shader.bind(); + shader.uniforms.uSamplers = sampleValues; + var samplerSize = []; + for (i = 0; i < maxTextures; i++) { + samplerSize.push(1.0 / 2048); + samplerSize.push(1.0 / 2048); + } + shader.uniforms.uSamplerSize = samplerSize; } - } - // if (vs > this.vbArray.length/2 ) { - vb.upload(arr, 0, true); - // } else { - // var view = arr.subarray(0, vs); - // vb.upload(view, 0); - // } - } - if (useSquare) - gl.drawArrays(gl.POINTS, 0, vertices); - else - gl.drawElements(gl.TRIANGLES, rectsCount * 6, gl.UNSIGNED_SHORT, 0); -}; - -module.exports = RectTileLayer; - -},{}],5:[function(require,module,exports){ -var shaderGenerator = require('./shaderGenerator'); - -function RectTileShader(gl, maxTextures) -{ - PIXI.Shader.call(this, gl, - "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\nattribute vec4 aFrame;\nattribute vec2 aAnim;\nattribute float aTextureId;\n\nuniform mat3 projectionMatrix;\nuniform vec2 animationFrame;\n\nvarying vec2 vTextureCoord;\nvarying float vTextureId;\nvarying vec4 vFrame;\n\nvoid main(void){\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n vec2 anim = aAnim * animationFrame;\n vTextureCoord = aTextureCoord + anim;\n vFrame = aFrame + vec4(anim, anim);\n vTextureId = aTextureId;\n}\n", - shaderGenerator.generateFragmentSrc(maxTextures, "#define GLSLIFY 1\nvarying vec2 vTextureCoord;\nvarying vec4 vFrame;\nvarying float vTextureId;\nuniform vec4 shadowColor;\nuniform sampler2D uSamplers[%count%];\nuniform vec2 uSamplerSize[%count%];\n\nvoid main(void){\n vec2 textureCoord = clamp(vTextureCoord, vFrame.xy, vFrame.zw);\n float textureId = floor(vTextureId + 0.5);\n\n vec4 color;\n %forloop%\n gl_FragColor = color;\n}\n") - ); - this.maxTextures = maxTextures; - this.vertSize = 11; - this.vertPerQuad = 4; - this.stride = this.vertSize * 4; - shaderGenerator.fillSamplers(this, this.maxTextures); -} - -RectTileShader.prototype = Object.create(PIXI.Shader.prototype); -RectTileShader.prototype.constructor = RectTileShader; -RectTileShader.prototype.createVao = function (renderer, vb) { - var gl = renderer.gl; - return renderer.createVao() - .addIndex(this.indexBuffer) - .addAttribute(vb, this.attributes.aVertexPosition, gl.FLOAT, false, this.stride, 0) - .addAttribute(vb, this.attributes.aTextureCoord, gl.FLOAT, false, this.stride, 2 * 4) - .addAttribute(vb, this.attributes.aFrame, gl.FLOAT, false, this.stride, 4 * 4) - .addAttribute(vb, this.attributes.aAnim, gl.FLOAT, false, this.stride, 8 * 4) - .addAttribute(vb, this.attributes.aTextureId, gl.FLOAT, false, this.stride, 10 * 4); -}; - -module.exports = RectTileShader; - -},{"./shaderGenerator":9}],6:[function(require,module,exports){ -var shaderGenerator = require('./shaderGenerator'); - - -function SquareTileShader(gl, maxTextures) { - PIXI.Shader.call(this, gl, - "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\nattribute vec2 aAnim;\nattribute float aTextureId;\nattribute float aSize;\n\nuniform mat3 projectionMatrix;\nuniform vec2 samplerSize;\nuniform vec2 animationFrame;\nuniform float projectionScale;\n\nvarying vec2 vTextureCoord;\nvarying float vSize;\nvarying float vTextureId;\n\nvoid main(void){\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition + aSize * 0.5, 1.0)).xy, 0.0, 1.0);\n gl_PointSize = aSize * projectionScale;\n vTextureCoord = aTextureCoord + aAnim * animationFrame;\n vTextureId = aTextureId;\n vSize = aSize;\n}\n", - shaderGenerator.generateFragmentSrc(maxTextures, "#define GLSLIFY 1\nvarying vec2 vTextureCoord;\nvarying float vSize;\nvarying float vTextureId;\n\nuniform vec4 shadowColor;\nuniform sampler2D uSamplers[%count%];\nuniform vec2 uSamplerSize[%count%];\nuniform vec2 pointScale;\n\nvoid main(void){\n float margin = 0.5 / vSize;\n vec2 pointCoord = (gl_PointCoord - 0.5) * pointScale + 0.5;\n vec2 clamped = vec2(clamp(pointCoord.x, margin, 1.0 - margin), clamp(pointCoord.y, margin, 1.0 - margin));\n vec2 textureCoord = pointCoord * vSize + vTextureCoord;\n float textureId = vTextureId;\n vec4 color;\n %forloop%\n gl_FragColor = color;\n}\n") - ); - this.maxTextures = maxTextures; - this.vertSize = 8; - this.vertPerQuad = 1; - this.stride = this.vertSize * 4; - shaderGenerator.fillSamplers(this, this.maxTextures); -} - -SquareTileShader.prototype = Object.create(PIXI.Shader.prototype); -SquareTileShader.prototype.constructor = SquareTileShader; -SquareTileShader.prototype.createVao = function (renderer, vb) { - var gl = renderer.gl; - return renderer.createVao() - .addIndex(this.indexBuffer) - .addAttribute(vb, this.attributes.aVertexPosition, gl.FLOAT, false, this.stride, 0) - .addAttribute(vb, this.attributes.aTextureCoord, gl.FLOAT, false, this.stride, 2 * 4) - .addAttribute(vb, this.attributes.aSize, gl.FLOAT, false, this.stride, 4 * 4) - .addAttribute(vb, this.attributes.aAnim, gl.FLOAT, false, this.stride, 5 * 4) - .addAttribute(vb, this.attributes.aTextureId, gl.FLOAT, false, this.stride, 7 * 4); -}; - -module.exports = SquareTileShader; - -},{"./shaderGenerator":9}],7:[function(require,module,exports){ -var RectTileShader = require('./RectTileShader'), - SquareTileShader = require('./SquareTileShader'), - glCore = PIXI.glCore; - -/* - * Renderer for square and rectangle tiles. - * Squares cannot be rotated, skewed. - * For container with squares, scale.x must be equals to scale.y, matrix.a to matrix.d - * Rectangles do not care about that. - * - * @class - * @memberof PIXI.tilemap - * @extends PIXI.ObjectRenderer - * @param renderer {PIXI.WebGLRenderer} The renderer this sprite batch works for. - */ - -function TileRenderer(renderer) { - PIXI.ObjectRenderer.call(this, renderer); - this.vbs = {}; - this.lastTimeCheck = 0; - this.tileAnim = [0, 0]; - this.maxTextures = 4; - this.indices = []; - this.indexBuffer = null; -} - -TileRenderer.prototype = Object.create(PIXI.ObjectRenderer.prototype); -TileRenderer.prototype.constructor = TileRenderer; -TileRenderer.vbAutoincrement = 0; -TileRenderer.SCALE_MODE = PIXI.SCALE_MODES.DEFAULT; - -TileRenderer.prototype.onContextChange = function () { - var gl = this.renderer.gl; - var maxTextures = this.maxTextures; - this.rectShader = new RectTileShader(gl, maxTextures); - this.squareShader = new SquareTileShader(gl, maxTextures); - this.checkIndexBuffer(2000); - this.rectShader.indexBuffer = this.indexBuffer; - this.squareShader.indexBuffer = this.indexBuffer; - this.vbs = {}; - this.glTextures = []; - this.boundSprites = []; - this.initBounds(); -}; - -TileRenderer.prototype.initBounds = function () { - var gl = this.renderer.gl; - var tempCanvas = document.createElement('canvas'); - tempCanvas.width = 2048; - tempCanvas.height = 2048; - // tempCanvas.getContext('2d').clearRect(0, 0, 2048, 2048); - for (var i = 0; i < this.maxTextures; i++) { - var glt = new glCore.GLTexture(gl); - glt.premultiplyAlpha = true; - glt.upload(tempCanvas); - glt.enableWrapClamp(); - - if (TileRenderer.SCALE_MODE === PIXI.SCALE_MODES.LINEAR) { - glt.enableLinearScaling(); - } else { - glt.enableNearestScaling(); - } - - this.glTextures.push(glt); - var bs = []; - for (var j = 0; j < 4; j++) { - var spr = new PIXI.Sprite(); - spr.position.x = 1024 * (j & 1); - spr.position.y = 1024 * (j >> 1); - bs.push(spr); - } - this.boundSprites.push(bs); - } -}; - -glCore.GLTexture.prototype._hackSubImage = function (sprite) { - this.bind(); - var gl = this.gl; - var baseTex = sprite.texture.baseTexture; - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1); - gl.texSubImage2D(gl.TEXTURE_2D, 0, sprite.position.x, sprite.position.y, this.format, this.type, baseTex.source); -}; - -TileRenderer.prototype.bindTextures = function (renderer, textures) { - var bounds = this.boundSprites; - var glts = this.glTextures; - var len = textures.length; - var maxTextures = this.maxTextures; - if (len >= 4 * maxTextures) { - return; - } - var i; - for (i = 0; i < len; i++) { - var texture = textures[i]; - renderer.bindTexture(texture); - if (!texture || !textures[i].valid) continue; - var bs = bounds[i >> 2][i & 3]; - if (!bs.texture || - bs.texture.baseTexture !== texture.baseTexture) { - bs.texture = texture; - var glt = glts[i >> 2]; - glt._hackSubImage(bs); - } - } - for (i = 0; i < maxTextures; i++) { - glts[i].bind(i); - } - renderer._activeTextureLocation = maxTextures - 1; -}; - -TileRenderer.prototype.checkLeaks = function () { - var now = Date.now(); - var old = now - 10000; - if (this.lastTimeCheck < old || - this.lastTimeCheck > now) { - this.lastTimeCheck = now; - var vbs = this.vbs; - for (var key in vbs) { - if (vbs[key].lastTimeAccess < old) { - this.removeVb(key); + shaderGenerator.fillSamplers = fillSamplers; + function generateFragmentSrc(maxTextures, fragmentSrc) { + return fragmentSrc.replace(/%count%/gi, maxTextures + "") + .replace(/%forloop%/gi, this.generateSampleSrc(maxTextures)); } - } - } -}; - -TileRenderer.prototype.start = function () { - this.renderer.state.setBlendMode(PIXI.BLEND_MODES.NORMAL); - //sorry, nothing -}; - -TileRenderer.prototype.getVb = function (id) { - this.checkLeaks(); - var vb = this.vbs[id]; - if (vb) { - vb.lastAccessTime = Date.now(); - return vb; - } - return null; -}; - -TileRenderer.prototype.createVb = function (useSquare) { - var id = ++TileRenderer.vbAutoincrement; - var shader = this.getShader(useSquare); - var gl = this.renderer.gl; - var vb = PIXI.glCore.GLBuffer.createVertexBuffer(gl, null, gl.STREAM_DRAW); - var stuff = { - id: id, - vb: vb, - vao: shader.createVao(this.renderer, vb), - lastTimeAccess: Date.now(), - useSquare: useSquare, - shader: shader - }; - this.vbs[id] = stuff; - return stuff; -}; - -TileRenderer.prototype.removeVb = function (id) { - if (this.vbs[id]) { - this.vbs[id].vb.destroy(); - this.vbs[id].vao.destroy(); - delete this.vbs[id]; - } -}; - -TileRenderer.prototype.checkIndexBuffer = function (size) { - // the total number of indices in our array, there are 6 points per quad. - var totalIndices = size * 6; - var indices = this.indices; - if (totalIndices <= indices.length) { - return; - } - var len = indices.length || totalIndices; - while (len < totalIndices) { - len <<= 1; - } - - indices = new Uint16Array(len); - this.indices = indices; - - // fill the indices with the quads to draw - for (var i = 0, j = 0; i + 5 < indices.length; i += 6, j += 4) { - indices[i + 0] = j + 0; - indices[i + 1] = j + 1; - indices[i + 2] = j + 2; - indices[i + 3] = j + 0; - indices[i + 4] = j + 2; - indices[i + 5] = j + 3; - } - - if (this.indexBuffer) { - this.indexBuffer.upload(indices); - } else { - var gl = this.renderer.gl; - this.indexBuffer = glCore.GLBuffer.createIndexBuffer(gl, this.indices, gl.STATIC_DRAW); - } -}; - -TileRenderer.prototype.getShader = function (useSquare) { - return useSquare ? this.squareShader : this.rectShader; -}; - -TileRenderer.prototype.destroy = function () { - PIXI.ObjectRenderer.prototype.destroy.call(this); - this.rectShader.destroy(); - this.squareShader.destroy(); - this.rectShader = null; - this.squareShader = null; -}; - -PIXI.WebGLRenderer.registerPlugin('tile', TileRenderer); - -module.exports = TileRenderer; - -},{"./RectTileShader":5,"./SquareTileShader":6}],8:[function(require,module,exports){ -function ZLayer() { - this.initialize.apply(this, arguments); -} - -ZLayer.prototype = Object.create(PIXI.Container.prototype); -ZLayer.prototype.initialize = function(tilemap, zIndex) { - PIXI.Container.apply(this, arguments); - this.tilemap = tilemap; - this.z = zIndex; -}; - -ZLayer.prototype.clear = function() { - var layers = this.children; - for (var i=0; i 0 && clearHeight > 0) { + gl.texSubImage2D(gl.TEXTURE_2D, 0, sprite.position.x, sprite.position.y, clearWidth, clearHeight, tex.format, tex.type, clearBuffer); } - - src += '\n{'; - src += '\n\tcolor = texture2D(uSamplers['+i+'], textureCoord * uSamplerSize['+i+']);'; - src += '\n}'; + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1); + gl.texSubImage2D(gl.TEXTURE_2D, 0, sprite.position.x, sprite.position.y, tex.format, tex.type, baseTex.source); } - - src += '\n'; - src += '\n'; - - return src; - } -}; - -module.exports = shaderGenerator; - -},{}],10:[function(require,module,exports){ -PIXI.tilemap = { - ZLayer: require('./ZLayer'), - GraphicsLayer: require('./GraphicsLayer'), - RectTileLayer: require('./RectTileLayer'), - CompositeRectTileLayer: require('./CompositeRectTileLayer'), - CanvasTileRenderer: require('./CanvasTileRenderer'), - TileRenderer: require('./TileRenderer') -}; - -module.exports = PIXI.tilemap; - -},{"./CanvasTileRenderer":1,"./CompositeRectTileLayer":2,"./GraphicsLayer":3,"./RectTileLayer":4,"./TileRenderer":7,"./ZLayer":8}]},{},[10])(10) -}); - - -//# sourceMappingURL=pixi-tilemap.js.map + var TileRenderer = (function (_super) { + __extends(TileRenderer, _super); + function TileRenderer(renderer) { + var _this = _super.call(this, renderer) || this; + _this.vbs = {}; + _this.indices = new Uint16Array(0); + _this.lastTimeCheck = 0; + _this.tileAnim = [0, 0]; + _this.maxTextures = 4; + _this.texLoc = []; + return _this; + } + TileRenderer.prototype.onContextChange = function () { + var gl = this.renderer.gl; + var maxTextures = this.maxTextures; + this.rectShader = new tilemap.RectTileShader(gl, maxTextures); + this.squareShader = new tilemap.SquareTileShader(gl, maxTextures); + this.checkIndexBuffer(2000); + this.rectShader.indexBuffer = this.indexBuffer; + this.squareShader.indexBuffer = this.indexBuffer; + this.vbs = {}; + this.glTextures = []; + this.boundSprites = []; + this.initBounds(); + }; + TileRenderer.prototype.initBounds = function () { + var gl = this.renderer.gl; + var tempCanvas = document.createElement('canvas'); + tempCanvas.width = 2048; + tempCanvas.height = 2048; + for (var i = 0; i < this.maxTextures; i++) { + var rt = PIXI.RenderTexture.create(2048, 2048); + rt.baseTexture.premultipliedAlpha = true; + rt.baseTexture.scaleMode = TileRenderer.SCALE_MODE; + rt.baseTexture.wrapMode = PIXI.WRAP_MODES.CLAMP; + this.renderer.textureManager.updateTexture(rt); + this.glTextures.push(rt); + var bs = []; + for (var j = 0; j < 4; j++) { + var spr = new PIXI.Sprite(); + spr.position.x = 1024 * (j & 1); + spr.position.y = 1024 * (j >> 1); + bs.push(spr); + } + this.boundSprites.push(bs); + } + }; + TileRenderer.prototype.bindTextures = function (renderer, shader, textures) { + var bounds = this.boundSprites; + var glts = this.glTextures; + var len = textures.length; + var maxTextures = this.maxTextures; + if (len > 4 * maxTextures) { + return; + } + var doClear = TileRenderer.DO_CLEAR; + if (doClear && !this._clearBuffer) { + this._clearBuffer = new Uint8Array(1024 * 1024 * 4); + } + var i; + for (i = 0; i < len; i++) { + var texture = textures[i]; + if (!texture || !textures[i].valid) + continue; + var bs = bounds[i >> 2][i & 3]; + if (!bs.texture || + bs.texture.baseTexture !== texture.baseTexture) { + bs.texture = texture; + var glt = glts[i >> 2]; + renderer.bindTexture(glt, 0, true); + if (doClear) { + _hackSubImage(glt.baseTexture._glTextures[renderer.CONTEXT_UID], bs, this._clearBuffer, 1024, 1024); + } + else { + _hackSubImage(glt.baseTexture._glTextures[renderer.CONTEXT_UID], bs); + } + } + } + this.texLoc.length = 0; + for (i = 0; i < maxTextures; i++) { + this.texLoc.push(renderer.bindTexture(glts[i], i, true)); + } + shader.uniforms.uSamplers = this.texLoc; + }; + TileRenderer.prototype.checkLeaks = function () { + var now = Date.now(); + var old = now - 10000; + if (this.lastTimeCheck < old || + this.lastTimeCheck > now) { + this.lastTimeCheck = now; + var vbs = this.vbs; + for (var key in vbs) { + if (vbs[key].lastTimeAccess < old) { + this.removeVb(key); + } + } + } + }; + ; + TileRenderer.prototype.start = function () { + this.renderer.state.setBlendMode(PIXI.BLEND_MODES.NORMAL); + }; + TileRenderer.prototype.getVb = function (id) { + this.checkLeaks(); + var vb = this.vbs[id]; + if (vb) { + vb.lastAccessTime = Date.now(); + return vb; + } + return null; + }; + TileRenderer.prototype.createVb = function (useSquare) { + var id = ++TileRenderer.vbAutoincrement; + var shader = this.getShader(useSquare); + var gl = this.renderer.gl; + var vb = PIXI.glCore.GLBuffer.createVertexBuffer(gl, null, gl.STREAM_DRAW); + var stuff = { + id: id, + vb: vb, + vao: shader.createVao(this.renderer, vb), + lastTimeAccess: Date.now(), + useSquare: useSquare, + shader: shader + }; + this.vbs[id] = stuff; + return stuff; + }; + TileRenderer.prototype.removeVb = function (id) { + if (this.vbs[id]) { + this.vbs[id].vb.destroy(); + this.vbs[id].vao.destroy(); + delete this.vbs[id]; + } + }; + TileRenderer.prototype.checkIndexBuffer = function (size) { + var totalIndices = size * 6; + var indices = this.indices; + if (totalIndices <= indices.length) { + return; + } + var len = indices.length || totalIndices; + while (len < totalIndices) { + len <<= 1; + } + indices = new Uint16Array(len); + this.indices = indices; + for (var i = 0, j = 0; i + 5 < indices.length; i += 6, j += 4) { + indices[i + 0] = j + 0; + indices[i + 1] = j + 1; + indices[i + 2] = j + 2; + indices[i + 3] = j + 0; + indices[i + 4] = j + 2; + indices[i + 5] = j + 3; + } + if (this.indexBuffer) { + this.indexBuffer.upload(indices); + } + else { + var gl = this.renderer.gl; + this.indexBuffer = glCore.GLBuffer.createIndexBuffer(gl, this.indices, gl.STATIC_DRAW); + } + }; + TileRenderer.prototype.getShader = function (useSquare) { + return useSquare ? this.squareShader : this.rectShader; + }; + TileRenderer.prototype.destroy = function () { + _super.prototype.destroy.call(this); + this.rectShader.destroy(); + this.squareShader.destroy(); + this.rectShader = null; + this.squareShader = null; + }; + ; + return TileRenderer; + }(PIXI.ObjectRenderer)); + TileRenderer.vbAutoincrement = 0; + TileRenderer.SCALE_MODE = PIXI.SCALE_MODES.LINEAR; + TileRenderer.DO_CLEAR = false; + tilemap.TileRenderer = TileRenderer; + PIXI.WebGLRenderer.registerPlugin('tilemap', TileRenderer); + })(tilemap = PIXI.tilemap || (PIXI.tilemap = {})); +})(PIXI || (PIXI = {})); +var PIXI; +(function (PIXI) { + var tilemap; + (function (tilemap_1) { + var ZLayer = (function (_super) { + __extends(ZLayer, _super); + function ZLayer(tilemap, zIndex) { + var _this = _super.call(this) || this; + _this._lastAnimationFrame = -1; + _this.tilemap = tilemap; + _this.z = zIndex; + return _this; + } + ZLayer.prototype.clear = function () { + var layers = this.children; + for (var i = 0; i < layers.length; i++) + layers[i].clear(); + this._previousLayers = 0; + }; + ZLayer.prototype.cacheIfDirty = function () { + var tilemap = this.tilemap; + var layers = this.children; + var modified = this._previousLayers != layers.length; + this._previousLayers = layers.length; + var buf = this.canvasBuffer; + var tempRender = this._tempRender; + if (!buf) { + buf = this.canvasBuffer = document.createElement('canvas'); + tempRender = this._tempRender = new PIXI.CanvasRenderer(100, 100, { view: buf }); + tempRender.context = tempRender.rootContext; + tempRender.plugins.tilemap.dontUseTransform = true; + } + if (buf.width != tilemap._layerWidth || + buf.height != tilemap._layerHeight) { + buf.width = tilemap._layerWidth; + buf.height = tilemap._layerHeight; + modified = true; + } + var i; + if (!modified) { + for (i = 0; i < layers.length; i++) { + if (layers[i].isModified(this._lastAnimationFrame != tilemap.animationFrame)) { + modified = true; + break; + } + } + } + this._lastAnimationFrame = tilemap.animationFrame; + if (modified) { + if (tilemap._hackRenderer) { + tilemap._hackRenderer(tempRender); + } + tempRender.context.clearRect(0, 0, buf.width, buf.height); + for (i = 0; i < layers.length; i++) { + layers[i].clearModify(); + layers[i].renderCanvas(tempRender); + } + } + this.layerTransform = this.worldTransform; + for (i = 0; i < layers.length; i++) { + this.layerTransform = layers[i].worldTransform; + break; + } + }; + ; + ZLayer.prototype.renderCanvas = function (renderer) { + this.cacheIfDirty(); + var wt = this.layerTransform; + renderer.context.setTransform(wt.a, wt.b, wt.c, wt.d, wt.tx * renderer.resolution, wt.ty * renderer.resolution); + var tilemap = this.tilemap; + renderer.context.drawImage(this.canvasBuffer, 0, 0); + }; + ; + return ZLayer; + }(PIXI.Container)); + tilemap_1.ZLayer = ZLayer; + })(tilemap = PIXI.tilemap || (PIXI.tilemap = {})); +})(PIXI || (PIXI = {})); +//# sourceMappingURL=pixi-tilemap.js.map \ No newline at end of file diff --git a/js/libs/pixi.js b/js/libs/pixi.js index dbfab8f1..4d0e32ca 100644 --- a/js/libs/pixi.js +++ b/js/libs/pixi.js @@ -1,6 +1,6 @@ /*! - * pixi.js - v4.0.3 - * Compiled Wed Oct 12 2016 19:18:54 GMT+0300 (RTZ 2 (зима)) + * pixi.js - v4.5.4 + * Compiled Wed, 23 Aug 2017 10:08:43 UTC * * pixi.js is licensed under the MIT License. * http://www.opensource.org/licenses/mit-license @@ -33,7 +33,7 @@ var Buffer = function(gl, type, data, drawType) * * @member {WebGLBuffer} */ - this.buffer = gl.createBuffer(); + this.buffer = gl.createBuffer(); /** * The type of the buffer @@ -60,6 +60,8 @@ var Buffer = function(gl, type, data, drawType) { this.upload(data); } + + this._updateID = 0; }; /** @@ -216,6 +218,8 @@ Framebuffer.prototype.enableStencil = function() // TODO.. this is depth AND stencil? gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.stencil); gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, this.width , this.height ); + + }; /** @@ -227,12 +231,11 @@ Framebuffer.prototype.enableStencil = function() */ Framebuffer.prototype.clear = function( r, g, b, a ) { - this.bind(); - var gl = this.gl; gl.clearColor(r, g, b, a); - gl.clear(gl.COLOR_BUFFER_BIT); + this.bind(); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); }; /** @@ -241,12 +244,6 @@ Framebuffer.prototype.clear = function( r, g, b, a ) Framebuffer.prototype.bind = function() { var gl = this.gl; - - if(this.texture) - { - this.texture.unbind(); - } - gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer ); }; @@ -321,6 +318,7 @@ Framebuffer.createRGBA = function(gl, width, height, data) //now create the framebuffer object and attach the texture to it. var fbo = new Framebuffer(gl, width, height); fbo.enableTexture(texture); + //fbo.enableStencil(); // get this back on soon! fbo.unbind(); @@ -358,6 +356,7 @@ module.exports = Framebuffer; var compileProgram = require('./shader/compileProgram'), extractAttributes = require('./shader/extractAttributes'), extractUniforms = require('./shader/extractUniforms'), + setPrecision = require('./shader/setPrecision'), generateUniformAccessObject = require('./shader/generateUniformAccessObject'); /** @@ -368,8 +367,10 @@ var compileProgram = require('./shader/compileProgram'), * @param gl {WebGLRenderingContext} * @param vertexSrc {string|string[]} The vertex shader source as an array of strings. * @param fragmentSrc {string|string[]} The fragment shader source as an array of strings. + * @param precision {precision]} The float precision of the shader. Options are 'lowp', 'mediump' or 'highp'. + * @param attributeLocations {object} A key value pair showing which location eact attribute should sit eg {position:0, uvs:1} */ -var Shader = function(gl, vertexSrc, fragmentSrc) +var Shader = function(gl, vertexSrc, fragmentSrc, precision, attributeLocations) { /** * The current WebGL rendering context @@ -378,14 +379,19 @@ var Shader = function(gl, vertexSrc, fragmentSrc) */ this.gl = gl; + if(precision) + { + vertexSrc = setPrecision(vertexSrc, precision); + fragmentSrc = setPrecision(fragmentSrc, precision); + } + /** * The shader program * * @member {WebGLProgram} */ // First compile the program.. - this.program = compileProgram(gl, vertexSrc, fragmentSrc); - + this.program = compileProgram(gl, vertexSrc, fragmentSrc, attributeLocations); /** * The attributes of the shader as an object containing the following properties @@ -400,7 +406,7 @@ var Shader = function(gl, vertexSrc, fragmentSrc) // next extract the attributes this.attributes = extractAttributes(gl, this.program); - var uniformData = extractUniforms(gl, this.program); + this.uniformData = extractUniforms(gl, this.program); /** * The uniforms of the shader as an object containing the following properties @@ -410,7 +416,8 @@ var Shader = function(gl, vertexSrc, fragmentSrc) * } * @member {Object} */ - this.uniforms = generateUniformAccessObject( gl, uniformData ); + this.uniforms = generateUniformAccessObject( gl, this.uniformData ); + }; /** * Uses this shader @@ -426,12 +433,18 @@ Shader.prototype.bind = function() */ Shader.prototype.destroy = function() { - // var gl = this.gl; + this.attributes = null; + this.uniformData = null; + this.uniforms = null; + + var gl = this.gl; + gl.deleteProgram(this.program); }; + module.exports = Shader; -},{"./shader/compileProgram":9,"./shader/extractAttributes":11,"./shader/extractUniforms":12,"./shader/generateUniformAccessObject":13}],4:[function(require,module,exports){ +},{"./shader/compileProgram":9,"./shader/extractAttributes":11,"./shader/extractUniforms":12,"./shader/generateUniformAccessObject":13,"./shader/setPrecision":17}],4:[function(require,module,exports){ /** * Helper class to create a WebGL Texture @@ -525,7 +538,7 @@ Texture.prototype.upload = function(source) if(newHeight !== this.height || newWidth !== this.width) { - gl.texImage2D(gl.TEXTURE_2D, 0, this.format, this.format, this.type, source); + gl.texImage2D(gl.TEXTURE_2D, 0, this.format, this.format, this.type, source); } else { @@ -574,7 +587,7 @@ Texture.prototype.uploadData = function(data, width, height) else { // TODO support for other types - this.type = gl.UNSIGNED_BYTE; + this.type = this.type || gl.UNSIGNED_BYTE; } // what type of data? @@ -904,19 +917,20 @@ VertexArrayObject.prototype.activate = function() lastBuffer = attrib.buffer; } - //attrib.attribute.pointer(attrib.type, attrib.normalized, attrib.stride, attrib.start); gl.vertexAttribPointer(attrib.attribute.location, - attrib.attribute.size, attrib.type || gl.FLOAT, + attrib.attribute.size, + attrib.type || gl.FLOAT, attrib.normalized || false, attrib.stride || 0, attrib.start || 0); - - } setVertexAttribArrays(gl, this.attributes, this.nativeState); - this.indexBuffer.bind(); + if(this.indexBuffer) + { + this.indexBuffer.bind(); + } return this; }; @@ -989,7 +1003,16 @@ VertexArrayObject.prototype.clear = function() VertexArrayObject.prototype.draw = function(type, size, start) { var gl = this.gl; - gl.drawElements(type, size, gl.UNSIGNED_SHORT, start || 0); + + if(this.indexBuffer) + { + gl.drawElements(type, size || this.indexBuffer.data.length, gl.UNSIGNED_SHORT, (start || 0) * 2 ); + } + else + { + // TODO need a better way to calculate size.. + gl.drawArrays(type, start, size || this.getSize()); + } return this; }; @@ -1014,6 +1037,12 @@ VertexArrayObject.prototype.destroy = function() this.nativeVao = null; }; +VertexArrayObject.prototype.getSize = function() +{ + var attrib = this.attributes[0]; + return attrib.buffer.data.length / (( attrib.stride/4 ) || attrib.attribute.size); +}; + },{"./setVertexAttribArrays":8}],6:[function(require,module,exports){ /** @@ -1028,7 +1057,7 @@ VertexArrayObject.prototype.destroy = function() */ var createContext = function(canvas, options) { - var gl = canvas.getContext('webgl', options) || + var gl = canvas.getContext('webgl', options) || canvas.getContext('experimental-webgl', options); if (!gl) @@ -1134,9 +1163,10 @@ module.exports = setVertexAttribArrays; * @param gl {WebGLRenderingContext} The current WebGL context {WebGLProgram} * @param vertexSrc {string|string[]} The vertex shader source as an array of strings. * @param fragmentSrc {string|string[]} The fragment shader source as an array of strings. + * @param attributeLocations {Object} An attribute location map that lets you manually set the attribute locations * @return {WebGLProgram} the shader program */ -var compileProgram = function(gl, vertexSrc, fragmentSrc) +var compileProgram = function(gl, vertexSrc, fragmentSrc, attributeLocations) { var glVertShader = compileShader(gl, gl.VERTEX_SHADER, vertexSrc); var glFragShader = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSrc); @@ -1145,6 +1175,17 @@ var compileProgram = function(gl, vertexSrc, fragmentSrc) gl.attachShader(program, glVertShader); gl.attachShader(program, glFragShader); + + // optionally, set the attributes manually for the program rather than letting WebGL decide.. + if(attributeLocations) + { + for(var i in attributeLocations) + { + gl.bindAttribLocation(program, attributeLocations[i], i); + } + } + + gl.linkProgram(program); // if linking fails, then log and cleanup @@ -1203,36 +1244,36 @@ module.exports = compileProgram; * @param type {String} Type of value * @param size {Number} */ -var defaultValue = function(type, size) +var defaultValue = function(type, size) { switch (type) { case 'float': return 0; - case 'vec2': + case 'vec2': return new Float32Array(2 * size); case 'vec3': return new Float32Array(3 * size); - case 'vec4': + case 'vec4': return new Float32Array(4 * size); - + case 'int': case 'sampler2D': return 0; - case 'ivec2': + case 'ivec2': return new Int32Array(2 * size); case 'ivec3': return new Int32Array(3 * size); - case 'ivec4': + case 'ivec4': return new Int32Array(4 * size); - case 'bool': + case 'bool': return false; case 'bvec2': @@ -1249,7 +1290,7 @@ var defaultValue = function(type, size) return new Float32Array([1, 0, 0, 1]); - case 'mat3': + case 'mat3': return new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]); @@ -1266,7 +1307,7 @@ var booleanArray = function(size) { var array = new Array(size); - for (var i = 0; i < array.length; i++) + for (var i = 0; i < array.length; i++) { array[i] = false; } @@ -1382,6 +1423,7 @@ var generateUniformAccessObject = function(gl, uniformData) var nameTokens = fullName.split('.'); var name = nameTokens[nameTokens.length - 1]; + var uniformGroup = getUniformGroup(nameTokens, uniforms); var uniform = uniformData[fullName]; @@ -1505,18 +1547,19 @@ module.exports = { extractAttributes: require('./extractAttributes'), extractUniforms: require('./extractUniforms'), generateUniformAccessObject: require('./generateUniformAccessObject'), + setPrecision: require('./setPrecision'), mapSize: require('./mapSize'), - mapType: require('./mapType') + mapType: require('./mapType') }; -},{"./compileProgram":9,"./defaultValue":10,"./extractAttributes":11,"./extractUniforms":12,"./generateUniformAccessObject":13,"./mapSize":15,"./mapType":16}],15:[function(require,module,exports){ +},{"./compileProgram":9,"./defaultValue":10,"./extractAttributes":11,"./extractUniforms":12,"./generateUniformAccessObject":13,"./mapSize":15,"./mapType":16,"./setPrecision":17}],15:[function(require,module,exports){ /** * @class * @memberof PIXI.glCore.shader * @param type {String} * @return {Number} */ -var mapSize = function(type) -{ +var mapSize = function(type) +{ return GLSL_TO_SIZE[type]; }; @@ -1549,15 +1592,15 @@ module.exports = mapSize; },{}],16:[function(require,module,exports){ -var mapSize = function(gl, type) +var mapSize = function(gl, type) { - if(!GL_TABLE) + if(!GL_TABLE) { var typeNames = Object.keys(GL_TO_GLSL_TYPES); GL_TABLE = {}; - for(var i = 0; i < typeNames.length; ++i) + for(var i = 0; i < typeNames.length; ++i) { var tn = typeNames[i]; GL_TABLE[ gl[tn] ] = GL_TO_GLSL_TYPES[tn]; @@ -1579,22 +1622,42 @@ var GL_TO_GLSL_TYPES = { 'INT_VEC2': 'ivec2', 'INT_VEC3': 'ivec3', 'INT_VEC4': 'ivec4', - + 'BOOL': 'bool', 'BOOL_VEC2': 'bvec2', 'BOOL_VEC3': 'bvec3', 'BOOL_VEC4': 'bvec4', - + 'FLOAT_MAT2': 'mat2', 'FLOAT_MAT3': 'mat3', 'FLOAT_MAT4': 'mat4', - - 'SAMPLER_2D': 'sampler2D' + + 'SAMPLER_2D': 'sampler2D' }; module.exports = mapSize; },{}],17:[function(require,module,exports){ +/** + * Sets the float precision on the shader. If the precision is already present this function will do nothing + * @param {string} src the shader source + * @param {string} precision The float precision of the shader. Options are 'lowp', 'mediump' or 'highp'. + * + * @return {string} modified shader source + */ +var setPrecision = function(src, precision) +{ + if(src.substring(0, 9) !== 'precision') + { + return 'precision ' + precision + ' float;\n' + src; + } + + return src; +}; + +module.exports = setPrecision; + +},{}],18:[function(require,module,exports){ /** * Bit twiddling hacks for JavaScript. * @@ -1773,13 +1836,13 @@ exports.interleave3 = function(x, y, z) { y = (y | (y<<4)) & 3272356035; y = (y | (y<<2)) & 1227133513; x |= (y << 1); - + z &= 0x3FF; z = (z | (z<<16)) & 4278190335; z = (z | (z<<8)) & 251719695; z = (z | (z<<4)) & 3272356035; z = (z | (z<<2)) & 1227133513; - + return x | (z << 2); } @@ -1800,7 +1863,7 @@ exports.nextCombination = function(v) { } -},{}],18:[function(require,module,exports){ +},{}],19:[function(require,module,exports){ 'use strict'; module.exports = earcut; @@ -2446,7 +2509,7 @@ earcut.flatten = function (data) { return result; }; -},{}],19:[function(require,module,exports){ +},{}],20:[function(require,module,exports){ 'use strict'; var has = Object.prototype.hasOwnProperty @@ -2759,7 +2822,7 @@ if ('undefined' !== typeof module) { module.exports = EventEmitter; } -},{}],20:[function(require,module,exports){ +},{}],21:[function(require,module,exports){ /** * isMobile.js v0.4.0 * @@ -2898,7 +2961,174 @@ if ('undefined' !== typeof module) { })(this); -},{}],21:[function(require,module,exports){ +},{}],22:[function(require,module,exports){ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +var MiniSignalBinding = (function () { + function MiniSignalBinding(fn, once, thisArg) { + if (once === undefined) once = false; + + _classCallCheck(this, MiniSignalBinding); + + this._fn = fn; + this._once = once; + this._thisArg = thisArg; + this._next = this._prev = this._owner = null; + } + + _createClass(MiniSignalBinding, [{ + key: 'detach', + value: function detach() { + if (this._owner === null) return false; + this._owner.detach(this); + return true; + } + }]); + + return MiniSignalBinding; +})(); + +function _addMiniSignalBinding(self, node) { + if (!self._head) { + self._head = node; + self._tail = node; + } else { + self._tail._next = node; + node._prev = self._tail; + self._tail = node; + } + + node._owner = self; + + return node; +} + +var MiniSignal = (function () { + function MiniSignal() { + _classCallCheck(this, MiniSignal); + + this._head = this._tail = undefined; + } + + _createClass(MiniSignal, [{ + key: 'handlers', + value: function handlers() { + var exists = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0]; + + var node = this._head; + + if (exists) return !!node; + + var ee = []; + + while (node) { + ee.push(node); + node = node._next; + } + + return ee; + } + }, { + key: 'has', + value: function has(node) { + if (!(node instanceof MiniSignalBinding)) { + throw new Error('MiniSignal#has(): First arg must be a MiniSignalBinding object.'); + } + + return node._owner === this; + } + }, { + key: 'dispatch', + value: function dispatch() { + var node = this._head; + + if (!node) return false; + + while (node) { + if (node._once) this.detach(node); + node._fn.apply(node._thisArg, arguments); + node = node._next; + } + + return true; + } + }, { + key: 'add', + value: function add(fn) { + var thisArg = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1]; + + if (typeof fn !== 'function') { + throw new Error('MiniSignal#add(): First arg must be a Function.'); + } + return _addMiniSignalBinding(this, new MiniSignalBinding(fn, false, thisArg)); + } + }, { + key: 'once', + value: function once(fn) { + var thisArg = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1]; + + if (typeof fn !== 'function') { + throw new Error('MiniSignal#once(): First arg must be a Function.'); + } + return _addMiniSignalBinding(this, new MiniSignalBinding(fn, true, thisArg)); + } + }, { + key: 'detach', + value: function detach(node) { + if (!(node instanceof MiniSignalBinding)) { + throw new Error('MiniSignal#detach(): First arg must be a MiniSignalBinding object.'); + } + if (node._owner !== this) return this; + + if (node._prev) node._prev._next = node._next; + if (node._next) node._next._prev = node._prev; + + if (node === this._head) { + this._head = node._next; + if (node._next === null) { + this._tail = null; + } + } else if (node === this._tail) { + this._tail = node._prev; + this._tail._next = null; + } + + node._owner = null; + return this; + } + }, { + key: 'detachAll', + value: function detachAll() { + var node = this._head; + if (!node) return this; + + this._head = this._tail = null; + + while (node) { + node._owner = null; + node = node._next; + } + return this; + } + }]); + + return MiniSignal; +})(); + +MiniSignal.MiniSignalBinding = MiniSignalBinding; + +exports['default'] = MiniSignal; +module.exports = exports['default']; + +},{}],23:[function(require,module,exports){ 'use strict'; /* eslint-disable no-unused-vars */ var hasOwnProperty = Object.prototype.hasOwnProperty; @@ -2983,7 +3213,7 @@ module.exports = shouldUseNative() ? Object.assign : function (target, source) { return to; }; -},{}],22:[function(require,module,exports){ +},{}],24:[function(require,module,exports){ 'use strict' module.exports = function parseURI (str, opts) { @@ -3015,7 +3245,7 @@ module.exports = function parseURI (str, opts) { return uri } -},{}],23:[function(require,module,exports){ +},{}],25:[function(require,module,exports){ (function (process){ // Copyright Joyent, Inc. and other Node contributors. // @@ -3244,7 +3474,7 @@ var substr = 'ab'.substr(-1) === 'b' }).call(this,require('_process')) -},{"_process":24}],24:[function(require,module,exports){ +},{"_process":26}],26:[function(require,module,exports){ // shim for using process in browser var process = module.exports = {}; @@ -3256,20 +3486,30 @@ var process = module.exports = {}; var cachedSetTimeout; var cachedClearTimeout; +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} (function () { try { - cachedSetTimeout = setTimeout; - } catch (e) { - cachedSetTimeout = function () { - throw new Error('setTimeout is not defined'); + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; } + } catch (e) { + cachedSetTimeout = defaultSetTimout; } try { - cachedClearTimeout = clearTimeout; - } catch (e) { - cachedClearTimeout = function () { - throw new Error('clearTimeout is not defined'); + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; } } ()) function runTimeout(fun) { @@ -3277,6 +3517,11 @@ function runTimeout(fun) { //normal enviroments in sane situations return setTimeout(fun, 0); } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedSetTimeout(fun, 0); @@ -3297,6 +3542,11 @@ function runClearTimeout(marker) { //normal enviroments in sane situations return clearTimeout(marker); } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedClearTimeout(marker); @@ -3406,7 +3656,7 @@ process.chdir = function (dir) { }; process.umask = function() { return 0; }; -},{}],25:[function(require,module,exports){ +},{}],27:[function(require,module,exports){ (function (global){ /*! https://mths.be/punycode v1.4.1 by @mathias */ ;(function(root) { @@ -3944,186 +4194,7 @@ process.umask = function() { return 0; }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],26:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -'use strict'; - -// If obj.hasOwnProperty has been overridden, then calling -// obj.hasOwnProperty(prop) will break. -// See: https://github.com/joyent/node/issues/1707 -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} - -module.exports = function(qs, sep, eq, options) { - sep = sep || '&'; - eq = eq || '='; - var obj = {}; - - if (typeof qs !== 'string' || qs.length === 0) { - return obj; - } - - var regexp = /\+/g; - qs = qs.split(sep); - - var maxKeys = 1000; - if (options && typeof options.maxKeys === 'number') { - maxKeys = options.maxKeys; - } - - var len = qs.length; - // maxKeys <= 0 means that we should not limit keys count - if (maxKeys > 0 && len > maxKeys) { - len = maxKeys; - } - - for (var i = 0; i < len; ++i) { - var x = qs[i].replace(regexp, '%20'), - idx = x.indexOf(eq), - kstr, vstr, k, v; - - if (idx >= 0) { - kstr = x.substr(0, idx); - vstr = x.substr(idx + 1); - } else { - kstr = x; - vstr = ''; - } - - k = decodeURIComponent(kstr); - v = decodeURIComponent(vstr); - - if (!hasOwnProperty(obj, k)) { - obj[k] = v; - } else if (isArray(obj[k])) { - obj[k].push(v); - } else { - obj[k] = [obj[k], v]; - } - } - - return obj; -}; - -var isArray = Array.isArray || function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]'; -}; - -},{}],27:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -'use strict'; - -var stringifyPrimitive = function(v) { - switch (typeof v) { - case 'string': - return v; - - case 'boolean': - return v ? 'true' : 'false'; - - case 'number': - return isFinite(v) ? v : ''; - - default: - return ''; - } -}; - -module.exports = function(obj, sep, eq, name) { - sep = sep || '&'; - eq = eq || '='; - if (obj === null) { - obj = undefined; - } - - if (typeof obj === 'object') { - return map(objectKeys(obj), function(k) { - var ks = encodeURIComponent(stringifyPrimitive(k)) + eq; - if (isArray(obj[k])) { - return map(obj[k], function(v) { - return ks + encodeURIComponent(stringifyPrimitive(v)); - }).join(sep); - } else { - return ks + encodeURIComponent(stringifyPrimitive(obj[k])); - } - }).join(sep); - - } - - if (!name) return ''; - return encodeURIComponent(stringifyPrimitive(name)) + eq + - encodeURIComponent(stringifyPrimitive(obj)); -}; - -var isArray = Array.isArray || function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]'; -}; - -function map (xs, f) { - if (xs.map) return xs.map(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - res.push(f(xs[i], i)); - } - return res; -} - -var objectKeys = Object.keys || function (obj) { - var res = []; - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key); - } - return res; -}; - },{}],28:[function(require,module,exports){ -'use strict'; - -exports.decode = exports.parse = require('./decode'); -exports.encode = exports.stringify = require('./encode'); - -},{"./decode":26,"./encode":27}],29:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -4147,2025 +4218,1822 @@ exports.encode = exports.stringify = require('./encode'); 'use strict'; -var punycode = require('punycode'); -var util = require('./util'); - -exports.parse = urlParse; -exports.resolve = urlResolve; -exports.resolveObject = urlResolveObject; -exports.format = urlFormat; - -exports.Url = Url; - -function Url() { - this.protocol = null; - this.slashes = null; - this.auth = null; - this.host = null; - this.port = null; - this.hostname = null; - this.hash = null; - this.search = null; - this.query = null; - this.pathname = null; - this.path = null; - this.href = null; +// If obj.hasOwnProperty has been overridden, then calling +// obj.hasOwnProperty(prop) will break. +// See: https://github.com/joyent/node/issues/1707 +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); } -// Reference: RFC 3986, RFC 1808, RFC 2396 - -// define these here so at least they only have to be -// compiled once on the first module load. -var protocolPattern = /^([a-z0-9.+-]+:)/i, - portPattern = /:[0-9]*$/, - - // Special case for a simple path URL - simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/, - - // RFC 2396: characters reserved for delimiting URLs. - // We actually just auto-escape these. - delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'], - - // RFC 2396: characters not allowed for various reasons. - unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims), - - // Allowed by RFCs, but cause of XSS attacks. Always escape these. - autoEscape = ['\''].concat(unwise), - // Characters that are never ever allowed in a hostname. - // Note that any invalid chars are also handled, but these - // are the ones that are *expected* to be seen, so we fast-path - // them. - nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape), - hostEndingChars = ['/', '?', '#'], - hostnameMaxLen = 255, - hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/, - hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/, - // protocols that can allow "unsafe" and "unwise" chars. - unsafeProtocol = { - 'javascript': true, - 'javascript:': true - }, - // protocols that never have a hostname. - hostlessProtocol = { - 'javascript': true, - 'javascript:': true - }, - // protocols that always contain a // bit. - slashedProtocol = { - 'http': true, - 'https': true, - 'ftp': true, - 'gopher': true, - 'file': true, - 'http:': true, - 'https:': true, - 'ftp:': true, - 'gopher:': true, - 'file:': true - }, - querystring = require('querystring'); - -function urlParse(url, parseQueryString, slashesDenoteHost) { - if (url && util.isObject(url) && url instanceof Url) return url; - - var u = new Url; - u.parse(url, parseQueryString, slashesDenoteHost); - return u; -} +module.exports = function(qs, sep, eq, options) { + sep = sep || '&'; + eq = eq || '='; + var obj = {}; -Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) { - if (!util.isString(url)) { - throw new TypeError("Parameter 'url' must be a string, not " + typeof url); + if (typeof qs !== 'string' || qs.length === 0) { + return obj; } - // Copy chrome, IE, opera backslash-handling behavior. - // Back slashes before the query string get converted to forward slashes - // See: https://code.google.com/p/chromium/issues/detail?id=25916 - var queryIndex = url.indexOf('?'), - splitter = - (queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#', - uSplit = url.split(splitter), - slashRegex = /\\/g; - uSplit[0] = uSplit[0].replace(slashRegex, '/'); - url = uSplit.join(splitter); - - var rest = url; - - // trim before proceeding. - // This is to support parse stuff like " http://foo.com \n" - rest = rest.trim(); - - if (!slashesDenoteHost && url.split('#').length === 1) { - // Try fast path regexp - var simplePath = simplePathPattern.exec(rest); - if (simplePath) { - this.path = rest; - this.href = rest; - this.pathname = simplePath[1]; - if (simplePath[2]) { - this.search = simplePath[2]; - if (parseQueryString) { - this.query = querystring.parse(this.search.substr(1)); - } else { - this.query = this.search.substr(1); - } - } else if (parseQueryString) { - this.search = ''; - this.query = {}; - } - return this; - } - } + var regexp = /\+/g; + qs = qs.split(sep); - var proto = protocolPattern.exec(rest); - if (proto) { - proto = proto[0]; - var lowerProto = proto.toLowerCase(); - this.protocol = lowerProto; - rest = rest.substr(proto.length); + var maxKeys = 1000; + if (options && typeof options.maxKeys === 'number') { + maxKeys = options.maxKeys; } - // figure out if it's got a host - // user@server is *always* interpreted as a hostname, and url - // resolution will treat //foo/bar as host=foo,path=bar because that's - // how the browser resolves relative URLs. - if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) { - var slashes = rest.substr(0, 2) === '//'; - if (slashes && !(proto && hostlessProtocol[proto])) { - rest = rest.substr(2); - this.slashes = true; - } + var len = qs.length; + // maxKeys <= 0 means that we should not limit keys count + if (maxKeys > 0 && len > maxKeys) { + len = maxKeys; } - if (!hostlessProtocol[proto] && - (slashes || (proto && !slashedProtocol[proto]))) { - - // there's a hostname. - // the first instance of /, ?, ;, or # ends the host. - // - // If there is an @ in the hostname, then non-host chars *are* allowed - // to the left of the last @ sign, unless some host-ending character - // comes *before* the @-sign. - // URLs are obnoxious. - // - // ex: - // http://a@b@c/ => user:a@b host:c - // http://a@b?@c => user:a host:c path:/?@c - - // v0.12 TODO(isaacs): This is not quite how Chrome does things. - // Review our test case against browsers more comprehensively. - - // find the first instance of any hostEndingChars - var hostEnd = -1; - for (var i = 0; i < hostEndingChars.length; i++) { - var hec = rest.indexOf(hostEndingChars[i]); - if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) - hostEnd = hec; - } + for (var i = 0; i < len; ++i) { + var x = qs[i].replace(regexp, '%20'), + idx = x.indexOf(eq), + kstr, vstr, k, v; - // at this point, either we have an explicit point where the - // auth portion cannot go past, or the last @ char is the decider. - var auth, atSign; - if (hostEnd === -1) { - // atSign can be anywhere. - atSign = rest.lastIndexOf('@'); + if (idx >= 0) { + kstr = x.substr(0, idx); + vstr = x.substr(idx + 1); } else { - // atSign must be in auth portion. - // http://a@b/c@d => host:b auth:a path:/c@d - atSign = rest.lastIndexOf('@', hostEnd); - } - - // Now we have a portion which is definitely the auth. - // Pull that off. - if (atSign !== -1) { - auth = rest.slice(0, atSign); - rest = rest.slice(atSign + 1); - this.auth = decodeURIComponent(auth); - } - - // the host is the remaining to the left of the first non-host char - hostEnd = -1; - for (var i = 0; i < nonHostChars.length; i++) { - var hec = rest.indexOf(nonHostChars[i]); - if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) - hostEnd = hec; + kstr = x; + vstr = ''; } - // if we still have not hit it, then the entire thing is a host. - if (hostEnd === -1) - hostEnd = rest.length; - this.host = rest.slice(0, hostEnd); - rest = rest.slice(hostEnd); - - // pull out port. - this.parseHost(); - - // we've indicated that there is a hostname, - // so even if it's empty, it has to be present. - this.hostname = this.hostname || ''; - - // if hostname begins with [ and ends with ] - // assume that it's an IPv6 address. - var ipv6Hostname = this.hostname[0] === '[' && - this.hostname[this.hostname.length - 1] === ']'; - - // validate a little. - if (!ipv6Hostname) { - var hostparts = this.hostname.split(/\./); - for (var i = 0, l = hostparts.length; i < l; i++) { - var part = hostparts[i]; - if (!part) continue; - if (!part.match(hostnamePartPattern)) { - var newpart = ''; - for (var j = 0, k = part.length; j < k; j++) { - if (part.charCodeAt(j) > 127) { - // we replace non-ASCII char with a temporary placeholder - // we need this to make sure size of hostname is not - // broken by replacing non-ASCII by nothing - newpart += 'x'; - } else { - newpart += part[j]; - } - } - // we test again with ASCII char only - if (!newpart.match(hostnamePartPattern)) { - var validParts = hostparts.slice(0, i); - var notHost = hostparts.slice(i + 1); - var bit = part.match(hostnamePartStart); - if (bit) { - validParts.push(bit[1]); - notHost.unshift(bit[2]); - } - if (notHost.length) { - rest = '/' + notHost.join('.') + rest; - } - this.hostname = validParts.join('.'); - break; - } - } - } - } + k = decodeURIComponent(kstr); + v = decodeURIComponent(vstr); - if (this.hostname.length > hostnameMaxLen) { - this.hostname = ''; + if (!hasOwnProperty(obj, k)) { + obj[k] = v; + } else if (isArray(obj[k])) { + obj[k].push(v); } else { - // hostnames are always lower case. - this.hostname = this.hostname.toLowerCase(); - } - - if (!ipv6Hostname) { - // IDNA Support: Returns a punycoded representation of "domain". - // It only converts parts of the domain name that - // have non-ASCII characters, i.e. it doesn't matter if - // you call it with a domain that already is ASCII-only. - this.hostname = punycode.toASCII(this.hostname); - } - - var p = this.port ? ':' + this.port : ''; - var h = this.hostname || ''; - this.host = h + p; - this.href += this.host; - - // strip [ and ] from the hostname - // the host field still retains them, though - if (ipv6Hostname) { - this.hostname = this.hostname.substr(1, this.hostname.length - 2); - if (rest[0] !== '/') { - rest = '/' + rest; - } - } - } - - // now rest is set to the post-host stuff. - // chop off any delim chars. - if (!unsafeProtocol[lowerProto]) { - - // First, make 100% sure that any "autoEscape" chars get - // escaped, even if encodeURIComponent doesn't think they - // need to be. - for (var i = 0, l = autoEscape.length; i < l; i++) { - var ae = autoEscape[i]; - if (rest.indexOf(ae) === -1) - continue; - var esc = encodeURIComponent(ae); - if (esc === ae) { - esc = escape(ae); - } - rest = rest.split(ae).join(esc); - } - } - - - // chop off from the tail first. - var hash = rest.indexOf('#'); - if (hash !== -1) { - // got a fragment string. - this.hash = rest.substr(hash); - rest = rest.slice(0, hash); - } - var qm = rest.indexOf('?'); - if (qm !== -1) { - this.search = rest.substr(qm); - this.query = rest.substr(qm + 1); - if (parseQueryString) { - this.query = querystring.parse(this.query); - } - rest = rest.slice(0, qm); - } else if (parseQueryString) { - // no query string, but parseQueryString still requested - this.search = ''; - this.query = {}; - } - if (rest) this.pathname = rest; - if (slashedProtocol[lowerProto] && - this.hostname && !this.pathname) { - this.pathname = '/'; - } - - //to support http.request - if (this.pathname || this.search) { - var p = this.pathname || ''; - var s = this.search || ''; - this.path = p + s; - } - - // finally, reconstruct the href based on what has been validated. - this.href = this.format(); - return this; -}; - -// format a parsed object into a url string -function urlFormat(obj) { - // ensure it's an object, and not a string url. - // If it's an obj, this is a no-op. - // this way, you can call url_format() on strings - // to clean up potentially wonky urls. - if (util.isString(obj)) obj = urlParse(obj); - if (!(obj instanceof Url)) return Url.prototype.format.call(obj); - return obj.format(); -} - -Url.prototype.format = function() { - var auth = this.auth || ''; - if (auth) { - auth = encodeURIComponent(auth); - auth = auth.replace(/%3A/i, ':'); - auth += '@'; - } - - var protocol = this.protocol || '', - pathname = this.pathname || '', - hash = this.hash || '', - host = false, - query = ''; - - if (this.host) { - host = auth + this.host; - } else if (this.hostname) { - host = auth + (this.hostname.indexOf(':') === -1 ? - this.hostname : - '[' + this.hostname + ']'); - if (this.port) { - host += ':' + this.port; + obj[k] = [obj[k], v]; } } - if (this.query && - util.isObject(this.query) && - Object.keys(this.query).length) { - query = querystring.stringify(this.query); - } - - var search = this.search || (query && ('?' + query)) || ''; - - if (protocol && protocol.substr(-1) !== ':') protocol += ':'; - - // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. - // unless they had them to begin with. - if (this.slashes || - (!protocol || slashedProtocol[protocol]) && host !== false) { - host = '//' + (host || ''); - if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname; - } else if (!host) { - host = ''; - } - - if (hash && hash.charAt(0) !== '#') hash = '#' + hash; - if (search && search.charAt(0) !== '?') search = '?' + search; - - pathname = pathname.replace(/[?#]/g, function(match) { - return encodeURIComponent(match); - }); - search = search.replace('#', '%23'); - - return protocol + host + pathname + search + hash; + return obj; }; -function urlResolve(source, relative) { - return urlParse(source, false, true).resolve(relative); -} - -Url.prototype.resolve = function(relative) { - return this.resolveObject(urlParse(relative, false, true)).format(); +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; }; -function urlResolveObject(source, relative) { - if (!source) return relative; - return urlParse(source, false, true).resolveObject(relative); -} - -Url.prototype.resolveObject = function(relative) { - if (util.isString(relative)) { - var rel = new Url(); - rel.parse(relative, false, true); - relative = rel; - } - - var result = new Url(); - var tkeys = Object.keys(this); - for (var tk = 0; tk < tkeys.length; tk++) { - var tkey = tkeys[tk]; - result[tkey] = this[tkey]; - } - - // hash is always overridden, no matter what. - // even href="" will remove it. - result.hash = relative.hash; - - // if the relative url is empty, then there's nothing left to do here. - if (relative.href === '') { - result.href = result.format(); - return result; - } +},{}],29:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. - // hrefs like //foo/bar always cut to the protocol. - if (relative.slashes && !relative.protocol) { - // take everything except the protocol from relative - var rkeys = Object.keys(relative); - for (var rk = 0; rk < rkeys.length; rk++) { - var rkey = rkeys[rk]; - if (rkey !== 'protocol') - result[rkey] = relative[rkey]; - } +'use strict'; - //urlParse appends trailing / to urls like http://www.example.com - if (slashedProtocol[result.protocol] && - result.hostname && !result.pathname) { - result.path = result.pathname = '/'; - } +var stringifyPrimitive = function(v) { + switch (typeof v) { + case 'string': + return v; - result.href = result.format(); - return result; - } + case 'boolean': + return v ? 'true' : 'false'; - if (relative.protocol && relative.protocol !== result.protocol) { - // if it's a known url protocol, then changing - // the protocol does weird things - // first, if it's not file:, then we MUST have a host, - // and if there was a path - // to begin with, then we MUST have a path. - // if it is file:, then the host is dropped, - // because that's known to be hostless. - // anything else is assumed to be absolute. - if (!slashedProtocol[relative.protocol]) { - var keys = Object.keys(relative); - for (var v = 0; v < keys.length; v++) { - var k = keys[v]; - result[k] = relative[k]; - } - result.href = result.format(); - return result; - } + case 'number': + return isFinite(v) ? v : ''; - result.protocol = relative.protocol; - if (!relative.host && !hostlessProtocol[relative.protocol]) { - var relPath = (relative.pathname || '').split('/'); - while (relPath.length && !(relative.host = relPath.shift())); - if (!relative.host) relative.host = ''; - if (!relative.hostname) relative.hostname = ''; - if (relPath[0] !== '') relPath.unshift(''); - if (relPath.length < 2) relPath.unshift(''); - result.pathname = relPath.join('/'); - } else { - result.pathname = relative.pathname; - } - result.search = relative.search; - result.query = relative.query; - result.host = relative.host || ''; - result.auth = relative.auth; - result.hostname = relative.hostname || relative.host; - result.port = relative.port; - // to support http.request - if (result.pathname || result.search) { - var p = result.pathname || ''; - var s = result.search || ''; - result.path = p + s; - } - result.slashes = result.slashes || relative.slashes; - result.href = result.format(); - return result; + default: + return ''; } +}; - var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'), - isRelAbs = ( - relative.host || - relative.pathname && relative.pathname.charAt(0) === '/' - ), - mustEndAbs = (isRelAbs || isSourceAbs || - (result.host && relative.pathname)), - removeAllDots = mustEndAbs, - srcPath = result.pathname && result.pathname.split('/') || [], - relPath = relative.pathname && relative.pathname.split('/') || [], - psychotic = result.protocol && !slashedProtocol[result.protocol]; - - // if the url is a non-slashed url, then relative - // links like ../.. should be able - // to crawl up to the hostname, as well. This is strange. - // result.protocol has already been set by now. - // Later on, put the first path part into the host field. - if (psychotic) { - result.hostname = ''; - result.port = null; - if (result.host) { - if (srcPath[0] === '') srcPath[0] = result.host; - else srcPath.unshift(result.host); - } - result.host = ''; - if (relative.protocol) { - relative.hostname = null; - relative.port = null; - if (relative.host) { - if (relPath[0] === '') relPath[0] = relative.host; - else relPath.unshift(relative.host); - } - relative.host = null; - } - mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === ''); +module.exports = function(obj, sep, eq, name) { + sep = sep || '&'; + eq = eq || '='; + if (obj === null) { + obj = undefined; } - if (isRelAbs) { - // it's absolute. - result.host = (relative.host || relative.host === '') ? - relative.host : result.host; - result.hostname = (relative.hostname || relative.hostname === '') ? - relative.hostname : result.hostname; - result.search = relative.search; - result.query = relative.query; - srcPath = relPath; - // fall through to the dot-handling below. - } else if (relPath.length) { - // it's relative - // throw away the existing file, and take the new path instead. - if (!srcPath) srcPath = []; - srcPath.pop(); - srcPath = srcPath.concat(relPath); - result.search = relative.search; - result.query = relative.query; - } else if (!util.isNullOrUndefined(relative.search)) { - // just pull out the search. - // like href='?foo'. - // Put this after the other two cases because it simplifies the booleans - if (psychotic) { - result.hostname = result.host = srcPath.shift(); - //occationaly the auth can get stuck only in host - //this especially happens in cases like - //url.resolveObject('mailto:local1@domain1', 'local2@domain2') - var authInHost = result.host && result.host.indexOf('@') > 0 ? - result.host.split('@') : false; - if (authInHost) { - result.auth = authInHost.shift(); - result.host = result.hostname = authInHost.shift(); + if (typeof obj === 'object') { + return map(objectKeys(obj), function(k) { + var ks = encodeURIComponent(stringifyPrimitive(k)) + eq; + if (isArray(obj[k])) { + return map(obj[k], function(v) { + return ks + encodeURIComponent(stringifyPrimitive(v)); + }).join(sep); + } else { + return ks + encodeURIComponent(stringifyPrimitive(obj[k])); } - } - result.search = relative.search; - result.query = relative.query; - //to support http.request - if (!util.isNull(result.pathname) || !util.isNull(result.search)) { - result.path = (result.pathname ? result.pathname : '') + - (result.search ? result.search : ''); - } - result.href = result.format(); - return result; - } + }).join(sep); - if (!srcPath.length) { - // no path at all. easy. - // we've already handled the other stuff above. - result.pathname = null; - //to support http.request - if (result.search) { - result.path = '/' + result.search; - } else { - result.path = null; - } - result.href = result.format(); - return result; } - // if a url ENDs in . or .., then it must get a trailing slash. - // however, if it ends in anything else non-slashy, - // then it must NOT get a trailing slash. - var last = srcPath.slice(-1)[0]; - var hasTrailingSlash = ( - (result.host || relative.host || srcPath.length > 1) && - (last === '.' || last === '..') || last === ''); + if (!name) return ''; + return encodeURIComponent(stringifyPrimitive(name)) + eq + + encodeURIComponent(stringifyPrimitive(obj)); +}; - // strip single dots, resolve double dots to parent dir - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = srcPath.length; i >= 0; i--) { - last = srcPath[i]; - if (last === '.') { - srcPath.splice(i, 1); - } else if (last === '..') { - srcPath.splice(i, 1); - up++; - } else if (up) { - srcPath.splice(i, 1); - up--; - } - } +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; - // if the path is allowed to go above the root, restore leading ..s - if (!mustEndAbs && !removeAllDots) { - for (; up--; up) { - srcPath.unshift('..'); - } +function map (xs, f) { + if (xs.map) return xs.map(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + res.push(f(xs[i], i)); } + return res; +} - if (mustEndAbs && srcPath[0] !== '' && - (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { - srcPath.unshift(''); +var objectKeys = Object.keys || function (obj) { + var res = []; + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key); } + return res; +}; - if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) { - srcPath.push(''); - } +},{}],30:[function(require,module,exports){ +'use strict'; - var isAbsolute = srcPath[0] === '' || - (srcPath[0] && srcPath[0].charAt(0) === '/'); +exports.decode = exports.parse = require('./decode'); +exports.encode = exports.stringify = require('./encode'); - // put the host back - if (psychotic) { - result.hostname = result.host = isAbsolute ? '' : - srcPath.length ? srcPath.shift() : ''; - //occationaly the auth can get stuck only in host - //this especially happens in cases like - //url.resolveObject('mailto:local1@domain1', 'local2@domain2') - var authInHost = result.host && result.host.indexOf('@') > 0 ? - result.host.split('@') : false; - if (authInHost) { - result.auth = authInHost.shift(); - result.host = result.hostname = authInHost.shift(); - } - } +},{"./decode":28,"./encode":29}],31:[function(require,module,exports){ +'use strict' - mustEndAbs = mustEndAbs || (result.host && srcPath.length); +/** + * Remove a range of items from an array + * + * @function removeItems + * @param {Array<*>} arr The target array + * @param {number} startIdx The index to begin removing from (inclusive) + * @param {number} removeCount How many items to remove + */ +module.exports = function removeItems(arr, startIdx, removeCount) +{ + var i, length = arr.length - if (mustEndAbs && !isAbsolute) { - srcPath.unshift(''); + if (startIdx >= length || removeCount === 0) { + return } - if (!srcPath.length) { - result.pathname = null; - result.path = null; - } else { - result.pathname = srcPath.join('/'); - } + removeCount = (startIdx + removeCount > length ? length - startIdx : removeCount) - //to support request.http - if (!util.isNull(result.pathname) || !util.isNull(result.search)) { - result.path = (result.pathname ? result.pathname : '') + - (result.search ? result.search : ''); - } - result.auth = relative.auth || result.auth; - result.slashes = result.slashes || relative.slashes; - result.href = result.format(); - return result; -}; + var len = length - removeCount -Url.prototype.parseHost = function() { - var host = this.host; - var port = portPattern.exec(host); - if (port) { - port = port[0]; - if (port !== ':') { - this.port = port.substr(1); - } - host = host.substr(0, host.length - port.length); + for (i = startIdx; i < len; ++i) { + arr[i] = arr[i + removeCount] } - if (host) this.hostname = host; -}; -},{"./util":30,"punycode":25,"querystring":28}],30:[function(require,module,exports){ + arr.length = len +} + +},{}],32:[function(require,module,exports){ 'use strict'; -module.exports = { - isString: function(arg) { - return typeof(arg) === 'string'; - }, - isObject: function(arg) { - return typeof(arg) === 'object' && arg !== null; - }, - isNull: function(arg) { - return arg === null; - }, - isNullOrUndefined: function(arg) { - return arg == null; - } -}; +exports.__esModule = true; -},{}],31:[function(require,module,exports){ -'use strict'; +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _miniSignals = require('mini-signals'); + +var _miniSignals2 = _interopRequireDefault(_miniSignals); + +var _parseUri = require('parse-uri'); + +var _parseUri2 = _interopRequireDefault(_parseUri); + +var _async = require('./async'); + +var async = _interopRequireWildcard(_async); + +var _Resource = require('./Resource'); + +var _Resource2 = _interopRequireDefault(_Resource); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -var parseUri = require('parse-uri'); -var async = require('./async'); -var Resource = require('./Resource'); -var EventEmitter = require('eventemitter3'); +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // some constants -var DEFAULT_CONCURRENCY = 10; var MAX_PROGRESS = 100; +var rgxExtractUrlHash = /(#[\w-]+)?$/; /** * Manages the state and loading of multiple resources to load. * * @class - * @param {string} [baseUrl=''] - The base url for all resources loaded by this loader. - * @param {number} [concurrency=10] - The number of resources to load concurrently. */ -function Loader(baseUrl, concurrency) { - EventEmitter.call(this); - - concurrency = concurrency || DEFAULT_CONCURRENCY; +var Loader = function () { /** - * The base url for all resources loaded by this loader. - * - * @member {string} + * @param {string} [baseUrl=''] - The base url for all resources loaded by this loader. + * @param {number} [concurrency=10] - The number of resources to load concurrently. */ - this.baseUrl = baseUrl || ''; + function Loader() { + var _this = this; + + var baseUrl = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; + var concurrency = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10; + + _classCallCheck(this, Loader); + + /** + * The base url for all resources loaded by this loader. + * + * @member {string} + */ + this.baseUrl = baseUrl; + + /** + * The progress percent of the loader going through the queue. + * + * @member {number} + */ + this.progress = 0; + + /** + * Loading state of the loader, true if it is currently loading resources. + * + * @member {boolean} + */ + this.loading = false; + + /** + * A querystring to append to every URL added to the loader. + * + * This should be a valid query string *without* the question-mark (`?`). The loader will + * also *not* escape values for you. Make sure to escape your parameters with + * [`encodeURIComponent`](https://mdn.io/encodeURIComponent) before assigning this property. + * + * @example + * const loader = new Loader(); + * + * loader.defaultQueryString = 'user=me&password=secret'; + * + * // This will request 'image.png?user=me&password=secret' + * loader.add('image.png').load(); + * + * loader.reset(); + * + * // This will request 'image.png?v=1&user=me&password=secret' + * loader.add('iamge.png?v=1').load(); + */ + this.defaultQueryString = ''; + + /** + * The middleware to run before loading each resource. + * + * @member {function[]} + */ + this._beforeMiddleware = []; + + /** + * The middleware to run after loading each resource. + * + * @member {function[]} + */ + this._afterMiddleware = []; + + /** + * The tracks the resources we are currently completing parsing for. + * + * @member {Resource[]} + */ + this._resourcesParsing = []; + + /** + * The `_loadResource` function bound with this object context. + * + * @private + * @member {function} + * @param {Resource} r - The resource to load + * @param {Function} d - The dequeue function + * @return {undefined} + */ + this._boundLoadResource = function (r, d) { + return _this._loadResource(r, d); + }; + + /** + * The resources waiting to be loaded. + * + * @private + * @member {Resource[]} + */ + this._queue = async.queue(this._boundLoadResource, concurrency); + + this._queue.pause(); + + /** + * All the resources for this loader keyed by name. + * + * @member {object} + */ + this.resources = {}; + + /** + * Dispatched once per loaded or errored resource. + * + * The callback looks like {@link Loader.OnProgressSignal}. + * + * @member {Signal} + */ + this.onProgress = new _miniSignals2.default(); + + /** + * Dispatched once per errored resource. + * + * The callback looks like {@link Loader.OnErrorSignal}. + * + * @member {Signal} + */ + this.onError = new _miniSignals2.default(); + + /** + * Dispatched once per loaded resource. + * + * The callback looks like {@link Loader.OnLoadSignal}. + * + * @member {Signal} + */ + this.onLoad = new _miniSignals2.default(); + + /** + * Dispatched when the loader begins to process the queue. + * + * The callback looks like {@link Loader.OnStartSignal}. + * + * @member {Signal} + */ + this.onStart = new _miniSignals2.default(); + + /** + * Dispatched when the queued resources all load. + * + * The callback looks like {@link Loader.OnCompleteSignal}. + * + * @member {Signal} + */ + this.onComplete = new _miniSignals2.default(); + + /** + * When the progress changes the loader and resource are disaptched. + * + * @memberof Loader + * @callback OnProgressSignal + * @param {Loader} loader - The loader the progress is advancing on. + * @param {Resource} resource - The resource that has completed or failed to cause the progress to advance. + */ + + /** + * When an error occurrs the loader and resource are disaptched. + * + * @memberof Loader + * @callback OnErrorSignal + * @param {Loader} loader - The loader the error happened in. + * @param {Resource} resource - The resource that caused the error. + */ + + /** + * When a load completes the loader and resource are disaptched. + * + * @memberof Loader + * @callback OnLoadSignal + * @param {Loader} loader - The loader that laoded the resource. + * @param {Resource} resource - The resource that has completed loading. + */ + + /** + * When the loader starts loading resources it dispatches this callback. + * + * @memberof Loader + * @callback OnStartSignal + * @param {Loader} loader - The loader that has started loading resources. + */ + + /** + * When the loader completes loading resources it dispatches this callback. + * + * @memberof Loader + * @callback OnCompleteSignal + * @param {Loader} loader - The loader that has finished loading resources. + */ + } /** - * The progress percent of the loader going through the queue. + * Adds a resource (or multiple resources) to the loader queue. * - * @member {number} + * This function can take a wide variety of different parameters. The only thing that is always + * required the url to load. All the following will work: + * + * ```js + * loader + * // normal param syntax + * .add('key', 'http://...', function () {}) + * .add('http://...', function () {}) + * .add('http://...') + * + * // object syntax + * .add({ + * name: 'key2', + * url: 'http://...' + * }, function () {}) + * .add({ + * url: 'http://...' + * }, function () {}) + * .add({ + * name: 'key3', + * url: 'http://...' + * onComplete: function () {} + * }) + * .add({ + * url: 'https://...', + * onComplete: function () {}, + * crossOrigin: true + * }) + * + * // you can also pass an array of objects or urls or both + * .add([ + * { name: 'key4', url: 'http://...', onComplete: function () {} }, + * { url: 'http://...', onComplete: function () {} }, + * 'http://...' + * ]) + * + * // and you can use both params and options + * .add('key', 'http://...', { crossOrigin: true }, function () {}) + * .add('http://...', { crossOrigin: true }, function () {}); + * ``` + * + * @param {string} [name] - The name of the resource to load, if not passed the url is used. + * @param {string} [url] - The url for this resource, relative to the baseUrl of this loader. + * @param {object} [options] - The options for the load. + * @param {boolean} [options.crossOrigin] - Is this request cross-origin? Default is to determine automatically. + * @param {Resource.LOAD_TYPE} [options.loadType=Resource.LOAD_TYPE.XHR] - How should this resource be loaded? + * @param {Resource.XHR_RESPONSE_TYPE} [options.xhrType=Resource.XHR_RESPONSE_TYPE.DEFAULT] - How should + * the data being loaded be interpreted when using XHR? + * @param {object} [options.metadata] - Extra configuration for middleware and the Resource object. + * @param {HTMLImageElement|HTMLAudioElement|HTMLVideoElement} [options.metadata.loadElement=null] - The + * element to use for loading, instead of creating one. + * @param {boolean} [options.metadata.skipSource=false] - Skips adding source(s) to the load element. This + * is useful if you want to pass in a `loadElement` that you already added load sources to. + * @param {function} [cb] - Function to call when this specific resource completes loading. + * @return {Loader} Returns itself. */ - this.progress = 0; + + + Loader.prototype.add = function add(name, url, options, cb) { + // special case of an array of objects or urls + if (Array.isArray(name)) { + for (var i = 0; i < name.length; ++i) { + this.add(name[i]); + } + + return this; + } + + // if an object is passed instead of params + if ((typeof name === 'undefined' ? 'undefined' : _typeof(name)) === 'object') { + cb = url || name.callback || name.onComplete; + options = name; + url = name.url; + name = name.name || name.key || name.url; + } + + // case where no name is passed shift all args over by one. + if (typeof url !== 'string') { + cb = options; + options = url; + url = name; + } + + // now that we shifted make sure we have a proper url. + if (typeof url !== 'string') { + throw new Error('No url passed to add resource to loader.'); + } + + // options are optional so people might pass a function and no options + if (typeof options === 'function') { + cb = options; + options = null; + } + + // if loading already you can only add resources that have a parent. + if (this.loading && (!options || !options.parentResource)) { + throw new Error('Cannot add resources while the loader is running.'); + } + + // check if resource already exists. + if (this.resources[name]) { + throw new Error('Resource named "' + name + '" already exists.'); + } + + // add base url if this isn't an absolute url + url = this._prepareUrl(url); + + // create the store the resource + this.resources[name] = new _Resource2.default(name, url, options); + + if (typeof cb === 'function') { + this.resources[name].onAfterMiddleware.once(cb); + } + + // if actively loading, make sure to adjust progress chunks for that parent and its children + if (this.loading) { + var parent = options.parentResource; + var incompleteChildren = []; + + for (var _i = 0; _i < parent.children.length; ++_i) { + if (!parent.children[_i].isComplete) { + incompleteChildren.push(parent.children[_i]); + } + } + + var fullChunk = parent.progressChunk * (incompleteChildren.length + 1); // +1 for parent + var eachChunk = fullChunk / (incompleteChildren.length + 2); // +2 for parent & new child + + parent.children.push(this.resources[name]); + parent.progressChunk = eachChunk; + + for (var _i2 = 0; _i2 < incompleteChildren.length; ++_i2) { + incompleteChildren[_i2].progressChunk = eachChunk; + } + + this.resources[name].progressChunk = eachChunk; + } + + // add the resource to the queue + this._queue.push(this.resources[name]); + + return this; + }; /** - * Loading state of the loader, true if it is currently loading resources. + * Sets up a middleware function that will run *before* the + * resource is loaded. * - * @member {boolean} + * @method before + * @param {function} fn - The middleware function to register. + * @return {Loader} Returns itself. */ - this.loading = false; + + + Loader.prototype.pre = function pre(fn) { + this._beforeMiddleware.push(fn); + + return this; + }; /** - * The percentage of total progress that a single resource represents. + * Sets up a middleware function that will run *after* the + * resource is loaded. * - * @member {number} + * @alias use + * @method after + * @param {function} fn - The middleware function to register. + * @return {Loader} Returns itself. */ - this._progressChunk = 0; + + + Loader.prototype.use = function use(fn) { + this._afterMiddleware.push(fn); + + return this; + }; /** - * The middleware to run before loading each resource. + * Resets the queue of the loader to prepare for a new load. * - * @member {function[]} + * @return {Loader} Returns itself. */ - this._beforeMiddleware = []; + + + Loader.prototype.reset = function reset() { + this.progress = 0; + this.loading = false; + + this._queue.kill(); + this._queue.pause(); + + // abort all resource loads + for (var k in this.resources) { + var res = this.resources[k]; + + if (res._onLoadBinding) { + res._onLoadBinding.detach(); + } + + if (res.isLoading) { + res.abort(); + } + } + + this.resources = {}; + + return this; + }; /** - * The middleware to run after loading each resource. + * Starts loading the queued resources. * - * @member {function[]} + * @param {function} [cb] - Optional callback that will be bound to the `complete` event. + * @return {Loader} Returns itself. */ - this._afterMiddleware = []; + + + Loader.prototype.load = function load(cb) { + // register complete callback if they pass one + if (typeof cb === 'function') { + this.onComplete.once(cb); + } + + // if the queue has already started we are done here + if (this.loading) { + return this; + } + + // distribute progress chunks + var chunk = 100 / this._queue._tasks.length; + + for (var i = 0; i < this._queue._tasks.length; ++i) { + this._queue._tasks[i].data.progressChunk = chunk; + } + + // update loading state + this.loading = true; + + // notify of start + this.onStart.dispatch(this); + + // start loading + this._queue.resume(); + + return this; + }; /** - * The `_loadResource` function bound with this object context. + * Prepares a url for usage based on the configuration of this object * * @private - * @member {function} + * @param {string} url - The url to prepare. + * @return {string} The prepared url. */ - this._boundLoadResource = this._loadResource.bind(this); + + + Loader.prototype._prepareUrl = function _prepareUrl(url) { + var parsedUrl = (0, _parseUri2.default)(url, { strictMode: true }); + var result = void 0; + + // absolute url, just use it as is. + if (parsedUrl.protocol || !parsedUrl.path || url.indexOf('//') === 0) { + result = url; + } + // if baseUrl doesn't end in slash and url doesn't start with slash, then add a slash inbetween + else if (this.baseUrl.length && this.baseUrl.lastIndexOf('/') !== this.baseUrl.length - 1 && url.charAt(0) !== '/') { + result = this.baseUrl + '/' + url; + } else { + result = this.baseUrl + url; + } + + // if we need to add a default querystring, there is a bit more work + if (this.defaultQueryString) { + var hash = rgxExtractUrlHash.exec(result)[0]; + + result = result.substr(0, result.length - hash.length); + + if (result.indexOf('?') !== -1) { + result += '&' + this.defaultQueryString; + } else { + result += '?' + this.defaultQueryString; + } + + result += hash; + } + + return result; + }; /** - * The resource buffer that fills until `load` is called to start loading resources. + * Loads a single resource. * * @private - * @member {Resource[]} + * @param {Resource} resource - The resource to load. + * @param {function} dequeue - The function to call when we need to dequeue this item. */ - this._buffer = []; + + + Loader.prototype._loadResource = function _loadResource(resource, dequeue) { + var _this2 = this; + + resource._dequeue = dequeue; + + // run before middleware + async.eachSeries(this._beforeMiddleware, function (fn, next) { + fn.call(_this2, resource, function () { + // if the before middleware marks the resource as complete, + // break and don't process any more before middleware + next(resource.isComplete ? {} : null); + }); + }, function () { + if (resource.isComplete) { + _this2._onLoad(resource); + } else { + resource._onLoadBinding = resource.onComplete.once(_this2._onLoad, _this2); + resource.load(); + } + }, true); + }; /** - * Used to track load completion. + * Called once each resource has loaded. * * @private - * @member {number} */ - this._numToLoad = 0; + + + Loader.prototype._onComplete = function _onComplete() { + this.loading = false; + + this.onComplete.dispatch(this, this.resources); + }; /** - * The resources waiting to be loaded. + * Called each time a resources is loaded. * * @private - * @member {Resource[]} + * @param {Resource} resource - The resource that was loaded */ - this._queue = async.queue(this._boundLoadResource, concurrency); - /** - * All the resources for this loader keyed by name. - * - * @member {object} - */ - this.resources = {}; - /** - * Emitted once per loaded or errored resource. - * - * @event progress - * @memberof Loader# - */ + Loader.prototype._onLoad = function _onLoad(resource) { + var _this3 = this; - /** - * Emitted once per errored resource. - * - * @event error - * @memberof Loader# - */ + resource._onLoadBinding = null; + + // remove this resource from the async queue, and add it to our list of resources that are being parsed + this._resourcesParsing.push(resource); + resource._dequeue(); + + // run all the after middleware for this resource + async.eachSeries(this._afterMiddleware, function (fn, next) { + fn.call(_this3, resource, next); + }, function () { + resource.onAfterMiddleware.dispatch(resource); + + _this3.progress += resource.progressChunk; + _this3.onProgress.dispatch(_this3, resource); + + if (resource.error) { + _this3.onError.dispatch(resource.error, _this3, resource); + } else { + _this3.onLoad.dispatch(_this3, resource); + } + + _this3._resourcesParsing.splice(_this3._resourcesParsing.indexOf(resource), 1); + + // do completion check + if (_this3._queue.idle() && _this3._resourcesParsing.length === 0) { + _this3.progress = MAX_PROGRESS; + _this3._onComplete(); + } + }, true); + }; + + return Loader; +}(); + +exports.default = Loader; + +},{"./Resource":33,"./async":34,"mini-signals":22,"parse-uri":24}],33:[function(require,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _parseUri = require('parse-uri'); + +var _parseUri2 = _interopRequireDefault(_parseUri); + +var _miniSignals = require('mini-signals'); + +var _miniSignals2 = _interopRequireDefault(_miniSignals); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +// tests is CORS is supported in XHR, if not we need to use XDR +var useXdr = !!(window.XDomainRequest && !('withCredentials' in new XMLHttpRequest())); +var tempAnchor = null; +// some status constants +var STATUS_NONE = 0; +var STATUS_OK = 200; +var STATUS_EMPTY = 204; +var STATUS_IE_BUG_EMPTY = 1223; +var STATUS_TYPE_OK = 2; + +// noop +function _noop() {} /* empty */ + +/** + * Manages the state and loading of a resource and all child resources. + * + * @class + */ + +var Resource = function () { /** - * Emitted once per loaded resource. + * Sets the load type to be used for a specific extension. * - * @event load - * @memberof Loader# + * @static + * @param {string} extname - The extension to set the type for, e.g. "png" or "fnt" + * @param {Resource.LOAD_TYPE} loadType - The load type to set it to. */ + Resource.setExtensionLoadType = function setExtensionLoadType(extname, loadType) { + setExtMap(Resource._loadTypeMap, extname, loadType); + }; /** - * Emitted when the loader begins to process the queue. + * Sets the load type to be used for a specific extension. * - * @event start - * @memberof Loader# + * @static + * @param {string} extname - The extension to set the type for, e.g. "png" or "fnt" + * @param {Resource.XHR_RESPONSE_TYPE} xhrType - The xhr type to set it to. */ + + Resource.setExtensionXhrType = function setExtensionXhrType(extname, xhrType) { + setExtMap(Resource._xhrTypeMap, extname, xhrType); + }; + /** - * Emitted when the queued resources all load. - * - * @event complete - * @memberof Loader# + * @param {string} name - The name of the resource to load. + * @param {string|string[]} url - The url for this resource, for audio/video loads you can pass + * an array of sources. + * @param {object} [options] - The options for the load. + * @param {string|boolean} [options.crossOrigin] - Is this request cross-origin? Default is to + * determine automatically. + * @param {Resource.LOAD_TYPE} [options.loadType=Resource.LOAD_TYPE.XHR] - How should this resource + * be loaded? + * @param {Resource.XHR_RESPONSE_TYPE} [options.xhrType=Resource.XHR_RESPONSE_TYPE.DEFAULT] - How + * should the data being loaded be interpreted when using XHR? + * @param {object} [options.metadata] - Extra configuration for middleware and the Resource object. + * @param {HTMLImageElement|HTMLAudioElement|HTMLVideoElement} [options.metadata.loadElement=null] - The + * element to use for loading, instead of creating one. + * @param {boolean} [options.metadata.skipSource=false] - Skips adding source(s) to the load element. This + * is useful if you want to pass in a `loadElement` that you already added load sources to. */ -} -Loader.prototype = Object.create(EventEmitter.prototype); -Loader.prototype.constructor = Loader; -module.exports = Loader; -/** - * Adds a resource (or multiple resources) to the loader queue. - * - * This function can take a wide variety of different parameters. The only thing that is always - * required the url to load. All the following will work: - * - * ```js - * loader - * // normal param syntax - * .add('key', 'http://...', function () {}) - * .add('http://...', function () {}) - * .add('http://...') - * - * // object syntax - * .add({ - * name: 'key2', - * url: 'http://...' - * }, function () {}) - * .add({ - * url: 'http://...' - * }, function () {}) - * .add({ - * name: 'key3', - * url: 'http://...' - * onComplete: function () {} - * }) - * .add({ - * url: 'https://...', - * onComplete: function () {}, - * crossOrigin: true - * }) - * - * // you can also pass an array of objects or urls or both - * .add([ - * { name: 'key4', url: 'http://...', onComplete: function () {} }, - * { url: 'http://...', onComplete: function () {} }, - * 'http://...' - * ]) - * - * // and you can use both params and options - * .add('key', 'http://...', { crossOrigin: true }, function () {}) - * .add('http://...', { crossOrigin: true }, function () {}); - * ``` - * - * @alias enqueue - * @param {string} [name] - The name of the resource to load, if not passed the url is used. - * @param {string} [url] - The url for this resource, relative to the baseUrl of this loader. - * @param {object} [options] - The options for the load. - * @param {boolean} [options.crossOrigin] - Is this request cross-origin? Default is to determine automatically. - * @param {Resource.XHR_LOAD_TYPE} [options.loadType=Resource.LOAD_TYPE.XHR] - How should this resource be loaded? - * @param {Resource.XHR_RESPONSE_TYPE} [options.xhrType=Resource.XHR_RESPONSE_TYPE.DEFAULT] - How should the data being - * loaded be interpreted when using XHR? - * @param {function} [cb] - Function to call when this specific resource completes loading. - * @return {Loader} Returns itself. - */ -Loader.prototype.add = Loader.prototype.enqueue = function (name, url, options, cb) { - // special case of an array of objects or urls - if (Array.isArray(name)) { - for (var i = 0; i < name.length; ++i) { - this.add(name[i]); + function Resource(name, url, options) { + _classCallCheck(this, Resource); + + if (typeof name !== 'string' || typeof url !== 'string') { + throw new Error('Both name and url are required for constructing a resource.'); } - return this; - } + options = options || {}; - // if an object is passed instead of params - if (typeof name === 'object') { - cb = url || name.callback || name.onComplete; - options = name; - url = name.url; - name = name.name || name.key || name.url; - } + /** + * The state flags of this resource. + * + * @member {number} + */ + this._flags = 0; - // case where no name is passed shift all args over by one. - if (typeof url !== 'string') { - cb = options; - options = url; - url = name; - } + // set data url flag, needs to be set early for some _determineX checks to work. + this._setFlag(Resource.STATUS_FLAGS.DATA_URL, url.indexOf('data:') === 0); - // now that we shifted make sure we have a proper url. - if (typeof url !== 'string') { - throw new Error('No url passed to add resource to loader.'); - } + /** + * The name of this resource. + * + * @member {string} + * @readonly + */ + this.name = name; - // options are optional so people might pass a function and no options - if (typeof options === 'function') { - cb = options; - options = null; - } + /** + * The url used to load this resource. + * + * @member {string} + * @readonly + */ + this.url = url; - // check if resource already exists. - if (this.resources[name]) { - throw new Error('Resource with name "' + name + '" already exists.'); - } + /** + * The extension used to load this resource. + * + * @member {string} + * @readonly + */ + this.extension = this._getExtension(); - // add base url if this isn't an absolute url - url = this._prepareUrl(url); + /** + * The data that was loaded by the resource. + * + * @member {any} + */ + this.data = null; - // create the store the resource - this.resources[name] = new Resource(name, url, options); + /** + * Is this request cross-origin? If unset, determined automatically. + * + * @member {string} + */ + this.crossOrigin = options.crossOrigin === true ? 'anonymous' : options.crossOrigin; - if (typeof cb === 'function') { - this.resources[name].once('afterMiddleware', cb); - } + /** + * The method of loading to use for this resource. + * + * @member {Resource.LOAD_TYPE} + */ + this.loadType = options.loadType || this._determineLoadType(); - this._numToLoad++; + /** + * The type used to load the resource via XHR. If unset, determined automatically. + * + * @member {string} + */ + this.xhrType = options.xhrType; - // if already loading add it to the worker queue - if (this._queue.started) { - this._queue.push(this.resources[name]); - this._progressChunk = (MAX_PROGRESS - this.progress) / (this._queue.length() + this._queue.running()); - } - // otherwise buffer it to be added to the queue later - else { - this._buffer.push(this.resources[name]); - this._progressChunk = MAX_PROGRESS / this._buffer.length; + /** + * Extra info for middleware, and controlling specifics about how the resource loads. + * + * Note that if you pass in a `loadElement`, the Resource class takes ownership of it. + * Meaning it will modify it as it sees fit. + * + * @member {object} + * @property {HTMLImageElement|HTMLAudioElement|HTMLVideoElement} [loadElement=null] - The + * element to use for loading, instead of creating one. + * @property {boolean} [skipSource=false] - Skips adding source(s) to the load element. This + * is useful if you want to pass in a `loadElement` that you already added load sources + * to. + */ + this.metadata = options.metadata || {}; + + /** + * The error that occurred while loading (if any). + * + * @member {Error} + * @readonly + */ + this.error = null; + + /** + * The XHR object that was used to load this resource. This is only set + * when `loadType` is `Resource.LOAD_TYPE.XHR`. + * + * @member {XMLHttpRequest} + * @readonly + */ + this.xhr = null; + + /** + * The child resources this resource owns. + * + * @member {Resource[]} + * @readonly + */ + this.children = []; + + /** + * The resource type. + * + * @member {Resource.TYPE} + * @readonly + */ + this.type = Resource.TYPE.UNKNOWN; + + /** + * The progress chunk owned by this resource. + * + * @member {number} + * @readonly + */ + this.progressChunk = 0; + + /** + * The `dequeue` method that will be used a storage place for the async queue dequeue method + * used privately by the loader. + * + * @private + * @member {function} + */ + this._dequeue = _noop; + + /** + * Used a storage place for the on load binding used privately by the loader. + * + * @private + * @member {function} + */ + this._onLoadBinding = null; + + /** + * The `complete` function bound to this resource's context. + * + * @private + * @member {function} + */ + this._boundComplete = this.complete.bind(this); + + /** + * The `_onError` function bound to this resource's context. + * + * @private + * @member {function} + */ + this._boundOnError = this._onError.bind(this); + + /** + * The `_onProgress` function bound to this resource's context. + * + * @private + * @member {function} + */ + this._boundOnProgress = this._onProgress.bind(this); + + // xhr callbacks + this._boundXhrOnError = this._xhrOnError.bind(this); + this._boundXhrOnAbort = this._xhrOnAbort.bind(this); + this._boundXhrOnLoad = this._xhrOnLoad.bind(this); + this._boundXdrOnTimeout = this._xdrOnTimeout.bind(this); + + /** + * Dispatched when the resource beings to load. + * + * The callback looks like {@link Resource.OnStartSignal}. + * + * @member {Signal} + */ + this.onStart = new _miniSignals2.default(); + + /** + * Dispatched each time progress of this resource load updates. + * Not all resources types and loader systems can support this event + * so sometimes it may not be available. If the resource + * is being loaded on a modern browser, using XHR, and the remote server + * properly sets Content-Length headers, then this will be available. + * + * The callback looks like {@link Resource.OnProgressSignal}. + * + * @member {Signal} + */ + this.onProgress = new _miniSignals2.default(); + + /** + * Dispatched once this resource has loaded, if there was an error it will + * be in the `error` property. + * + * The callback looks like {@link Resource.OnCompleteSignal}. + * + * @member {Signal} + */ + this.onComplete = new _miniSignals2.default(); + + /** + * Dispatched after this resource has had all the *after* middleware run on it. + * + * The callback looks like {@link Resource.OnCompleteSignal}. + * + * @member {Signal} + */ + this.onAfterMiddleware = new _miniSignals2.default(); + + /** + * When the resource starts to load. + * + * @memberof Resource + * @callback OnStartSignal + * @param {Resource} resource - The resource that the event happened on. + */ + + /** + * When the resource reports loading progress. + * + * @memberof Resource + * @callback OnProgressSignal + * @param {Resource} resource - The resource that the event happened on. + * @param {number} percentage - The progress of the load in the range [0, 1]. + */ + + /** + * When the resource finishes loading. + * + * @memberof Resource + * @callback OnCompleteSignal + * @param {Resource} resource - The resource that the event happened on. + */ } - return this; -}; + /** + * Stores whether or not this url is a data url. + * + * @member {boolean} + * @readonly + */ + + + /** + * Marks the resource as complete. + * + */ + Resource.prototype.complete = function complete() { + // TODO: Clean this up in a wrapper or something...gross.... + if (this.data && this.data.removeEventListener) { + this.data.removeEventListener('error', this._boundOnError, false); + this.data.removeEventListener('load', this._boundComplete, false); + this.data.removeEventListener('progress', this._boundOnProgress, false); + this.data.removeEventListener('canplaythrough', this._boundComplete, false); + } -/** - * Sets up a middleware function that will run *before* the - * resource is loaded. - * - * @alias pre - * @method before - * @param {function} fn - The middleware function to register. - * @return {Loader} Returns itself. - */ -Loader.prototype.before = Loader.prototype.pre = function (fn) { - this._beforeMiddleware.push(fn); + if (this.xhr) { + if (this.xhr.removeEventListener) { + this.xhr.removeEventListener('error', this._boundXhrOnError, false); + this.xhr.removeEventListener('abort', this._boundXhrOnAbort, false); + this.xhr.removeEventListener('progress', this._boundOnProgress, false); + this.xhr.removeEventListener('load', this._boundXhrOnLoad, false); + } else { + this.xhr.onerror = null; + this.xhr.ontimeout = null; + this.xhr.onprogress = null; + this.xhr.onload = null; + } + } - return this; -}; + if (this.isComplete) { + throw new Error('Complete called again for an already completed resource.'); + } -/** - * Sets up a middleware function that will run *after* the - * resource is loaded. - * - * @alias use - * @method after - * @param {function} fn - The middleware function to register. - * @return {Loader} Returns itself. - */ -Loader.prototype.after = Loader.prototype.use = function (fn) { - this._afterMiddleware.push(fn); + this._setFlag(Resource.STATUS_FLAGS.COMPLETE, true); + this._setFlag(Resource.STATUS_FLAGS.LOADING, false); - return this; -}; + this.onComplete.dispatch(this); + }; + + /** + * Aborts the loading of this resource, with an optional message. + * + * @param {string} message - The message to use for the error + */ -/** - * Resets the queue of the loader to prepare for a new load. - * - * @return {Loader} Returns itself. - */ -Loader.prototype.reset = function () { - // this.baseUrl = baseUrl || ''; - this.progress = 0; + Resource.prototype.abort = function abort(message) { + // abort can be called multiple times, ignore subsequent calls. + if (this.error) { + return; + } - this.loading = false; + // store error + this.error = new Error(message); - this._progressChunk = 0; + // abort the actual loading + if (this.xhr) { + this.xhr.abort(); + } else if (this.xdr) { + this.xdr.abort(); + } else if (this.data) { + // single source + if (this.data.src) { + this.data.src = Resource.EMPTY_GIF; + } + // multi-source + else { + while (this.data.firstChild) { + this.data.removeChild(this.data.firstChild); + } + } + } - // this._beforeMiddleware.length = 0; - // this._afterMiddleware.length = 0; + // done now. + this.complete(); + }; - this._buffer.length = 0; + /** + * Kicks off loading of this resource. This method is asynchronous. + * + * @param {function} [cb] - Optional callback to call once the resource is loaded. + */ - this._numToLoad = 0; - this._queue.kill(); - this._queue.started = false; + Resource.prototype.load = function load(cb) { + var _this = this; - // abort all resource loads - for (var k in this.resources) { - var res = this.resources[k]; + if (this.isLoading) { + return; + } - res.off('complete', this._onLoad, this); + if (this.isComplete) { + if (cb) { + setTimeout(function () { + return cb(_this); + }, 1); + } - if (res.isLoading) { - res.abort(); + return; + } else if (cb) { + this.onComplete.once(cb); } - } - this.resources = {}; + this._setFlag(Resource.STATUS_FLAGS.LOADING, true); - return this; -}; + this.onStart.dispatch(this); -/** - * Starts loading the queued resources. - * - * @fires start - * @param {function} [cb] - Optional callback that will be bound to the `complete` event. - * @return {Loader} Returns itself. - */ -Loader.prototype.load = function (cb) { - // register complete callback if they pass one - if (typeof cb === 'function') { - this.once('complete', cb); - } + // if unset, determine the value + if (this.crossOrigin === false || typeof this.crossOrigin !== 'string') { + this.crossOrigin = this._determineCrossOrigin(this.url); + } - // if the queue has already started we are done here - if (this._queue.started) { - return this; - } + switch (this.loadType) { + case Resource.LOAD_TYPE.IMAGE: + this.type = Resource.TYPE.IMAGE; + this._loadElement('image'); + break; - // notify of start - this.emit('start', this); + case Resource.LOAD_TYPE.AUDIO: + this.type = Resource.TYPE.AUDIO; + this._loadSourceElement('audio'); + break; - // update loading state - this.loading = true; + case Resource.LOAD_TYPE.VIDEO: + this.type = Resource.TYPE.VIDEO; + this._loadSourceElement('video'); + break; - // start the internal queue - for (var i = 0; i < this._buffer.length; ++i) { - this._queue.push(this._buffer[i]); - } + case Resource.LOAD_TYPE.XHR: + /* falls through */ + default: + if (useXdr && this.crossOrigin) { + this._loadXdr(); + } else { + this._loadXhr(); + } + break; + } + }; - // empty the buffer - this._buffer.length = 0; + /** + * Checks if the flag is set. + * + * @private + * @param {number} flag - The flag to check. + * @return {boolean} True if the flag is set. + */ - return this; -}; -/** - * Prepares a url for usage based on the configuration of this object - * - * @private - * @param {string} url - The url to prepare. - * @return {string} The prepared url. - */ -Loader.prototype._prepareUrl = function (url) { - var parsedUrl = parseUri(url, { strictMode: true }); + Resource.prototype._hasFlag = function _hasFlag(flag) { + return !!(this._flags & flag); + }; - // absolute url, just use it as is. - if (parsedUrl.protocol || !parsedUrl.path || parsedUrl.path.indexOf('//') === 0) { - return url; - } + /** + * (Un)Sets the flag. + * + * @private + * @param {number} flag - The flag to (un)set. + * @param {boolean} value - Whether to set or (un)set the flag. + */ - // if baseUrl doesn't end in slash and url doesn't start with slash, then add a slash inbetween - if (this.baseUrl.length - && this.baseUrl.lastIndexOf('/') !== this.baseUrl.length - 1 - && url.charAt(0) !== '/' - ) { - return this.baseUrl + '/' + url; - } - return this.baseUrl + url; -}; + Resource.prototype._setFlag = function _setFlag(flag, value) { + this._flags = value ? this._flags | flag : this._flags & ~flag; + }; -/** - * Loads a single resource. - * - * @private - * @param {Resource} resource - The resource to load. - * @param {function} dequeue - The function to call when we need to dequeue this item. - */ -Loader.prototype._loadResource = function (resource, dequeue) { - var self = this; + /** + * Loads this resources using an element that has a single source, + * like an HTMLImageElement. + * + * @private + * @param {string} type - The type of element to use. + */ - resource._dequeue = dequeue; - // run before middleware - async.eachSeries( - this._beforeMiddleware, - function (fn, next) { - fn.call(self, resource, function () { - // if the before middleware marks the resource as complete, - // break and don't process any more before middleware - next(resource.isComplete ? {} : null); - }); - }, - function () { - // resource.on('progress', self.emit.bind(self, 'progress')); + Resource.prototype._loadElement = function _loadElement(type) { + if (this.metadata.loadElement) { + this.data = this.metadata.loadElement; + } else if (type === 'image' && typeof window.Image !== 'undefined') { + this.data = new Image(); + } else { + this.data = document.createElement(type); + } - if (resource.isComplete) { - self._onLoad(resource); - } - else { - resource.once('complete', self._onLoad, self); - resource.load(); - } + if (this.crossOrigin) { + this.data.crossOrigin = this.crossOrigin; } - ); -}; -/** - * Called once each resource has loaded. - * - * @fires complete - * @private - */ -Loader.prototype._onComplete = function () { - this.loading = false; + if (!this.metadata.skipSource) { + this.data.src = this.url; + } - this.emit('complete', this, this.resources); -}; + this.data.addEventListener('error', this._boundOnError, false); + this.data.addEventListener('load', this._boundComplete, false); + this.data.addEventListener('progress', this._boundOnProgress, false); + }; -/** - * Called each time a resources is loaded. - * - * @fires progress - * @fires error - * @fires load - * @private - * @param {Resource} resource - The resource that was loaded - */ -Loader.prototype._onLoad = function (resource) { - var self = this; + /** + * Loads this resources using an element that has multiple sources, + * like an HTMLAudioElement or HTMLVideoElement. + * + * @private + * @param {string} type - The type of element to use. + */ - // run middleware, this *must* happen before dequeue so sub-assets get added properly - async.eachSeries( - this._afterMiddleware, - function (fn, next) { - fn.call(self, resource, next); - }, - function () { - resource.emit('afterMiddleware', resource); - self._numToLoad--; + Resource.prototype._loadSourceElement = function _loadSourceElement(type) { + if (this.metadata.loadElement) { + this.data = this.metadata.loadElement; + } else if (type === 'audio' && typeof window.Audio !== 'undefined') { + this.data = new Audio(); + } else { + this.data = document.createElement(type); + } - self.progress += self._progressChunk; - self.emit('progress', self, resource); + if (this.data === null) { + this.abort('Unsupported element: ' + type); - if (resource.error) { - self.emit('error', resource.error, self, resource); - } - else { - self.emit('load', self, resource); - } + return; + } - // do completion check - if (self._numToLoad === 0) { - self.progress = 100; - self._onComplete(); + if (!this.metadata.skipSource) { + // support for CocoonJS Canvas+ runtime, lacks document.createElement('source') + if (navigator.isCocoonJS) { + this.data.src = Array.isArray(this.url) ? this.url[0] : this.url; + } else if (Array.isArray(this.url)) { + for (var i = 0; i < this.url.length; ++i) { + this.data.appendChild(this._createSource(type, this.url[i])); + } + } else { + this.data.appendChild(this._createSource(type, this.url)); } } - ); - // remove this resource from the async queue - resource._dequeue(); -}; + this.data.addEventListener('error', this._boundOnError, false); + this.data.addEventListener('load', this._boundComplete, false); + this.data.addEventListener('progress', this._boundOnProgress, false); + this.data.addEventListener('canplaythrough', this._boundComplete, false); + + this.data.load(); + }; -Loader.LOAD_TYPE = Resource.LOAD_TYPE; -Loader.XHR_RESPONSE_TYPE = Resource.XHR_RESPONSE_TYPE; + /** + * Loads this resources using an XMLHttpRequest. + * + * @private + */ -},{"./Resource":32,"./async":33,"eventemitter3":19,"parse-uri":22}],32:[function(require,module,exports){ -'use strict'; -var EventEmitter = require('eventemitter3'); -var parseUri = require('parse-uri'); + Resource.prototype._loadXhr = function _loadXhr() { + // if unset, determine the value + if (typeof this.xhrType !== 'string') { + this.xhrType = this._determineXhrType(); + } -// tests is CORS is supported in XHR, if not we need to use XDR -var useXdr = !!(window.XDomainRequest && !('withCredentials' in (new XMLHttpRequest()))); -var tempAnchor = null; + var xhr = this.xhr = new XMLHttpRequest(); -// some status constants -var STATUS_NONE = 0; -var STATUS_OK = 200; -var STATUS_EMPTY = 204; + // set the request type and url + xhr.open('GET', this.url, true); -/** - * Manages the state and loading of a single resource represented by - * a single URL. - * - * @class - * @param {string} name - The name of the resource to load. - * @param {string|string[]} url - The url for this resource, for audio/video loads you can pass an array of sources. - * @param {object} [options] - The options for the load. - * @param {string|boolean} [options.crossOrigin] - Is this request cross-origin? Default is to determine automatically. - * @param {Resource.LOAD_TYPE} [options.loadType=Resource.LOAD_TYPE.XHR] - How should this resource be loaded? - * @param {Resource.XHR_RESPONSE_TYPE} [options.xhrType=Resource.XHR_RESPONSE_TYPE.DEFAULT] - How should the data being - * loaded be interpreted when using XHR? - * @param {object} [options.metadata] - Extra info for middleware. - */ -function Resource(name, url, options) { - EventEmitter.call(this); + // load json as text and parse it ourselves. We do this because some browsers + // *cough* safari *cough* can't deal with it. + if (this.xhrType === Resource.XHR_RESPONSE_TYPE.JSON || this.xhrType === Resource.XHR_RESPONSE_TYPE.DOCUMENT) { + xhr.responseType = Resource.XHR_RESPONSE_TYPE.TEXT; + } else { + xhr.responseType = this.xhrType; + } - options = options || {}; + xhr.addEventListener('error', this._boundXhrOnError, false); + xhr.addEventListener('abort', this._boundXhrOnAbort, false); + xhr.addEventListener('progress', this._boundOnProgress, false); + xhr.addEventListener('load', this._boundXhrOnLoad, false); - if (typeof name !== 'string' || typeof url !== 'string') { - throw new Error('Both name and url are required for constructing a resource.'); - } + xhr.send(); + }; /** - * The name of this resource. + * Loads this resources using an XDomainRequest. This is here because we need to support IE9 (gross). * - * @member {string} - * @readonly + * @private */ - this.name = name; - /** - * The url used to load this resource. - * - * @member {string} - * @readonly - */ - this.url = url; - /** - * Stores whether or not this url is a data url. - * - * @member {boolean} - * @readonly - */ - this.isDataUrl = this.url.indexOf('data:') === 0; + Resource.prototype._loadXdr = function _loadXdr() { + // if unset, determine the value + if (typeof this.xhrType !== 'string') { + this.xhrType = this._determineXhrType(); + } - /** - * The data that was loaded by the resource. - * - * @member {any} - */ - this.data = null; + var xdr = this.xhr = new XDomainRequest(); - /** - * Is this request cross-origin? If unset, determined automatically. - * - * @member {string} - */ - this.crossOrigin = options.crossOrigin === true ? 'anonymous' : options.crossOrigin; + // XDomainRequest has a few quirks. Occasionally it will abort requests + // A way to avoid this is to make sure ALL callbacks are set even if not used + // More info here: http://stackoverflow.com/questions/15786966/xdomainrequest-aborts-post-on-ie-9 + xdr.timeout = 5000; - /** - * The method of loading to use for this resource. - * - * @member {Resource.LOAD_TYPE} - */ - this.loadType = options.loadType || this._determineLoadType(); + xdr.onerror = this._boundXhrOnError; + xdr.ontimeout = this._boundXdrOnTimeout; + xdr.onprogress = this._boundOnProgress; + xdr.onload = this._boundXhrOnLoad; - /** - * The type used to load the resource via XHR. If unset, determined automatically. - * - * @member {string} - */ - this.xhrType = options.xhrType; + xdr.open('GET', this.url, true); - /** - * Extra info for middleware, and controlling specifics about how the resource loads. - * - * Note that if you pass in a `loadElement`, the Resource class takes ownership of it. - * Meaning it will modify it as it sees fit. - * - * @member {object} - * @property {HTMLImageElement|HTMLAudioElement|HTMLVideoElement} [loadElement=null] - The - * element to use for loading, instead of creating one. - * @property {boolean} [skipSource=false] - Skips adding source(s) to the load element. This - * is useful if you want to pass in a `loadElement` that you already added load sources - * to. - */ - this.metadata = options.metadata || {}; + // Note: The xdr.send() call is wrapped in a timeout to prevent an + // issue with the interface where some requests are lost if multiple + // XDomainRequests are being sent at the same time. + // Some info here: https://github.com/photonstorm/phaser/issues/1248 + setTimeout(function () { + return xdr.send(); + }, 1); + }; /** - * The error that occurred while loading (if any). + * Creates a source used in loading via an element. * - * @member {Error} - * @readonly + * @private + * @param {string} type - The element type (video or audio). + * @param {string} url - The source URL to load from. + * @param {string} [mime] - The mime type of the video + * @return {HTMLSourceElement} The source element. */ - this.error = null; - /** - * The XHR object that was used to load this resource. This is only set - * when `loadType` is `Resource.LOAD_TYPE.XHR`. - * - * @member {XMLHttpRequest} - */ - this.xhr = null; - /** - * Describes if this resource was loaded as json. Only valid after the resource - * has completely loaded. - * - * @member {boolean} - */ - this.isJson = false; + Resource.prototype._createSource = function _createSource(type, url, mime) { + if (!mime) { + mime = type + '/' + url.substr(url.lastIndexOf('.') + 1); + } - /** - * Describes if this resource was loaded as xml. Only valid after the resource - * has completely loaded. - * - * @member {boolean} - */ - this.isXml = false; + var source = document.createElement('source'); - /** - * Describes if this resource was loaded as an image tag. Only valid after the resource - * has completely loaded. - * - * @member {boolean} - */ - this.isImage = false; + source.src = url; + source.type = mime; - /** - * Describes if this resource was loaded as an audio tag. Only valid after the resource - * has completely loaded. - * - * @member {boolean} - */ - this.isAudio = false; + return source; + }; /** - * Describes if this resource was loaded as a video tag. Only valid after the resource - * has completely loaded. + * Called if a load errors out. * - * @member {boolean} + * @param {Event} event - The error event from the element that emits it. + * @private */ - this.isVideo = false; - /** - * Describes if this resource has finished loading. Is true when the resource has completely - * loaded. - * - * @member {boolean} - */ - this.isComplete = false; - /** - * Describes if this resource is currently loading. Is true when the resource starts loading, - * and is false again when complete. - * - * @member {boolean} - */ - this.isLoading = false; + Resource.prototype._onError = function _onError(event) { + this.abort('Failed to load element using: ' + event.target.nodeName); + }; /** - * The `dequeue` method that will be used a storage place for the async queue dequeue method - * used privately by the loader. + * Called if a load progress event fires for xhr/xdr. * * @private - * @member {function} + * @param {XMLHttpRequestProgressEvent|Event} event - Progress event. */ - this._dequeue = null; - /** - * The `complete` function bound to this resource's context. - * - * @private - * @member {function} - */ - this._boundComplete = this.complete.bind(this); + + Resource.prototype._onProgress = function _onProgress(event) { + if (event && event.lengthComputable) { + this.onProgress.dispatch(this, event.loaded / event.total); + } + }; /** - * The `_onError` function bound to this resource's context. + * Called if an error event fires for xhr/xdr. * * @private - * @member {function} + * @param {XMLHttpRequestErrorEvent|Event} event - Error event. */ - this._boundOnError = this._onError.bind(this); + + + Resource.prototype._xhrOnError = function _xhrOnError() { + var xhr = this.xhr; + + this.abort(reqType(xhr) + ' Request failed. Status: ' + xhr.status + ', text: "' + xhr.statusText + '"'); + }; /** - * The `_onProgress` function bound to this resource's context. + * Called if an abort event fires for xhr. * * @private - * @member {function} + * @param {XMLHttpRequestAbortEvent} event - Abort Event */ - this._boundOnProgress = this._onProgress.bind(this); - // xhr callbacks - this._boundXhrOnError = this._xhrOnError.bind(this); - this._boundXhrOnAbort = this._xhrOnAbort.bind(this); - this._boundXhrOnLoad = this._xhrOnLoad.bind(this); - this._boundXdrOnTimeout = this._xdrOnTimeout.bind(this); - /** - * Emitted when the resource beings to load. - * - * @event start - * @memberof Resource# - */ + Resource.prototype._xhrOnAbort = function _xhrOnAbort() { + this.abort(reqType(this.xhr) + ' Request was aborted by the user.'); + }; /** - * Emitted each time progress of this resource load updates. - * Not all resources types and loader systems can support this event - * so sometimes it may not be available. If the resource - * is being loaded on a modern browser, using XHR, and the remote server - * properly sets Content-Length headers, then this will be available. + * Called if a timeout event fires for xdr. * - * @event progress - * @memberof Resource# + * @private + * @param {Event} event - Timeout event. */ + + Resource.prototype._xdrOnTimeout = function _xdrOnTimeout() { + this.abort(reqType(this.xhr) + ' Request timed out.'); + }; + /** - * Emitted once this resource has loaded, if there was an error it will - * be in the `error` property. + * Called when data successfully loads from an xhr/xdr request. * - * @event complete - * @memberof Resource# + * @private + * @param {XMLHttpRequestLoadEvent|Event} event - Load event */ -} -Resource.prototype = Object.create(EventEmitter.prototype); -Resource.prototype.constructor = Resource; -module.exports = Resource; -/** - * Marks the resource as complete. - * - * @fires complete - */ -Resource.prototype.complete = function () { - // TODO: Clean this up in a wrapper or something...gross.... - if (this.data && this.data.removeEventListener) { - this.data.removeEventListener('error', this._boundOnError, false); - this.data.removeEventListener('load', this._boundComplete, false); - this.data.removeEventListener('progress', this._boundOnProgress, false); - this.data.removeEventListener('canplaythrough', this._boundComplete, false); - } + Resource.prototype._xhrOnLoad = function _xhrOnLoad() { + var xhr = this.xhr; + var text = ''; + var status = typeof xhr.status === 'undefined' ? STATUS_OK : xhr.status; // XDR has no `.status`, assume 200. - if (this.xhr) { - if (this.xhr.removeEventListener) { - this.xhr.removeEventListener('error', this._boundXhrOnError, false); - this.xhr.removeEventListener('abort', this._boundXhrOnAbort, false); - this.xhr.removeEventListener('progress', this._boundOnProgress, false); - this.xhr.removeEventListener('load', this._boundXhrOnLoad, false); - } - else { - this.xhr.onerror = null; - this.xhr.ontimeout = null; - this.xhr.onprogress = null; - this.xhr.onload = null; + // responseText is accessible only if responseType is '' or 'text' and on older browsers + if (xhr.responseType === '' || xhr.responseType === 'text' || typeof xhr.responseType === 'undefined') { + text = xhr.responseText; } - } - - if (this.isComplete) { - throw new Error('Complete called again for an already completed resource.'); - } - - this.isComplete = true; - this.isLoading = false; - - this.emit('complete', this); -}; - -/** - * Aborts the loading of this resource, with an optional message. - * - * @param {string} message - The message to use for the error - */ -Resource.prototype.abort = function (message) { - // abort can be called multiple times, ignore subsequent calls. - if (this.error) { - return; - } - - // store error - this.error = new Error(message); - // abort the actual loading - if (this.xhr) { - this.xhr.abort(); - } - else if (this.xdr) { - this.xdr.abort(); - } - else if (this.data) { - // single source - if (typeof this.data.src !== 'undefined') { - this.data.src = ''; + // status can be 0 when using the `file://` protocol so we also check if a response is set. + // If it has a response, we assume 200; otherwise a 0 status code with no contents is an aborted request. + if (status === STATUS_NONE && text.length > 0) { + status = STATUS_OK; } - // multi-source - else { - while (this.data.firstChild) { - this.data.removeChild(this.data.firstChild); + // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request + else if (status === STATUS_IE_BUG_EMPTY) { + status = STATUS_EMPTY; } - } - } - - // done now. - this.complete(); -}; - -/** - * Kicks off loading of this resource. This method is asynchronous. - * - * @fires start - * @param {function} [cb] - Optional callback to call once the resource is loaded. - */ -Resource.prototype.load = function (cb) { - if (this.isLoading) { - return; - } - - if (this.isComplete) { - if (cb) { - var self = this; - - setTimeout(function () { - cb(self); - }, 1); - } - - return; - } - else if (cb) { - this.once('complete', cb); - } - - this.isLoading = true; - - this.emit('start', this); - - // if unset, determine the value - if (this.crossOrigin === false || typeof this.crossOrigin !== 'string') { - this.crossOrigin = this._determineCrossOrigin(this.url); - } - switch (this.loadType) { - case Resource.LOAD_TYPE.IMAGE: - this._loadElement('image'); - break; - - case Resource.LOAD_TYPE.AUDIO: - this._loadSourceElement('audio'); - break; - - case Resource.LOAD_TYPE.VIDEO: - this._loadSourceElement('video'); - break; + var statusType = status / 100 | 0; - case Resource.LOAD_TYPE.XHR: - /* falls through */ - default: - if (useXdr && this.crossOrigin) { - this._loadXdr(); - } - else { - this._loadXhr(); + if (statusType === STATUS_TYPE_OK) { + // if text, just return it + if (this.xhrType === Resource.XHR_RESPONSE_TYPE.TEXT) { + this.data = text; + this.type = Resource.TYPE.TEXT; } - break; - } -}; - -/** - * Loads this resources using an element that has a single source, - * like an HTMLImageElement. - * - * @private - * @param {string} type - The type of element to use. - */ -Resource.prototype._loadElement = function (type) { - if (this.metadata.loadElement) { - this.data = this.metadata.loadElement; - } - else if (type === 'image' && typeof window.Image !== 'undefined') { - this.data = new Image(); - } - else { - this.data = document.createElement(type); - } - - if (this.crossOrigin) { - this.data.crossOrigin = this.crossOrigin; - } - - if (!this.metadata.skipSource) { - this.data.src = this.url; - } + // if json, parse into json object + else if (this.xhrType === Resource.XHR_RESPONSE_TYPE.JSON) { + try { + this.data = JSON.parse(text); + this.type = Resource.TYPE.JSON; + } catch (e) { + this.abort('Error trying to parse loaded json: ' + e); - var typeName = 'is' + type[0].toUpperCase() + type.substring(1); + return; + } + } + // if xml, parse into an xml document or div element + else if (this.xhrType === Resource.XHR_RESPONSE_TYPE.DOCUMENT) { + try { + if (window.DOMParser) { + var domparser = new DOMParser(); - if (this[typeName] === false) { - this[typeName] = true; - } + this.data = domparser.parseFromString(text, 'text/xml'); + } else { + var div = document.createElement('div'); - this.data.addEventListener('error', this._boundOnError, false); - this.data.addEventListener('load', this._boundComplete, false); - this.data.addEventListener('progress', this._boundOnProgress, false); -}; + div.innerHTML = text; -/** - * Loads this resources using an element that has multiple sources, - * like an HTMLAudioElement or HTMLVideoElement. - * - * @private - * @param {string} type - The type of element to use. - */ -Resource.prototype._loadSourceElement = function (type) { - if (this.metadata.loadElement) { - this.data = this.metadata.loadElement; - } - else if (type === 'audio' && typeof window.Audio !== 'undefined') { - this.data = new Audio(); - } - else { - this.data = document.createElement(type); - } + this.data = div; + } - if (this.data === null) { - this.abort('Unsupported element ' + type); + this.type = Resource.TYPE.XML; + } catch (e) { + this.abort('Error trying to parse loaded xml: ' + e); - return; - } + return; + } + } + // other types just return the response + else { + this.data = xhr.response || text; + } + } else { + this.abort('[' + xhr.status + '] ' + xhr.statusText + ': ' + xhr.responseURL); - if (!this.metadata.skipSource) { - // support for CocoonJS Canvas+ runtime, lacks document.createElement('source') - if (navigator.isCocoonJS) { - this.data.src = Array.isArray(this.url) ? this.url[0] : this.url; - } - else if (Array.isArray(this.url)) { - for (var i = 0; i < this.url.length; ++i) { - this.data.appendChild(this._createSource(type, this.url[i])); - } - } - else { - this.data.appendChild(this._createSource(type, this.url)); + return; } - } - - this['is' + type[0].toUpperCase() + type.substring(1)] = true; - - this.data.addEventListener('error', this._boundOnError, false); - this.data.addEventListener('load', this._boundComplete, false); - this.data.addEventListener('progress', this._boundOnProgress, false); - this.data.addEventListener('canplaythrough', this._boundComplete, false); - - this.data.load(); -}; - -/** - * Loads this resources using an XMLHttpRequest. - * - * @private - */ -Resource.prototype._loadXhr = function () { - // if unset, determine the value - if (typeof this.xhrType !== 'string') { - this.xhrType = this._determineXhrType(); - } - - var xhr = this.xhr = new XMLHttpRequest(); - - // set the request type and url - xhr.open('GET', this.url, true); - - // load json as text and parse it ourselves. We do this because some browsers - // *cough* safari *cough* can't deal with it. - if (this.xhrType === Resource.XHR_RESPONSE_TYPE.JSON || this.xhrType === Resource.XHR_RESPONSE_TYPE.DOCUMENT) { - xhr.responseType = Resource.XHR_RESPONSE_TYPE.TEXT; - } - else { - xhr.responseType = this.xhrType; - } - - xhr.addEventListener('error', this._boundXhrOnError, false); - xhr.addEventListener('abort', this._boundXhrOnAbort, false); - xhr.addEventListener('progress', this._boundOnProgress, false); - xhr.addEventListener('load', this._boundXhrOnLoad, false); - xhr.send(); -}; + this.complete(); + }; -/** - * Loads this resources using an XDomainRequest. This is here because we need to support IE9 (gross). - * - * @private - */ -Resource.prototype._loadXdr = function () { - // if unset, determine the value - if (typeof this.xhrType !== 'string') { - this.xhrType = this._determineXhrType(); - } + /** + * Sets the `crossOrigin` property for this resource based on if the url + * for this resource is cross-origin. If crossOrigin was manually set, this + * function does nothing. + * + * @private + * @param {string} url - The url to test. + * @param {object} [loc=window.location] - The location object to test against. + * @return {string} The crossOrigin value to use (or empty string for none). + */ - var xdr = this.xhr = new XDomainRequest(); - // XDomainRequest has a few quirks. Occasionally it will abort requests - // A way to avoid this is to make sure ALL callbacks are set even if not used - // More info here: http://stackoverflow.com/questions/15786966/xdomainrequest-aborts-post-on-ie-9 - xdr.timeout = 5000; + Resource.prototype._determineCrossOrigin = function _determineCrossOrigin(url, loc) { + // data: and javascript: urls are considered same-origin + if (url.indexOf('data:') === 0) { + return ''; + } - xdr.onerror = this._boundXhrOnError; - xdr.ontimeout = this._boundXdrOnTimeout; - xdr.onprogress = this._boundOnProgress; - xdr.onload = this._boundXhrOnLoad; + // default is window.location + loc = loc || window.location; - xdr.open('GET', this.url, true); + if (!tempAnchor) { + tempAnchor = document.createElement('a'); + } - // Note: The xdr.send() call is wrapped in a timeout to prevent an - // issue with the interface where some requests are lost if multiple - // XDomainRequests are being sent at the same time. - // Some info here: https://github.com/photonstorm/phaser/issues/1248 - setTimeout(function () { - xdr.send(); - }, 0); -}; + // let the browser determine the full href for the url of this resource and then + // parse with the node url lib, we can't use the properties of the anchor element + // because they don't work in IE9 :( + tempAnchor.href = url; + url = (0, _parseUri2.default)(tempAnchor.href, { strictMode: true }); -/** - * Creates a source used in loading via an element. - * - * @private - * @param {string} type - The element type (video or audio). - * @param {string} url - The source URL to load from. - * @param {string} [mime] - The mime type of the video - * @return {HTMLSourceElement} The source element. - */ -Resource.prototype._createSource = function (type, url, mime) { - if (!mime) { - mime = type + '/' + url.substr(url.lastIndexOf('.') + 1); - } + var samePort = !url.port && loc.port === '' || url.port === loc.port; + var protocol = url.protocol ? url.protocol + ':' : ''; - var source = document.createElement('source'); + // if cross origin + if (url.host !== loc.hostname || !samePort || protocol !== loc.protocol) { + return 'anonymous'; + } - source.src = url; - source.type = mime; + return ''; + }; - return source; -}; + /** + * Determines the responseType of an XHR request based on the extension of the + * resource being loaded. + * + * @private + * @return {Resource.XHR_RESPONSE_TYPE} The responseType to use. + */ -/** - * Called if a load errors out. - * - * @param {Event} event - The error event from the element that emits it. - * @private - */ -Resource.prototype._onError = function (event) { - this.abort('Failed to load element using ' + event.target.nodeName); -}; -/** - * Called if a load progress event fires for xhr/xdr. - * - * @fires progress - * @private - * @param {XMLHttpRequestProgressEvent|Event} event - Progress event. - */ -Resource.prototype._onProgress = function (event) { - if (event && event.lengthComputable) { - this.emit('progress', this, event.loaded / event.total); - } -}; + Resource.prototype._determineXhrType = function _determineXhrType() { + return Resource._xhrTypeMap[this.extension] || Resource.XHR_RESPONSE_TYPE.TEXT; + }; -/** - * Called if an error event fires for xhr/xdr. - * - * @private - * @param {XMLHttpRequestErrorEvent|Event} event - Error event. - */ -Resource.prototype._xhrOnError = function () { - var xhr = this.xhr; + /** + * Determines the loadType of a resource based on the extension of the + * resource being loaded. + * + * @private + * @return {Resource.LOAD_TYPE} The loadType to use. + */ - this.abort(reqType(xhr) + ' Request failed. Status: ' + xhr.status + ', text: "' + xhr.statusText + '"'); -}; -/** - * Called if an abort event fires for xhr. - * - * @private - * @param {XMLHttpRequestAbortEvent} event - Abort Event - */ -Resource.prototype._xhrOnAbort = function () { - this.abort(reqType(this.xhr) + ' Request was aborted by the user.'); -}; + Resource.prototype._determineLoadType = function _determineLoadType() { + return Resource._loadTypeMap[this.extension] || Resource.LOAD_TYPE.XHR; + }; -/** - * Called if a timeout event fires for xdr. - * - * @private - * @param {Event} event - Timeout event. - */ -Resource.prototype._xdrOnTimeout = function () { - this.abort(reqType(this.xhr) + ' Request timed out.'); -}; + /** + * Extracts the extension (sans '.') of the file being loaded by the resource. + * + * @private + * @return {string} The extension. + */ -/** - * Called when data successfully loads from an xhr/xdr request. - * - * @private - * @param {XMLHttpRequestLoadEvent|Event} event - Load event - */ -Resource.prototype._xhrOnLoad = function () { - var xhr = this.xhr; - var status = typeof xhr.status === 'undefined' ? xhr.status : STATUS_OK; // XDR has no `.status`, assume 200. - // status can be 0 when using the file:// protocol, also check if a response was found - if (status === STATUS_OK || status === STATUS_EMPTY || (status === STATUS_NONE && xhr.responseText.length > 0)) { - // if text, just return it - if (this.xhrType === Resource.XHR_RESPONSE_TYPE.TEXT) { - this.data = xhr.responseText; - } - // if json, parse into json object - else if (this.xhrType === Resource.XHR_RESPONSE_TYPE.JSON) { - try { - this.data = JSON.parse(xhr.responseText); - this.isJson = true; - } - catch (e) { - this.abort('Error trying to parse loaded json:', e); + Resource.prototype._getExtension = function _getExtension() { + var url = this.url; + var ext = ''; - return; - } - } - // if xml, parse into an xml document or div element - else if (this.xhrType === Resource.XHR_RESPONSE_TYPE.DOCUMENT) { - try { - if (window.DOMParser) { - var domparser = new DOMParser(); + if (this.isDataUrl) { + var slashIndex = url.indexOf('/'); - this.data = domparser.parseFromString(xhr.responseText, 'text/xml'); - } - else { - var div = document.createElement('div'); + ext = url.substring(slashIndex + 1, url.indexOf(';', slashIndex)); + } else { + var queryStart = url.indexOf('?'); - div.innerHTML = xhr.responseText; - this.data = div; - } - this.isXml = true; + if (queryStart !== -1) { + url = url.substring(0, queryStart); } - catch (e) { - this.abort('Error trying to parse loaded xml:', e); - return; - } - } - // other types just return the response - else { - this.data = xhr.response || xhr.responseText; + ext = url.substring(url.lastIndexOf('.') + 1); } - } - else { - this.abort('[' + xhr.status + ']' + xhr.statusText + ':' + xhr.responseURL); - - return; - } - - this.complete(); -}; - -/** - * Sets the `crossOrigin` property for this resource based on if the url - * for this resource is cross-origin. If crossOrigin was manually set, this - * function does nothing. - * - * @private - * @param {string} url - The url to test. - * @param {object} [loc=window.location] - The location object to test against. - * @return {string} The crossOrigin value to use (or empty string for none). - */ -Resource.prototype._determineCrossOrigin = function (url, loc) { - // data: and javascript: urls are considered same-origin - if (url.indexOf('data:') === 0) { - return ''; - } - // default is window.location - loc = loc || window.location; - - if (!tempAnchor) { - tempAnchor = document.createElement('a'); - } - - // let the browser determine the full href for the url of this resource and then - // parse with the node url lib, we can't use the properties of the anchor element - // because they don't work in IE9 :( - tempAnchor.href = url; - url = parseUri(tempAnchor.href, { strictMode: true }); + return ext.toLowerCase(); + }; - var samePort = (!url.port && loc.port === '') || (url.port === loc.port); - var protocol = url.protocol ? url.protocol + ':' : ''; + /** + * Determines the mime type of an XHR request based on the responseType of + * resource being loaded. + * + * @private + * @param {Resource.XHR_RESPONSE_TYPE} type - The type to get a mime type for. + * @return {string} The mime type to use. + */ - // if cross origin - if (url.host !== loc.hostname || !samePort || protocol !== loc.protocol) { - return 'anonymous'; - } - return ''; -}; + Resource.prototype._getMimeFromXhrType = function _getMimeFromXhrType(type) { + switch (type) { + case Resource.XHR_RESPONSE_TYPE.BUFFER: + return 'application/octet-binary'; -/** - * Determines the responseType of an XHR request based on the extension of the - * resource being loaded. - * - * @private - * @return {Resource.XHR_RESPONSE_TYPE} The responseType to use. - */ -Resource.prototype._determineXhrType = function () { - return Resource._xhrTypeMap[this._getExtension()] || Resource.XHR_RESPONSE_TYPE.TEXT; -}; + case Resource.XHR_RESPONSE_TYPE.BLOB: + return 'application/blob'; -Resource.prototype._determineLoadType = function () { - return Resource._loadTypeMap[this._getExtension()] || Resource.LOAD_TYPE.XHR; -}; + case Resource.XHR_RESPONSE_TYPE.DOCUMENT: + return 'application/xml'; -Resource.prototype._getExtension = function () { - var url = this.url; - var ext = ''; + case Resource.XHR_RESPONSE_TYPE.JSON: + return 'application/json'; - if (this.isDataUrl) { - var slashIndex = url.indexOf('/'); + case Resource.XHR_RESPONSE_TYPE.DEFAULT: + case Resource.XHR_RESPONSE_TYPE.TEXT: + /* falls through */ + default: + return 'text/plain'; - ext = url.substring(slashIndex + 1, url.indexOf(';', slashIndex)); - } - else { - var queryStart = url.indexOf('?'); + } + }; - if (queryStart !== -1) { - url = url.substring(0, queryStart); + _createClass(Resource, [{ + key: 'isDataUrl', + get: function get() { + return this._hasFlag(Resource.STATUS_FLAGS.DATA_URL); } - ext = url.substring(url.lastIndexOf('.') + 1); - } + /** + * Describes if this resource has finished loading. Is true when the resource has completely + * loaded. + * + * @member {boolean} + * @readonly + */ - return ext.toLowerCase(); -}; + }, { + key: 'isComplete', + get: function get() { + return this._hasFlag(Resource.STATUS_FLAGS.COMPLETE); + } -/** - * Determines the mime type of an XHR request based on the responseType of - * resource being loaded. - * - * @private - * @param {Resource.XHR_RESPONSE_TYPE} type - The type to get a mime type for. - * @return {string} The mime type to use. - */ -Resource.prototype._getMimeFromXhrType = function (type) { - switch (type) { - case Resource.XHR_RESPONSE_TYPE.BUFFER: - return 'application/octet-binary'; + /** + * Describes if this resource is currently loading. Is true when the resource starts loading, + * and is false again when complete. + * + * @member {boolean} + * @readonly + */ - case Resource.XHR_RESPONSE_TYPE.BLOB: - return 'application/blob'; + }, { + key: 'isLoading', + get: function get() { + return this._hasFlag(Resource.STATUS_FLAGS.LOADING); + } + }]); - case Resource.XHR_RESPONSE_TYPE.DOCUMENT: - return 'application/xml'; + return Resource; +}(); - case Resource.XHR_RESPONSE_TYPE.JSON: - return 'application/json'; +/** + * The types of resources a resource could represent. + * + * @static + * @readonly + * @enum {number} + */ - case Resource.XHR_RESPONSE_TYPE.DEFAULT: - case Resource.XHR_RESPONSE_TYPE.TEXT: - /* falls through */ - default: - return 'text/plain'; - } +exports.default = Resource; +Resource.STATUS_FLAGS = { + NONE: 0, + DATA_URL: 1 << 0, + COMPLETE: 1 << 1, + LOADING: 1 << 2 }; /** - * Quick helper to get string xhr type. + * The types of resources a resource could represent. * - * @ignore - * @param {XMLHttpRequest|XDomainRequest} xhr - The request to check. - * @return {string} The type. + * @static + * @readonly + * @enum {number} */ -function reqType(xhr) { - return xhr.toString().replace('object ', ''); -} +Resource.TYPE = { + UNKNOWN: 0, + JSON: 1, + XML: 2, + IMAGE: 3, + AUDIO: 4, + VIDEO: 5, + TEXT: 6 +}; /** * The types of loading a resource can use. @@ -6176,13 +6044,13 @@ function reqType(xhr) { */ Resource.LOAD_TYPE = { /** Uses XMLHttpRequest to load the resource. */ - XHR: 1, + XHR: 1, /** Uses an `Image` object to load the resource. */ - IMAGE: 2, + IMAGE: 2, /** Uses an `Audio` object to load the resource. */ - AUDIO: 3, + AUDIO: 3, /** Uses a `Video` object to load the resource. */ - VIDEO: 4 + VIDEO: 4 }; /** @@ -6193,84 +6061,93 @@ Resource.LOAD_TYPE = { * @enum {string} */ Resource.XHR_RESPONSE_TYPE = { - /** defaults to text */ - DEFAULT: 'text', + /** string */ + DEFAULT: 'text', /** ArrayBuffer */ - BUFFER: 'arraybuffer', + BUFFER: 'arraybuffer', /** Blob */ - BLOB: 'blob', + BLOB: 'blob', /** Document */ - DOCUMENT: 'document', + DOCUMENT: 'document', /** Object */ - JSON: 'json', + JSON: 'json', /** String */ - TEXT: 'text' + TEXT: 'text' }; Resource._loadTypeMap = { - gif: Resource.LOAD_TYPE.IMAGE, - png: Resource.LOAD_TYPE.IMAGE, - bmp: Resource.LOAD_TYPE.IMAGE, - jpg: Resource.LOAD_TYPE.IMAGE, - jpeg: Resource.LOAD_TYPE.IMAGE, - tif: Resource.LOAD_TYPE.IMAGE, - tiff: Resource.LOAD_TYPE.IMAGE, - webp: Resource.LOAD_TYPE.IMAGE, - tga: Resource.LOAD_TYPE.IMAGE, - 'svg+xml': Resource.LOAD_TYPE.IMAGE + // images + gif: Resource.LOAD_TYPE.IMAGE, + png: Resource.LOAD_TYPE.IMAGE, + bmp: Resource.LOAD_TYPE.IMAGE, + jpg: Resource.LOAD_TYPE.IMAGE, + jpeg: Resource.LOAD_TYPE.IMAGE, + tif: Resource.LOAD_TYPE.IMAGE, + tiff: Resource.LOAD_TYPE.IMAGE, + webp: Resource.LOAD_TYPE.IMAGE, + tga: Resource.LOAD_TYPE.IMAGE, + svg: Resource.LOAD_TYPE.IMAGE, + 'svg+xml': Resource.LOAD_TYPE.IMAGE, // for SVG data urls + + // audio + mp3: Resource.LOAD_TYPE.AUDIO, + ogg: Resource.LOAD_TYPE.AUDIO, + wav: Resource.LOAD_TYPE.AUDIO, + + // videos + mp4: Resource.LOAD_TYPE.VIDEO, + webm: Resource.LOAD_TYPE.VIDEO }; Resource._xhrTypeMap = { // xml - xhtml: Resource.XHR_RESPONSE_TYPE.DOCUMENT, - html: Resource.XHR_RESPONSE_TYPE.DOCUMENT, - htm: Resource.XHR_RESPONSE_TYPE.DOCUMENT, - xml: Resource.XHR_RESPONSE_TYPE.DOCUMENT, - tmx: Resource.XHR_RESPONSE_TYPE.DOCUMENT, - tsx: Resource.XHR_RESPONSE_TYPE.DOCUMENT, - svg: Resource.XHR_RESPONSE_TYPE.DOCUMENT, + xhtml: Resource.XHR_RESPONSE_TYPE.DOCUMENT, + html: Resource.XHR_RESPONSE_TYPE.DOCUMENT, + htm: Resource.XHR_RESPONSE_TYPE.DOCUMENT, + xml: Resource.XHR_RESPONSE_TYPE.DOCUMENT, + tmx: Resource.XHR_RESPONSE_TYPE.DOCUMENT, + svg: Resource.XHR_RESPONSE_TYPE.DOCUMENT, + + // This was added to handle Tiled Tileset XML, but .tsx is also a TypeScript React Component. + // Since it is way less likely for people to be loading TypeScript files instead of Tiled files, + // this should probably be fine. + tsx: Resource.XHR_RESPONSE_TYPE.DOCUMENT, // images - gif: Resource.XHR_RESPONSE_TYPE.BLOB, - png: Resource.XHR_RESPONSE_TYPE.BLOB, - bmp: Resource.XHR_RESPONSE_TYPE.BLOB, - jpg: Resource.XHR_RESPONSE_TYPE.BLOB, - jpeg: Resource.XHR_RESPONSE_TYPE.BLOB, - tif: Resource.XHR_RESPONSE_TYPE.BLOB, - tiff: Resource.XHR_RESPONSE_TYPE.BLOB, - webp: Resource.XHR_RESPONSE_TYPE.BLOB, - tga: Resource.XHR_RESPONSE_TYPE.BLOB, + gif: Resource.XHR_RESPONSE_TYPE.BLOB, + png: Resource.XHR_RESPONSE_TYPE.BLOB, + bmp: Resource.XHR_RESPONSE_TYPE.BLOB, + jpg: Resource.XHR_RESPONSE_TYPE.BLOB, + jpeg: Resource.XHR_RESPONSE_TYPE.BLOB, + tif: Resource.XHR_RESPONSE_TYPE.BLOB, + tiff: Resource.XHR_RESPONSE_TYPE.BLOB, + webp: Resource.XHR_RESPONSE_TYPE.BLOB, + tga: Resource.XHR_RESPONSE_TYPE.BLOB, // json - json: Resource.XHR_RESPONSE_TYPE.JSON, + json: Resource.XHR_RESPONSE_TYPE.JSON, // text - text: Resource.XHR_RESPONSE_TYPE.TEXT, - txt: Resource.XHR_RESPONSE_TYPE.TEXT -}; + text: Resource.XHR_RESPONSE_TYPE.TEXT, + txt: Resource.XHR_RESPONSE_TYPE.TEXT, -/** - * Sets the load type to be used for a specific extension. - * - * @static - * @param {string} extname - The extension to set the type for, e.g. "png" or "fnt" - * @param {Resource.LOAD_TYPE} loadType - The load type to set it to. - */ -Resource.setExtensionLoadType = function (extname, loadType) { - setExtMap(Resource._loadTypeMap, extname, loadType); + // fonts + ttf: Resource.XHR_RESPONSE_TYPE.BUFFER, + otf: Resource.XHR_RESPONSE_TYPE.BUFFER }; +// We can't set the `src` attribute to empty string, so on abort we set it to this 1px transparent gif +Resource.EMPTY_GIF = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='; + /** - * Sets the load type to be used for a specific extension. + * Quick helper to set a value on one of the extension maps. Ensures there is no + * dot at the start of the extension. * - * @static - * @param {string} extname - The extension to set the type for, e.g. "png" or "fnt" - * @param {Resource.XHR_RESPONSE_TYPE} xhrType - The xhr type to set it to. + * @ignore + * @param {object} map - The map to set on. + * @param {string} extname - The extension (or key) to set. + * @param {number} val - The value to set. */ -Resource.setExtensionXhrType = function (extname, xhrType) { - setExtMap(Resource._xhrTypeMap, extname, xhrType); -}; - function setExtMap(map, extname, val) { if (extname && extname.indexOf('.') === 0) { extname = extname.substring(1); @@ -6283,29 +6160,38 @@ function setExtMap(map, extname, val) { map[extname] = val; } -},{"eventemitter3":19,"parse-uri":22}],33:[function(require,module,exports){ +/** + * Quick helper to get string xhr type. + * + * @ignore + * @param {XMLHttpRequest|XDomainRequest} xhr - The request to check. + * @return {string} The type. + */ +function reqType(xhr) { + return xhr.toString().replace('object ', ''); +} + +},{"mini-signals":22,"parse-uri":24}],34:[function(require,module,exports){ 'use strict'; +exports.__esModule = true; +exports.eachSeries = eachSeries; +exports.queue = queue; /** * Smaller version of the async library constructs. * */ - -module.exports = { - eachSeries: asyncEachSeries, - queue: asyncQueue -}; - -function _noop() { /* empty */ } +function _noop() {} /* empty */ /** * Iterates an array in series. * - * @param {*[]} array - Array to iterate. + * @param {Array.<*>} array - Array to iterate. * @param {function} iterator - Function to call for each element. * @param {function} callback - Function to call when done, or on error. + * @param {boolean} [deferNext=false] - Break synchronous each loop by calling next with a setTimeout of 1. */ -function asyncEachSeries(array, iterator, callback) { +function eachSeries(array, iterator, callback, deferNext) { var i = 0; var len = array.length; @@ -6318,7 +6204,13 @@ function asyncEachSeries(array, iterator, callback) { return; } - iterator(array[i++], next); + if (deferNext) { + setTimeout(function () { + iterator(array[i++], next); + }, 1); + } else { + iterator(array[i++], next); + } })(); } @@ -6348,11 +6240,11 @@ function onlyOnce(fn) { * @param {number} concurrency - How many workers to run in parrallel. * @return {*} The async queue object. */ -function asyncQueue(worker, concurrency) { - if (concurrency == null) { // eslint-disable-line no-eq-null,eqeqeq +function queue(worker, concurrency) { + if (concurrency == null) { + // eslint-disable-line no-eq-null,eqeqeq concurrency = 1; - } - else if (concurrency === 0) { + } else if (concurrency === 0) { throw new Error('Concurrency must not be zero'); } @@ -6368,17 +6260,19 @@ function asyncQueue(worker, concurrency) { error: _noop, started: false, paused: false, - push: function (data, callback) { + push: function push(data, callback) { _insert(data, false, callback); }, - kill: function () { + kill: function kill() { + workers = 0; q.drain = _noop; + q.started = false; q._tasks = []; }, - unshift: function (data, callback) { + unshift: function unshift(data, callback) { _insert(data, true, callback); }, - process: function () { + process: function process() { while (!q.paused && workers < q.concurrency && q._tasks.length) { var task = q._tasks.shift(); @@ -6395,276 +6289,1030 @@ function asyncQueue(worker, concurrency) { worker(task.data, onlyOnce(_next(task))); } }, - length: function () { + length: function length() { return q._tasks.length; }, - running: function () { + running: function running() { return workers; }, - idle: function () { + idle: function idle() { return q._tasks.length + workers === 0; }, - pause: function () { + pause: function pause() { if (q.paused === true) { return; } - q.paused = true; - }, - resume: function () { - if (q.paused === false) { - return; - } + q.paused = true; + }, + resume: function resume() { + if (q.paused === false) { + return; + } + + q.paused = false; + + // Need to call q.process once per concurrent + // worker to preserve full concurrency after pause + for (var w = 1; w <= q.concurrency; w++) { + q.process(); + } + } + }; + + function _insert(data, insertAtFront, callback) { + if (callback != null && typeof callback !== 'function') { + // eslint-disable-line no-eq-null,eqeqeq + throw new Error('task callback must be a function'); + } + + q.started = true; + + if (data == null && q.idle()) { + // eslint-disable-line no-eq-null,eqeqeq + // call drain immediately if there are no tasks + setTimeout(function () { + return q.drain(); + }, 1); + + return; + } + + var item = { + data: data, + callback: typeof callback === 'function' ? callback : _noop + }; + + if (insertAtFront) { + q._tasks.unshift(item); + } else { + q._tasks.push(item); + } + + setTimeout(function () { + return q.process(); + }, 1); + } + + function _next(task) { + return function next() { + workers -= 1; + + task.callback.apply(task, arguments); + + if (arguments[0] != null) { + // eslint-disable-line no-eq-null,eqeqeq + q.error(arguments[0], task.data); + } + + if (workers <= q.concurrency - q.buffer) { + q.unsaturated(); + } + + if (q.idle()) { + q.drain(); + } + + q.process(); + }; + } + + return q; +} + +},{}],35:[function(require,module,exports){ +'use strict'; + +exports.__esModule = true; +exports.encodeBinary = encodeBinary; +var _keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + +function encodeBinary(input) { + var output = ''; + var inx = 0; + + while (inx < input.length) { + // Fill byte buffer array + var bytebuffer = [0, 0, 0]; + var encodedCharIndexes = [0, 0, 0, 0]; + + for (var jnx = 0; jnx < bytebuffer.length; ++jnx) { + if (inx < input.length) { + // throw away high-order byte, as documented at: + // https://developer.mozilla.org/En/Using_XMLHttpRequest#Handling_binary_data + bytebuffer[jnx] = input.charCodeAt(inx++) & 0xff; + } else { + bytebuffer[jnx] = 0; + } + } + + // Get each encoded character, 6 bits at a time + // index 1: first 6 bits + encodedCharIndexes[0] = bytebuffer[0] >> 2; + + // index 2: second 6 bits (2 least significant bits from input byte 1 + 4 most significant bits from byte 2) + encodedCharIndexes[1] = (bytebuffer[0] & 0x3) << 4 | bytebuffer[1] >> 4; + + // index 3: third 6 bits (4 least significant bits from input byte 2 + 2 most significant bits from byte 3) + encodedCharIndexes[2] = (bytebuffer[1] & 0x0f) << 2 | bytebuffer[2] >> 6; + + // index 3: forth 6 bits (6 least significant bits from input byte 3) + encodedCharIndexes[3] = bytebuffer[2] & 0x3f; + + // Determine whether padding happened, and adjust accordingly + var paddingBytes = inx - (input.length - 1); + + switch (paddingBytes) { + case 2: + // Set last 2 characters to padding char + encodedCharIndexes[3] = 64; + encodedCharIndexes[2] = 64; + break; + + case 1: + // Set last character to padding char + encodedCharIndexes[3] = 64; + break; + + default: + break; // No padding - proceed + } + + // Now we will grab each appropriate character out of our keystring + // based on our index array and append it to the output string + for (var _jnx = 0; _jnx < encodedCharIndexes.length; ++_jnx) { + output += _keyStr.charAt(encodedCharIndexes[_jnx]); + } + } + + return output; +} + +},{}],36:[function(require,module,exports){ +'use strict'; + +// import Loader from './Loader'; +// import Resource from './Resource'; +// import * as async from './async'; +// import * as b64 from './b64'; + +/* eslint-disable no-undef */ + +var Loader = require('./Loader').default; +var Resource = require('./Resource').default; +var async = require('./async'); +var b64 = require('./b64'); + +Loader.Resource = Resource; +Loader.async = async; +Loader.base64 = b64; + +// export manually, and also as default +module.exports = Loader; +// export default Loader; +module.exports.default = Loader; + +},{"./Loader":32,"./Resource":33,"./async":34,"./b64":35}],37:[function(require,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.blobMiddlewareFactory = blobMiddlewareFactory; + +var _Resource = require('../../Resource'); + +var _Resource2 = _interopRequireDefault(_Resource); + +var _b = require('../../b64'); + +var _b2 = _interopRequireDefault(_b); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var Url = window.URL || window.webkitURL; + +// a middleware for transforming XHR loaded Blobs into more useful objects +function blobMiddlewareFactory() { + return function blobMiddleware(resource, next) { + if (!resource.data) { + next(); + + return; + } + + // if this was an XHR load of a blob + if (resource.xhr && resource.xhrType === _Resource2.default.XHR_RESPONSE_TYPE.BLOB) { + // if there is no blob support we probably got a binary string back + if (!window.Blob || typeof resource.data === 'string') { + var type = resource.xhr.getResponseHeader('content-type'); + + // this is an image, convert the binary string into a data url + if (type && type.indexOf('image') === 0) { + resource.data = new Image(); + resource.data.src = 'data:' + type + ';base64,' + _b2.default.encodeBinary(resource.xhr.responseText); + + resource.type = _Resource2.default.TYPE.IMAGE; + + // wait until the image loads and then callback + resource.data.onload = function () { + resource.data.onload = null; + + next(); + }; + + // next will be called on load + return; + } + } + // if content type says this is an image, then we should transform the blob into an Image object + else if (resource.data.type.indexOf('image') === 0) { + var _ret = function () { + var src = Url.createObjectURL(resource.data); + + resource.blob = resource.data; + resource.data = new Image(); + resource.data.src = src; + + resource.type = _Resource2.default.TYPE.IMAGE; + + // cleanup the no longer used blob after the image loads + // TODO: Is this correct? Will the image be invalid after revoking? + resource.data.onload = function () { + Url.revokeObjectURL(src); + resource.data.onload = null; + + next(); + }; + + // next will be called on load. + return { + v: void 0 + }; + }(); + + if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v; + } + } + + next(); + }; +} + +},{"../../Resource":33,"../../b64":35}],38:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +var punycode = require('punycode'); +var util = require('./util'); + +exports.parse = urlParse; +exports.resolve = urlResolve; +exports.resolveObject = urlResolveObject; +exports.format = urlFormat; + +exports.Url = Url; + +function Url() { + this.protocol = null; + this.slashes = null; + this.auth = null; + this.host = null; + this.port = null; + this.hostname = null; + this.hash = null; + this.search = null; + this.query = null; + this.pathname = null; + this.path = null; + this.href = null; +} + +// Reference: RFC 3986, RFC 1808, RFC 2396 + +// define these here so at least they only have to be +// compiled once on the first module load. +var protocolPattern = /^([a-z0-9.+-]+:)/i, + portPattern = /:[0-9]*$/, + + // Special case for a simple path URL + simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/, + + // RFC 2396: characters reserved for delimiting URLs. + // We actually just auto-escape these. + delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'], + + // RFC 2396: characters not allowed for various reasons. + unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims), + + // Allowed by RFCs, but cause of XSS attacks. Always escape these. + autoEscape = ['\''].concat(unwise), + // Characters that are never ever allowed in a hostname. + // Note that any invalid chars are also handled, but these + // are the ones that are *expected* to be seen, so we fast-path + // them. + nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape), + hostEndingChars = ['/', '?', '#'], + hostnameMaxLen = 255, + hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/, + hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/, + // protocols that can allow "unsafe" and "unwise" chars. + unsafeProtocol = { + 'javascript': true, + 'javascript:': true + }, + // protocols that never have a hostname. + hostlessProtocol = { + 'javascript': true, + 'javascript:': true + }, + // protocols that always contain a // bit. + slashedProtocol = { + 'http': true, + 'https': true, + 'ftp': true, + 'gopher': true, + 'file': true, + 'http:': true, + 'https:': true, + 'ftp:': true, + 'gopher:': true, + 'file:': true + }, + querystring = require('querystring'); + +function urlParse(url, parseQueryString, slashesDenoteHost) { + if (url && util.isObject(url) && url instanceof Url) return url; + + var u = new Url; + u.parse(url, parseQueryString, slashesDenoteHost); + return u; +} + +Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) { + if (!util.isString(url)) { + throw new TypeError("Parameter 'url' must be a string, not " + typeof url); + } + + // Copy chrome, IE, opera backslash-handling behavior. + // Back slashes before the query string get converted to forward slashes + // See: https://code.google.com/p/chromium/issues/detail?id=25916 + var queryIndex = url.indexOf('?'), + splitter = + (queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#', + uSplit = url.split(splitter), + slashRegex = /\\/g; + uSplit[0] = uSplit[0].replace(slashRegex, '/'); + url = uSplit.join(splitter); + + var rest = url; + + // trim before proceeding. + // This is to support parse stuff like " http://foo.com \n" + rest = rest.trim(); + + if (!slashesDenoteHost && url.split('#').length === 1) { + // Try fast path regexp + var simplePath = simplePathPattern.exec(rest); + if (simplePath) { + this.path = rest; + this.href = rest; + this.pathname = simplePath[1]; + if (simplePath[2]) { + this.search = simplePath[2]; + if (parseQueryString) { + this.query = querystring.parse(this.search.substr(1)); + } else { + this.query = this.search.substr(1); + } + } else if (parseQueryString) { + this.search = ''; + this.query = {}; + } + return this; + } + } + + var proto = protocolPattern.exec(rest); + if (proto) { + proto = proto[0]; + var lowerProto = proto.toLowerCase(); + this.protocol = lowerProto; + rest = rest.substr(proto.length); + } + + // figure out if it's got a host + // user@server is *always* interpreted as a hostname, and url + // resolution will treat //foo/bar as host=foo,path=bar because that's + // how the browser resolves relative URLs. + if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) { + var slashes = rest.substr(0, 2) === '//'; + if (slashes && !(proto && hostlessProtocol[proto])) { + rest = rest.substr(2); + this.slashes = true; + } + } + + if (!hostlessProtocol[proto] && + (slashes || (proto && !slashedProtocol[proto]))) { + + // there's a hostname. + // the first instance of /, ?, ;, or # ends the host. + // + // If there is an @ in the hostname, then non-host chars *are* allowed + // to the left of the last @ sign, unless some host-ending character + // comes *before* the @-sign. + // URLs are obnoxious. + // + // ex: + // http://a@b@c/ => user:a@b host:c + // http://a@b?@c => user:a host:c path:/?@c + + // v0.12 TODO(isaacs): This is not quite how Chrome does things. + // Review our test case against browsers more comprehensively. + + // find the first instance of any hostEndingChars + var hostEnd = -1; + for (var i = 0; i < hostEndingChars.length; i++) { + var hec = rest.indexOf(hostEndingChars[i]); + if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) + hostEnd = hec; + } + + // at this point, either we have an explicit point where the + // auth portion cannot go past, or the last @ char is the decider. + var auth, atSign; + if (hostEnd === -1) { + // atSign can be anywhere. + atSign = rest.lastIndexOf('@'); + } else { + // atSign must be in auth portion. + // http://a@b/c@d => host:b auth:a path:/c@d + atSign = rest.lastIndexOf('@', hostEnd); + } + + // Now we have a portion which is definitely the auth. + // Pull that off. + if (atSign !== -1) { + auth = rest.slice(0, atSign); + rest = rest.slice(atSign + 1); + this.auth = decodeURIComponent(auth); + } + + // the host is the remaining to the left of the first non-host char + hostEnd = -1; + for (var i = 0; i < nonHostChars.length; i++) { + var hec = rest.indexOf(nonHostChars[i]); + if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) + hostEnd = hec; + } + // if we still have not hit it, then the entire thing is a host. + if (hostEnd === -1) + hostEnd = rest.length; + + this.host = rest.slice(0, hostEnd); + rest = rest.slice(hostEnd); + + // pull out port. + this.parseHost(); + + // we've indicated that there is a hostname, + // so even if it's empty, it has to be present. + this.hostname = this.hostname || ''; + + // if hostname begins with [ and ends with ] + // assume that it's an IPv6 address. + var ipv6Hostname = this.hostname[0] === '[' && + this.hostname[this.hostname.length - 1] === ']'; + + // validate a little. + if (!ipv6Hostname) { + var hostparts = this.hostname.split(/\./); + for (var i = 0, l = hostparts.length; i < l; i++) { + var part = hostparts[i]; + if (!part) continue; + if (!part.match(hostnamePartPattern)) { + var newpart = ''; + for (var j = 0, k = part.length; j < k; j++) { + if (part.charCodeAt(j) > 127) { + // we replace non-ASCII char with a temporary placeholder + // we need this to make sure size of hostname is not + // broken by replacing non-ASCII by nothing + newpart += 'x'; + } else { + newpart += part[j]; + } + } + // we test again with ASCII char only + if (!newpart.match(hostnamePartPattern)) { + var validParts = hostparts.slice(0, i); + var notHost = hostparts.slice(i + 1); + var bit = part.match(hostnamePartStart); + if (bit) { + validParts.push(bit[1]); + notHost.unshift(bit[2]); + } + if (notHost.length) { + rest = '/' + notHost.join('.') + rest; + } + this.hostname = validParts.join('.'); + break; + } + } + } + } + + if (this.hostname.length > hostnameMaxLen) { + this.hostname = ''; + } else { + // hostnames are always lower case. + this.hostname = this.hostname.toLowerCase(); + } + + if (!ipv6Hostname) { + // IDNA Support: Returns a punycoded representation of "domain". + // It only converts parts of the domain name that + // have non-ASCII characters, i.e. it doesn't matter if + // you call it with a domain that already is ASCII-only. + this.hostname = punycode.toASCII(this.hostname); + } + + var p = this.port ? ':' + this.port : ''; + var h = this.hostname || ''; + this.host = h + p; + this.href += this.host; + + // strip [ and ] from the hostname + // the host field still retains them, though + if (ipv6Hostname) { + this.hostname = this.hostname.substr(1, this.hostname.length - 2); + if (rest[0] !== '/') { + rest = '/' + rest; + } + } + } - q.paused = false; + // now rest is set to the post-host stuff. + // chop off any delim chars. + if (!unsafeProtocol[lowerProto]) { - // Need to call q.process once per concurrent - // worker to preserve full concurrency after pause - for (var w = 1; w <= q.concurrency; w++) { - q.process(); - } - } - }; + // First, make 100% sure that any "autoEscape" chars get + // escaped, even if encodeURIComponent doesn't think they + // need to be. + for (var i = 0, l = autoEscape.length; i < l; i++) { + var ae = autoEscape[i]; + if (rest.indexOf(ae) === -1) + continue; + var esc = encodeURIComponent(ae); + if (esc === ae) { + esc = escape(ae); + } + rest = rest.split(ae).join(esc); + } + } - function _insert(data, insertAtFront, callback) { - if (callback != null && typeof callback !== 'function') { // eslint-disable-line no-eq-null,eqeqeq - throw new Error('task callback must be a function'); - } - q.started = true; + // chop off from the tail first. + var hash = rest.indexOf('#'); + if (hash !== -1) { + // got a fragment string. + this.hash = rest.substr(hash); + rest = rest.slice(0, hash); + } + var qm = rest.indexOf('?'); + if (qm !== -1) { + this.search = rest.substr(qm); + this.query = rest.substr(qm + 1); + if (parseQueryString) { + this.query = querystring.parse(this.query); + } + rest = rest.slice(0, qm); + } else if (parseQueryString) { + // no query string, but parseQueryString still requested + this.search = ''; + this.query = {}; + } + if (rest) this.pathname = rest; + if (slashedProtocol[lowerProto] && + this.hostname && !this.pathname) { + this.pathname = '/'; + } - if (data == null && q.idle()) { // eslint-disable-line no-eq-null,eqeqeq - // call drain immediately if there are no tasks - setTimeout(function () { - q.drain(); - }, 1); + //to support http.request + if (this.pathname || this.search) { + var p = this.pathname || ''; + var s = this.search || ''; + this.path = p + s; + } - return; - } + // finally, reconstruct the href based on what has been validated. + this.href = this.format(); + return this; +}; - var item = { - data: data, - callback: typeof callback === 'function' ? callback : _noop - }; +// format a parsed object into a url string +function urlFormat(obj) { + // ensure it's an object, and not a string url. + // If it's an obj, this is a no-op. + // this way, you can call url_format() on strings + // to clean up potentially wonky urls. + if (util.isString(obj)) obj = urlParse(obj); + if (!(obj instanceof Url)) return Url.prototype.format.call(obj); + return obj.format(); +} - if (insertAtFront) { - q._tasks.unshift(item); - } - else { - q._tasks.push(item); - } +Url.prototype.format = function() { + var auth = this.auth || ''; + if (auth) { + auth = encodeURIComponent(auth); + auth = auth.replace(/%3A/i, ':'); + auth += '@'; + } - setTimeout(function () { - q.process(); - }, 1); + var protocol = this.protocol || '', + pathname = this.pathname || '', + hash = this.hash || '', + host = false, + query = ''; + + if (this.host) { + host = auth + this.host; + } else if (this.hostname) { + host = auth + (this.hostname.indexOf(':') === -1 ? + this.hostname : + '[' + this.hostname + ']'); + if (this.port) { + host += ':' + this.port; } + } - function _next(task) { - return function () { - workers -= 1; + if (this.query && + util.isObject(this.query) && + Object.keys(this.query).length) { + query = querystring.stringify(this.query); + } - task.callback.apply(task, arguments); + var search = this.search || (query && ('?' + query)) || ''; - if (arguments[0] != null) { // eslint-disable-line no-eq-null,eqeqeq - q.error(arguments[0], task.data); - } + if (protocol && protocol.substr(-1) !== ':') protocol += ':'; - if (workers <= (q.concurrency - q.buffer)) { - q.unsaturated(); - } + // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. + // unless they had them to begin with. + if (this.slashes || + (!protocol || slashedProtocol[protocol]) && host !== false) { + host = '//' + (host || ''); + if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname; + } else if (!host) { + host = ''; + } - if (q.idle()) { - q.drain(); - } + if (hash && hash.charAt(0) !== '#') hash = '#' + hash; + if (search && search.charAt(0) !== '?') search = '?' + search; - q.process(); - }; - } + pathname = pathname.replace(/[?#]/g, function(match) { + return encodeURIComponent(match); + }); + search = search.replace('#', '%23'); - return q; + return protocol + host + pathname + search + hash; +}; + +function urlResolve(source, relative) { + return urlParse(source, false, true).resolve(relative); } -},{}],34:[function(require,module,exports){ -/* eslint no-magic-numbers: 0 */ -'use strict'; +Url.prototype.resolve = function(relative) { + return this.resolveObject(urlParse(relative, false, true)).format(); +}; -module.exports = { - // private property - _keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', - - encodeBinary: function (input) { - var output = ''; - var bytebuffer; - var encodedCharIndexes = new Array(4); - var inx = 0; - var jnx = 0; - var paddingBytes = 0; - - while (inx < input.length) { - // Fill byte buffer array - bytebuffer = new Array(3); - - for (jnx = 0; jnx < bytebuffer.length; jnx++) { - if (inx < input.length) { - // throw away high-order byte, as documented at: - // https://developer.mozilla.org/En/Using_XMLHttpRequest#Handling_binary_data - bytebuffer[jnx] = input.charCodeAt(inx++) & 0xff; - } - else { - bytebuffer[jnx] = 0; - } - } +function urlResolveObject(source, relative) { + if (!source) return relative; + return urlParse(source, false, true).resolveObject(relative); +} - // Get each encoded character, 6 bits at a time - // index 1: first 6 bits - encodedCharIndexes[0] = bytebuffer[0] >> 2; - // index 2: second 6 bits (2 least significant bits from input byte 1 + 4 most significant bits from byte 2) - encodedCharIndexes[1] = ((bytebuffer[0] & 0x3) << 4) | (bytebuffer[1] >> 4); - // index 3: third 6 bits (4 least significant bits from input byte 2 + 2 most significant bits from byte 3) - encodedCharIndexes[2] = ((bytebuffer[1] & 0x0f) << 2) | (bytebuffer[2] >> 6); - // index 3: forth 6 bits (6 least significant bits from input byte 3) - encodedCharIndexes[3] = bytebuffer[2] & 0x3f; - - // Determine whether padding happened, and adjust accordingly - paddingBytes = inx - (input.length - 1); - switch (paddingBytes) { - case 2: - // Set last 2 characters to padding char - encodedCharIndexes[3] = 64; - encodedCharIndexes[2] = 64; - break; +Url.prototype.resolveObject = function(relative) { + if (util.isString(relative)) { + var rel = new Url(); + rel.parse(relative, false, true); + relative = rel; + } - case 1: - // Set last character to padding char - encodedCharIndexes[3] = 64; - break; + var result = new Url(); + var tkeys = Object.keys(this); + for (var tk = 0; tk < tkeys.length; tk++) { + var tkey = tkeys[tk]; + result[tkey] = this[tkey]; + } - default: - break; // No padding - proceed - } + // hash is always overridden, no matter what. + // even href="" will remove it. + result.hash = relative.hash; - // Now we will grab each appropriate character out of our keystring - // based on our index array and append it to the output string - for (jnx = 0; jnx < encodedCharIndexes.length; jnx++) { - output += this._keyStr.charAt(encodedCharIndexes[jnx]); - } - } + // if the relative url is empty, then there's nothing left to do here. + if (relative.href === '') { + result.href = result.format(); + return result; + } - return output; + // hrefs like //foo/bar always cut to the protocol. + if (relative.slashes && !relative.protocol) { + // take everything except the protocol from relative + var rkeys = Object.keys(relative); + for (var rk = 0; rk < rkeys.length; rk++) { + var rkey = rkeys[rk]; + if (rkey !== 'protocol') + result[rkey] = relative[rkey]; } -}; - -},{}],35:[function(require,module,exports){ -/* eslint global-require: 0 */ -'use strict'; -module.exports = require('./Loader'); -module.exports.Resource = require('./Resource'); -module.exports.middleware = { - caching: { - memory: require('./middlewares/caching/memory') - }, - parsing: { - blob: require('./middlewares/parsing/blob') + //urlParse appends trailing / to urls like http://www.example.com + if (slashedProtocol[result.protocol] && + result.hostname && !result.pathname) { + result.path = result.pathname = '/'; } -}; - -module.exports.async = require('./async'); -},{"./Loader":31,"./Resource":32,"./async":33,"./middlewares/caching/memory":36,"./middlewares/parsing/blob":37}],36:[function(require,module,exports){ -'use strict'; - -// a simple in-memory cache for resources -var cache = {}; + result.href = result.format(); + return result; + } -module.exports = function () { - return function (resource, next) { - // if cached, then set data and complete the resource - if (cache[resource.url]) { - resource.data = cache[resource.url]; - resource.complete(); // marks resource load complete and stops processing before middlewares - } - // if not cached, wait for complete and store it in the cache. - else { - resource.once('complete', function () { - cache[this.url] = this.data; - }); - } + if (relative.protocol && relative.protocol !== result.protocol) { + // if it's a known url protocol, then changing + // the protocol does weird things + // first, if it's not file:, then we MUST have a host, + // and if there was a path + // to begin with, then we MUST have a path. + // if it is file:, then the host is dropped, + // because that's known to be hostless. + // anything else is assumed to be absolute. + if (!slashedProtocol[relative.protocol]) { + var keys = Object.keys(relative); + for (var v = 0; v < keys.length; v++) { + var k = keys[v]; + result[k] = relative[k]; + } + result.href = result.format(); + return result; + } - next(); - }; -}; + result.protocol = relative.protocol; + if (!relative.host && !hostlessProtocol[relative.protocol]) { + var relPath = (relative.pathname || '').split('/'); + while (relPath.length && !(relative.host = relPath.shift())); + if (!relative.host) relative.host = ''; + if (!relative.hostname) relative.hostname = ''; + if (relPath[0] !== '') relPath.unshift(''); + if (relPath.length < 2) relPath.unshift(''); + result.pathname = relPath.join('/'); + } else { + result.pathname = relative.pathname; + } + result.search = relative.search; + result.query = relative.query; + result.host = relative.host || ''; + result.auth = relative.auth; + result.hostname = relative.hostname || relative.host; + result.port = relative.port; + // to support http.request + if (result.pathname || result.search) { + var p = result.pathname || ''; + var s = result.search || ''; + result.path = p + s; + } + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; + } -},{}],37:[function(require,module,exports){ -'use strict'; + var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'), + isRelAbs = ( + relative.host || + relative.pathname && relative.pathname.charAt(0) === '/' + ), + mustEndAbs = (isRelAbs || isSourceAbs || + (result.host && relative.pathname)), + removeAllDots = mustEndAbs, + srcPath = result.pathname && result.pathname.split('/') || [], + relPath = relative.pathname && relative.pathname.split('/') || [], + psychotic = result.protocol && !slashedProtocol[result.protocol]; -var Resource = require('../../Resource'); -var b64 = require('../../b64'); + // if the url is a non-slashed url, then relative + // links like ../.. should be able + // to crawl up to the hostname, as well. This is strange. + // result.protocol has already been set by now. + // Later on, put the first path part into the host field. + if (psychotic) { + result.hostname = ''; + result.port = null; + if (result.host) { + if (srcPath[0] === '') srcPath[0] = result.host; + else srcPath.unshift(result.host); + } + result.host = ''; + if (relative.protocol) { + relative.hostname = null; + relative.port = null; + if (relative.host) { + if (relPath[0] === '') relPath[0] = relative.host; + else relPath.unshift(relative.host); + } + relative.host = null; + } + mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === ''); + } -var Url = window.URL || window.webkitURL; + if (isRelAbs) { + // it's absolute. + result.host = (relative.host || relative.host === '') ? + relative.host : result.host; + result.hostname = (relative.hostname || relative.hostname === '') ? + relative.hostname : result.hostname; + result.search = relative.search; + result.query = relative.query; + srcPath = relPath; + // fall through to the dot-handling below. + } else if (relPath.length) { + // it's relative + // throw away the existing file, and take the new path instead. + if (!srcPath) srcPath = []; + srcPath.pop(); + srcPath = srcPath.concat(relPath); + result.search = relative.search; + result.query = relative.query; + } else if (!util.isNullOrUndefined(relative.search)) { + // just pull out the search. + // like href='?foo'. + // Put this after the other two cases because it simplifies the booleans + if (psychotic) { + result.hostname = result.host = srcPath.shift(); + //occationaly the auth can get stuck only in host + //this especially happens in cases like + //url.resolveObject('mailto:local1@domain1', 'local2@domain2') + var authInHost = result.host && result.host.indexOf('@') > 0 ? + result.host.split('@') : false; + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); + } + } + result.search = relative.search; + result.query = relative.query; + //to support http.request + if (!util.isNull(result.pathname) || !util.isNull(result.search)) { + result.path = (result.pathname ? result.pathname : '') + + (result.search ? result.search : ''); + } + result.href = result.format(); + return result; + } -// a middleware for transforming XHR loaded Blobs into more useful objects + if (!srcPath.length) { + // no path at all. easy. + // we've already handled the other stuff above. + result.pathname = null; + //to support http.request + if (result.search) { + result.path = '/' + result.search; + } else { + result.path = null; + } + result.href = result.format(); + return result; + } -module.exports = function () { - return function (resource, next) { - if (!resource.data) { - next(); + // if a url ENDs in . or .., then it must get a trailing slash. + // however, if it ends in anything else non-slashy, + // then it must NOT get a trailing slash. + var last = srcPath.slice(-1)[0]; + var hasTrailingSlash = ( + (result.host || relative.host || srcPath.length > 1) && + (last === '.' || last === '..') || last === ''); - return; - } + // strip single dots, resolve double dots to parent dir + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = srcPath.length; i >= 0; i--) { + last = srcPath[i]; + if (last === '.') { + srcPath.splice(i, 1); + } else if (last === '..') { + srcPath.splice(i, 1); + up++; + } else if (up) { + srcPath.splice(i, 1); + up--; + } + } - // if this was an XHR load of a blob - if (resource.xhr && resource.xhrType === Resource.XHR_RESPONSE_TYPE.BLOB) { - // if there is no blob support we probably got a binary string back - if (!window.Blob || typeof resource.data === 'string') { - var type = resource.xhr.getResponseHeader('content-type'); + // if the path is allowed to go above the root, restore leading ..s + if (!mustEndAbs && !removeAllDots) { + for (; up--; up) { + srcPath.unshift('..'); + } + } - // this is an image, convert the binary string into a data url - if (type && type.indexOf('image') === 0) { - resource.data = new Image(); - resource.data.src = 'data:' + type + ';base64,' + b64.encodeBinary(resource.xhr.responseText); + if (mustEndAbs && srcPath[0] !== '' && + (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { + srcPath.unshift(''); + } - resource.isImage = true; + if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) { + srcPath.push(''); + } - // wait until the image loads and then callback - resource.data.onload = function () { - resource.data.onload = null; + var isAbsolute = srcPath[0] === '' || + (srcPath[0] && srcPath[0].charAt(0) === '/'); - next(); - }; + // put the host back + if (psychotic) { + result.hostname = result.host = isAbsolute ? '' : + srcPath.length ? srcPath.shift() : ''; + //occationaly the auth can get stuck only in host + //this especially happens in cases like + //url.resolveObject('mailto:local1@domain1', 'local2@domain2') + var authInHost = result.host && result.host.indexOf('@') > 0 ? + result.host.split('@') : false; + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); + } + } - // next will be called on load - return; - } - } - // if content type says this is an image, then we should transform the blob into an Image object - else if (resource.data.type.indexOf('image') === 0) { - var src = Url.createObjectURL(resource.data); + mustEndAbs = mustEndAbs || (result.host && srcPath.length); - resource.blob = resource.data; - resource.data = new Image(); - resource.data.src = src; + if (mustEndAbs && !isAbsolute) { + srcPath.unshift(''); + } - resource.isImage = true; + if (!srcPath.length) { + result.pathname = null; + result.path = null; + } else { + result.pathname = srcPath.join('/'); + } - // cleanup the no longer used blob after the image loads - resource.data.onload = function () { - Url.revokeObjectURL(src); - resource.data.onload = null; + //to support request.http + if (!util.isNull(result.pathname) || !util.isNull(result.search)) { + result.path = (result.pathname ? result.pathname : '') + + (result.search ? result.search : ''); + } + result.auth = relative.auth || result.auth; + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; +}; - next(); - }; +Url.prototype.parseHost = function() { + var host = this.host; + var port = portPattern.exec(host); + if (port) { + port = port[0]; + if (port !== ':') { + this.port = port.substr(1); + } + host = host.substr(0, host.length - port.length); + } + if (host) this.hostname = host; +}; - // next will be called on load. - return; - } - } +},{"./util":39,"punycode":27,"querystring":30}],39:[function(require,module,exports){ +'use strict'; - next(); - }; +module.exports = { + isString: function(arg) { + return typeof(arg) === 'string'; + }, + isObject: function(arg) { + return typeof(arg) === 'object' && arg !== null; + }, + isNull: function(arg) { + return arg === null; + }, + isNullOrUndefined: function(arg) { + return arg == null; + } }; -},{"../../Resource":32,"../../b64":34}],38:[function(require,module,exports){ +},{}],40:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -6688,7 +7336,7 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // add some extra variables to the container.. -Object.assign(core.DisplayObject.prototype, _accessibleTarget2.default); +core.utils.mixins.delayMixin(core.DisplayObject.prototype, _accessibleTarget2.default); var KEY_CODE_TAB = 9; @@ -6703,15 +7351,17 @@ var DIV_HOOK_POS_Y = -1000; var DIV_HOOK_ZINDEX = 2; /** - * The Accessibility manager reacreates the ability to tab and and have content read by screen + * The Accessibility manager recreates the ability to tab and have content read by screen * readers. This is very important as it can possibly help people with disabilities access pixi * content. * * Much like interaction any DisplayObject can be made accessible. This manager will map the - * events as if the mouse was being used, minimizing the efferot required to implement. + * events as if the mouse was being used, minimizing the effort required to implement. + * + * An instance of this class is automatically created by default, and can be found at renderer.plugins.accessibility * * @class - * @memberof PIXI + * @memberof PIXI.accessibility */ var AccessibilityManager = function () { @@ -6725,7 +7375,7 @@ var AccessibilityManager = function () { this.createTouchHook(); } - // first we create a div that will sit over the pixi element. This is where the div overlays will go. + // first we create a div that will sit over the PixiJS element. This is where the div overlays will go. var div = document.createElement('div'); div.style.width = DIV_TOUCH_SIZE + 'px'; @@ -6736,7 +7386,7 @@ var AccessibilityManager = function () { div.style.zIndex = DIV_TOUCH_ZINDEX; /** - * This is the dom element that will sit over the pixi element. This is where the div overlays will go. + * This is the dom element that will sit over the PixiJS element. This is where the div overlays will go. * * @type {HTMLElement} * @private @@ -6760,7 +7410,7 @@ var AccessibilityManager = function () { this.renderId = 0; /** - * Setting this to true will visually show the divs + * Setting this to true will visually show the divs. * * @type {boolean} */ @@ -6790,7 +7440,7 @@ var AccessibilityManager = function () { this._onMouseMove = this._onMouseMove.bind(this); /** - * stores the state of the manager. If there are no accessible objects or the mouse is moving the will be false. + * stores the state of the manager. If there are no accessible objects or the mouse is moving, this will be false. * * @member {Array<*>} * @private @@ -6833,7 +7483,7 @@ var AccessibilityManager = function () { /** * Activating will cause the Accessibility layer to be shown. This is called when a user - * preses the tab key + * preses the tab key. * * @private */ @@ -6858,7 +7508,7 @@ var AccessibilityManager = function () { /** * Deactivating will cause the Accessibility layer to be hidden. This is called when a user moves - * the mouse + * the mouse. * * @private */ @@ -6882,7 +7532,7 @@ var AccessibilityManager = function () { }; /** - * This recursive function will run throught he scene graph and add any new accessible objects to the DOM layer. + * This recursive function will run through the scene graph and add any new accessible objects to the DOM layer. * * @private * @param {PIXI.Container} displayObject - The DisplayObject to check. @@ -7072,7 +7722,7 @@ var AccessibilityManager = function () { }; /** - * Maps the div focus events to pixis InteractionManager (mouseover) + * Maps the div focus events to pixi's InteractionManager (mouseover) * * @private * @param {FocusEvent} e - The focus event. @@ -7086,7 +7736,7 @@ var AccessibilityManager = function () { }; /** - * Maps the div focus events to pixis InteractionManager (mouseout) + * Maps the div focus events to pixi's InteractionManager (mouseout) * * @private * @param {FocusEvent} e - The focusout event. @@ -7156,7 +7806,7 @@ exports.default = AccessibilityManager; core.WebGLRenderer.registerPlugin('accessibility', AccessibilityManager); core.CanvasRenderer.registerPlugin('accessibility', AccessibilityManager); -},{"../core":61,"./accessibleTarget":39,"ismobilejs":20}],39:[function(require,module,exports){ +},{"../core":65,"./accessibleTarget":41,"ismobilejs":21}],41:[function(require,module,exports){ "use strict"; exports.__esModule = true; @@ -7164,9 +7814,8 @@ exports.__esModule = true; * Default property values of accessible objects * used by {@link PIXI.accessibility.AccessibilityManager}. * - * @mixin - * @name accessibleTarget - * @memberof PIXI + * @function accessibleTarget + * @memberof PIXI.accessibility * @example * function MyObject() {} * @@ -7215,7 +7864,7 @@ exports.default = { _accessibleDiv: false }; -},{}],40:[function(require,module,exports){ +},{}],42:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -7240,32 +7889,259 @@ Object.defineProperty(exports, 'AccessibilityManager', { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -},{"./AccessibilityManager":38,"./accessibleTarget":39}],41:[function(require,module,exports){ +},{"./AccessibilityManager":40,"./accessibleTarget":41}],43:[function(require,module,exports){ 'use strict'; exports.__esModule = true; -var _pixiGlCore = require('pixi-gl-core'); +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _autoDetectRenderer = require('./autoDetectRenderer'); + +var _Container = require('./display/Container'); + +var _Container2 = _interopRequireDefault(_Container); + +var _ticker = require('./ticker'); + +var _settings = require('./settings'); + +var _settings2 = _interopRequireDefault(_settings); var _const = require('./const'); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Convenience class to create a new PIXI application. + * This class automatically creates the renderer, ticker + * and root container. + * + * @example + * // Create the application + * const app = new PIXI.Application(); + * + * // Add the view to the DOM + * document.body.appendChild(app.view); + * + * // ex, add display objects + * app.stage.addChild(PIXI.Sprite.fromImage('something.png')); + * + * @class + * @memberof PIXI + */ +var Application = function () { + // eslint-disable-next-line valid-jsdoc + /** + * @param {object} [options] - The optional renderer parameters + * @param {boolean} [options.autoStart=true] - automatically starts the rendering after the construction. + * Note that setting this parameter to false does NOT stop the shared ticker even if you set + * options.sharedTicker to true in case that it is already started. Stop it by your own. + * @param {number} [options.width=800] - the width of the renderers view + * @param {number} [options.height=600] - the height of the renderers view + * @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional + * @param {boolean} [options.transparent=false] - If the render view is transparent, default false + * @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment) + * @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you + * need to call toDataUrl on the webgl context + * @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2 + * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present + * @param {number} [options.backgroundColor=0x000000] - The background color of the rendered area + * (shown if not transparent). + * @param {boolean} [options.clearBeforeRender=true] - This sets if the renderer will clear the canvas or + * not before the new render pass. + * @param {boolean} [options.roundPixels=false] - If true PixiJS will Math.floor() x/y values when rendering, + * stopping pixel interpolation. + * @param {boolean} [options.forceFXAA=false] - forces FXAA antialiasing to be used over native. + * FXAA is faster, but may not always look as great **webgl only** + * @param {boolean} [options.legacy=false] - `true` to ensure compatibility with older / less advanced devices. + * If you experience unexplained flickering try setting this to true. **webgl only** + * @param {string} [options.powerPreference] - Parameter passed to webgl context, set to "high-performance" + * for devices with dual graphics card **webgl only** + * @param {boolean} [options.sharedTicker=false] - `true` to use PIXI.ticker.shared, `false` to create new ticker. + * @param {boolean} [options.sharedLoader=false] - `true` to use PIXI.loaders.shared, `false` to create new Loader. + */ + function Application(options, arg2, arg3, arg4, arg5) { + _classCallCheck(this, Application); + + // Support for constructor(width, height, options, noWebGL, useSharedTicker) + if (typeof options === 'number') { + options = Object.assign({ + width: options, + height: arg2 || _settings2.default.RENDER_OPTIONS.height, + forceCanvas: !!arg4, + sharedTicker: !!arg5 + }, arg3); + } + + /** + * The default options, so we mixin functionality later. + * @member {object} + * @protected + */ + this._options = options = Object.assign({ + autoStart: true, + sharedTicker: false, + forceCanvas: false, + sharedLoader: false + }, options); + + /** + * WebGL renderer if available, otherwise CanvasRenderer + * @member {PIXI.WebGLRenderer|PIXI.CanvasRenderer} + */ + this.renderer = (0, _autoDetectRenderer.autoDetectRenderer)(options); + + /** + * The root display container that's rendered. + * @member {PIXI.Container} + */ + this.stage = new _Container2.default(); + + /** + * Internal reference to the ticker + * @member {PIXI.ticker.Ticker} + * @private + */ + this._ticker = null; + + /** + * Ticker for doing render updates. + * @member {PIXI.ticker.Ticker} + * @default PIXI.ticker.shared + */ + this.ticker = options.sharedTicker ? _ticker.shared : new _ticker.Ticker(); + + // Start the rendering + if (options.autoStart) { + this.start(); + } + } + + /** + * Render the current stage. + */ + Application.prototype.render = function render() { + this.renderer.render(this.stage); + }; + + /** + * Convenience method for stopping the render. + */ + + + Application.prototype.stop = function stop() { + this._ticker.stop(); + }; + + /** + * Convenience method for starting the render. + */ + + + Application.prototype.start = function start() { + this._ticker.start(); + }; + + /** + * Reference to the renderer's canvas element. + * @member {HTMLCanvasElement} + * @readonly + */ + + + /** + * Destroy and don't use after this. + * @param {Boolean} [removeView=false] Automatically remove canvas from DOM. + */ + Application.prototype.destroy = function destroy(removeView) { + var oldTicker = this._ticker; + + this.ticker = null; + + oldTicker.destroy(); + + this.stage.destroy(); + this.stage = null; + + this.renderer.destroy(removeView); + this.renderer = null; + + this._options = null; + }; + + _createClass(Application, [{ + key: 'ticker', + set: function set(ticker) // eslint-disable-line require-jsdoc + { + if (this._ticker) { + this._ticker.remove(this.render, this); + } + this._ticker = ticker; + if (ticker) { + ticker.add(this.render, this, _const.UPDATE_PRIORITY.LOW); + } + }, + get: function get() // eslint-disable-line require-jsdoc + { + return this._ticker; + } + }, { + key: 'view', + get: function get() { + return this.renderer.view; + } + + /** + * Reference to the renderer's screen rectangle. Its safe to use as filterArea or hitArea for whole screen + * @member {PIXI.Rectangle} + * @readonly + */ + + }, { + key: 'screen', + get: function get() { + return this.renderer.screen; + } + }]); + + return Application; +}(); + +exports.default = Application; + +},{"./autoDetectRenderer":45,"./const":46,"./display/Container":48,"./settings":101,"./ticker":120}],44:[function(require,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _pixiGlCore = require('pixi-gl-core'); + +var _settings = require('./settings'); + +var _settings2 = _interopRequireDefault(_settings); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } -function checkPrecision(src) { +function checkPrecision(src, def) { if (src instanceof Array) { if (src[0].substring(0, 9) !== 'precision') { var copy = src.slice(0); - copy.unshift('precision ' + _const.PRECISION.DEFAULT + ' float;'); + copy.unshift('precision ' + def + ' float;'); return copy; } } else if (src.substring(0, 9) !== 'precision') { - return 'precision ' + _const.PRECISION.DEFAULT + ' float;\n' + src; + return 'precision ' + def + ' float;\n' + src; } return src; @@ -7292,7 +8168,7 @@ var Shader = function (_GLShader) { function Shader(gl, vertexSrc, fragmentSrc) { _classCallCheck(this, Shader); - return _possibleConstructorReturn(this, _GLShader.call(this, gl, checkPrecision(vertexSrc), checkPrecision(fragmentSrc))); + return _possibleConstructorReturn(this, _GLShader.call(this, gl, checkPrecision(vertexSrc, _settings2.default.PRECISION_VERTEX), checkPrecision(fragmentSrc, _settings2.default.PRECISION_FRAGMENT))); } return Shader; @@ -7300,27 +8176,89 @@ var Shader = function (_GLShader) { exports.default = Shader; -},{"./const":42,"pixi-gl-core":7}],42:[function(require,module,exports){ +},{"./settings":101,"pixi-gl-core":7}],45:[function(require,module,exports){ 'use strict'; exports.__esModule = true; -exports.SPRITE_MAX_TEXTURES = exports.SPRITE_BATCH_SIZE = exports.TEXT_GRADIENT = exports.TRANSFORM_MODE = exports.PRECISION = exports.SHAPES = exports.SVG_SIZE = exports.DATA_URI = exports.URL_FILE_EXTENSION = exports.DEFAULT_RENDER_OPTIONS = exports.FILTER_RESOLUTION = exports.RESOLUTION = exports.RETINA_PREFIX = exports.MIPMAP_TEXTURES = exports.GC_MODES = exports.WRAP_MODES = exports.SCALE_MODES = exports.DRAW_MODES = exports.BLEND_MODES = exports.RENDERER_TYPE = exports.TARGET_FPMS = exports.DEG_TO_RAD = exports.RAD_TO_DEG = exports.PI_2 = exports.VERSION = undefined; +exports.autoDetectRenderer = autoDetectRenderer; -var _maxRecommendedTextures = require('./utils/maxRecommendedTextures'); +var _utils = require('./utils'); -var _maxRecommendedTextures2 = _interopRequireDefault(_maxRecommendedTextures); +var utils = _interopRequireWildcard(_utils); + +var _CanvasRenderer = require('./renderers/canvas/CanvasRenderer'); + +var _CanvasRenderer2 = _interopRequireDefault(_CanvasRenderer); + +var _WebGLRenderer = require('./renderers/webgl/WebGLRenderer'); + +var _WebGLRenderer2 = _interopRequireDefault(_WebGLRenderer); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +// eslint-disable-next-line valid-jsdoc +/** + * This helper function will automatically detect which renderer you should be using. + * WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by + * the browser then this function will return a canvas renderer + * + * @memberof PIXI + * @function autoDetectRenderer + * @param {object} [options] - The optional renderer parameters + * @param {number} [options.width=800] - the width of the renderers view + * @param {number} [options.height=600] - the height of the renderers view + * @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional + * @param {boolean} [options.transparent=false] - If the render view is transparent, default false + * @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment) + * @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you + * need to call toDataUrl on the webgl context + * @param {number} [options.backgroundColor=0x000000] - The background color of the rendered area + * (shown if not transparent). + * @param {boolean} [options.clearBeforeRender=true] - This sets if the renderer will clear the canvas or + * not before the new render pass. + * @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2 + * @param {boolean} [options.forceCanvas=false] - prevents selection of WebGL renderer, even if such is present + * @param {boolean} [options.roundPixels=false] - If true PixiJS will Math.floor() x/y values when rendering, + * stopping pixel interpolation. + * @param {boolean} [options.forceFXAA=false] - forces FXAA antialiasing to be used over native. + * FXAA is faster, but may not always look as great **webgl only** + * @param {boolean} [options.legacy=false] - `true` to ensure compatibility with older / less advanced devices. + * If you experience unexplained flickering try setting this to true. **webgl only** + * @param {string} [options.powerPreference] - Parameter passed to webgl context, set to "high-performance" + * for devices with dual graphics card **webgl only** + * @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer + */ +function autoDetectRenderer(options, arg1, arg2, arg3) { + // Backward-compatible support for noWebGL option + var forceCanvas = options && options.forceCanvas; + + if (arg3 !== undefined) { + forceCanvas = arg3; + } + + if (!forceCanvas && utils.isWebGLSupported()) { + return new _WebGLRenderer2.default(options, arg1, arg2); + } + + return new _CanvasRenderer2.default(options, arg1, arg2); +} + +},{"./renderers/canvas/CanvasRenderer":77,"./renderers/webgl/WebGLRenderer":84,"./utils":124}],46:[function(require,module,exports){ +'use strict'; + +exports.__esModule = true; /** * String of the current PIXI version. * * @static * @constant * @memberof PIXI + * @name VERSION * @type {string} */ -var VERSION = exports.VERSION = '4.0.3'; +var VERSION = exports.VERSION = '4.5.4'; /** * Two Pi. @@ -7352,23 +8290,13 @@ var RAD_TO_DEG = exports.RAD_TO_DEG = 180 / Math.PI; */ var DEG_TO_RAD = exports.DEG_TO_RAD = Math.PI / 180; -/** - * Target frames per millisecond. - * - * @static - * @constant - * @memberof PIXI - * @type {number} - * @default 0.06 - */ -var TARGET_FPMS = exports.TARGET_FPMS = 0.06; - /** * Constant to identify the Renderer Type. * * @static * @constant * @memberof PIXI + * @name RENDERER_TYPE * @type {object} * @property {number} UNKNOWN - Unknown render type. * @property {number} WEBGL - WebGL render type. @@ -7389,6 +8317,7 @@ var RENDERER_TYPE = exports.RENDERER_TYPE = { * @static * @constant * @memberof PIXI + * @name BLEND_MODES * @type {object} * @property {number} NORMAL * @property {number} ADD @@ -7425,7 +8354,10 @@ var BLEND_MODES = exports.BLEND_MODES = { HUE: 13, SATURATION: 14, COLOR: 15, - LUMINOSITY: 16 + LUMINOSITY: 16, + NORMAL_NPM: 17, + ADD_NPM: 18, + SCREEN_NPM: 19 }; /** @@ -7435,6 +8367,7 @@ var BLEND_MODES = exports.BLEND_MODES = { * @static * @constant * @memberof PIXI + * @name DRAW_MODES * @type {object} * @property {number} POINTS * @property {number} LINES @@ -7457,19 +8390,18 @@ var DRAW_MODES = exports.DRAW_MODES = { /** * The scale modes that are supported by pixi. * - * The DEFAULT scale mode affects the default scaling mode of future operations. + * The {@link PIXI.settings.SCALE_MODE} scale mode affects the default scaling mode of future operations. * It can be re-assigned to either LINEAR or NEAREST, depending upon suitability. * * @static * @constant * @memberof PIXI + * @name SCALE_MODES * @type {object} - * @property {number} DEFAULT=LINEAR * @property {number} LINEAR Smooth scaling * @property {number} NEAREST Pixelating scaling */ var SCALE_MODES = exports.SCALE_MODES = { - DEFAULT: 0, LINEAR: 0, NEAREST: 1 }; @@ -7477,7 +8409,7 @@ var SCALE_MODES = exports.SCALE_MODES = { /** * The wrap modes that are supported by pixi. * - * The DEFAULT wrap mode affects the default wraping mode of future operations. + * The {@link PIXI.settings.WRAP_MODE} wrap mode affects the default wraping mode of future operations. * It can be re-assigned to either CLAMP or REPEAT, depending upon suitability. * If the texture is non power of two then clamp will be used regardless as webGL can * only use REPEAT if the texture is po2. @@ -7486,15 +8418,14 @@ var SCALE_MODES = exports.SCALE_MODES = { * * @static * @constant + * @name WRAP_MODES * @memberof PIXI * @type {object} - * @property {number} DEFAULT=CLAMP * @property {number} CLAMP - The textures uvs are clamped * @property {number} REPEAT - The texture uvs tile and repeat * @property {number} MIRRORED_REPEAT - The texture uvs tile and repeat with mirroring */ var WRAP_MODES = exports.WRAP_MODES = { - DEFAULT: 0, CLAMP: 0, REPEAT: 1, MIRRORED_REPEAT: 2 @@ -7503,8 +8434,8 @@ var WRAP_MODES = exports.WRAP_MODES = { /** * The gc modes that are supported by pixi. * - * The DEFAULT Garbage Collection mode for pixi textures is MANUAL - * If set to DEFAULT, the renderer will occasianally check textures usage. If they are not + * The {@link PIXI.settings.GC_MODE} Garbage Collection mode for PixiJS textures is AUTO + * If set to GC_MODE, the renderer will occasionally check textures usage. If they are not * used for a specified period of time they will be removed from the GPU. They will of course * be uploaded again when they are required. This is a silent behind the scenes process that * should ensure that the GPU does not get filled up. @@ -7514,91 +8445,17 @@ var WRAP_MODES = exports.WRAP_MODES = { * * @static * @constant + * @name GC_MODES * @memberof PIXI * @type {object} - * @property {number} DEFAULT=MANUAL * @property {number} AUTO - Garbage collection will happen periodically automatically * @property {number} MANUAL - Garbage collection will need to be called manually */ var GC_MODES = exports.GC_MODES = { - DEFAULT: 0, AUTO: 0, MANUAL: 1 }; -/** - * If set to true WebGL will attempt make textures mimpaped by default. - * Mipmapping will only succeed if the base texture uploaded has power of two dimensions. - * - * @static - * @constant - * @memberof PIXI - * @type {boolean} - */ -var MIPMAP_TEXTURES = exports.MIPMAP_TEXTURES = true; - -/** - * The prefix that denotes a URL is for a retina asset. - * - * @static - * @constant - * @memberof PIXI - * @type {RegExp|string} - * @example `@2x` - */ -var RETINA_PREFIX = exports.RETINA_PREFIX = /@(.+)x/; - -/** - * Default resolution / device pixel ratio of the renderer. - * - * @static - * @constant - * @memberof PIXI - * @type {number} - */ -var RESOLUTION = exports.RESOLUTION = 1; - -/** - * Default filter resolution. - * - * @static - * @constant - * @type {number} - */ -var FILTER_RESOLUTION = exports.FILTER_RESOLUTION = 1; - -/** - * The default render options if none are supplied to {@link PIXI.WebGLRenderer} - * or {@link PIXI.CanvasRenderer}. - * - * @static - * @constant - * @memberof PIXI - * @type {object} - * @property {HTMLCanvasElement} view=null - * @property {number} resolution=1 - * @property {boolean} antialias=false - * @property {boolean} forceFXAA=false - * @property {boolean} autoResize=false - * @property {boolean} transparent=false - * @property {number} backgroundColor=0x000000 - * @property {boolean} clearBeforeRender=true - * @property {boolean} preserveDrawingBuffer=false - * @property {boolean} roundPixels=false - */ -var DEFAULT_RENDER_OPTIONS = exports.DEFAULT_RENDER_OPTIONS = { - view: null, - resolution: 1, - antialias: false, - forceFXAA: false, - autoResize: false, - transparent: false, - backgroundColor: 0x000000, - clearBeforeRender: true, - preserveDrawingBuffer: false, - roundPixels: false -}; - /** * Regexp for image type by extension. * @@ -7612,13 +8469,14 @@ var URL_FILE_EXTENSION = exports.URL_FILE_EXTENSION = /\.(\w{3,4})(?:$|\?|#)/i; /** * Regexp for data URI. - * Based on: https://github.com/ragingwind/data-uri-regex + * Based on: {@link https://github.com/ragingwind/data-uri-regex} * * @static * @constant + * @name DATA_URI * @memberof PIXI * @type {RegExp|string} - * @example `data:image/png;base64` + * @example data:image/png;base64 */ var DATA_URI = exports.DATA_URI = /^\s*data:(?:([\w-]+)\/([\w+.-]+))?(?:;(charset=[\w-]+|base64))?,(.*)/i; @@ -7627,24 +8485,26 @@ var DATA_URI = exports.DATA_URI = /^\s*data:(?:([\w-]+)\/([\w+.-]+))?(?:;(charse * * @static * @constant + * @name SVG_SIZE * @memberof PIXI * @type {RegExp|string} - * @example `` + * @example <svg width="100" height="100"></svg> */ -var SVG_SIZE = exports.SVG_SIZE = /]*(?:\s(width|height)="(\d*(?:\.\d+)?)(?:px)?")[^>]*(?:\s(width|height)="(\d*(?:\.\d+)?)(?:px)?")[^>]*>/i; // eslint-disable-line max-len +var SVG_SIZE = exports.SVG_SIZE = /]*(?:\s(width|height)=('|")(\d*(?:\.\d+)?)(?:px)?('|"))[^>]*(?:\s(width|height)=('|")(\d*(?:\.\d+)?)(?:px)?('|"))[^>]*>/i; // eslint-disable-line max-len /** * Constants that identify shapes, mainly to prevent `instanceof` calls. * * @static * @constant + * @name SHAPES * @memberof PIXI * @type {object} - * @property {number} POLY - * @property {number} RECT - * @property {number} CIRC - * @property {number} ELIP - * @property {number} RREC + * @property {number} POLY Polygon + * @property {number} RECT Rectangle + * @property {number} CIRC Circle + * @property {number} ELIP Ellipse + * @property {number} RREC Rounded Rectangle */ var SHAPES = exports.SHAPES = { POLY: 0, @@ -7659,15 +8519,14 @@ var SHAPES = exports.SHAPES = { * * @static * @constant + * @name PRECISION * @memberof PIXI * @type {object} - * @property {number} DEFAULT='mediump' - * @property {number} LOW='lowp' - * @property {number} MEDIUM='mediump' - * @property {number} HIGH='highp' + * @property {string} LOW='lowp' + * @property {string} MEDIUM='mediump' + * @property {string} HIGH='highp' */ var PRECISION = exports.PRECISION = { - DEFAULT: 'mediump', LOW: 'lowp', MEDIUM: 'mediump', HIGH: 'highp' @@ -7678,14 +8537,13 @@ var PRECISION = exports.PRECISION = { * * @static * @constant + * @name TRANSFORM_MODE * @memberof PIXI * @type {object} - * @property {number} DEFAULT=STATIC * @property {number} STATIC * @property {number} DYNAMIC */ var TRANSFORM_MODE = exports.TRANSFORM_MODE = { - DEFAULT: 0, STATIC: 0, DYNAMIC: 1 }; @@ -7695,43 +8553,42 @@ var TRANSFORM_MODE = exports.TRANSFORM_MODE = { * * @static * @constant + * @name TEXT_GRADIENT * @memberof PIXI * @type {object} - * @property {number} LINEAR_VERTICAL - * @property {number} LINEAR_HORIZONTAL + * @property {number} LINEAR_VERTICAL Vertical gradient + * @property {number} LINEAR_HORIZONTAL Linear gradient */ var TEXT_GRADIENT = exports.TEXT_GRADIENT = { LINEAR_VERTICAL: 0, LINEAR_HORIZONTAL: 1 }; -// TODO: maybe change to SPRITE.BATCH_SIZE: 2000 -// TODO: maybe add PARTICLE.BATCH_SIZE: 15000 - /** - * The default sprite batch size. - * - * The default aims to balance desktop and mobile devices. - * - * @static - * @constant - * @memberof PIXI - * @type {number} - * @default 4096 - */ -var SPRITE_BATCH_SIZE = exports.SPRITE_BATCH_SIZE = 4096; - -/** - * The maximum textures that this device supports. + * Represents the update priorities used by internal PIXI classes when registered with + * the {@link PIXI.ticker.Ticker} object. Higher priority items are updated first and lower + * priority items, such as render, should go later. * * @static * @constant + * @name UPDATE_PRIORITY * @memberof PIXI - * @type {number} - */ -var SPRITE_MAX_TEXTURES = exports.SPRITE_MAX_TEXTURES = (0, _maxRecommendedTextures2.default)(32); + * @type {object} + * @property {number} INTERACTION=50 Highest priority, used for {@link PIXI.interaction.InteractionManager} + * @property {number} HIGH=25 High priority updating, {@link PIXI.VideoBaseTexture} and {@link PIXI.extras.AnimatedSprite} + * @property {number} NORMAL=0 Default priority for ticker events, see {@link PIXI.ticker.Ticker#add}. + * @property {number} LOW=-25 Low priority used for {@link PIXI.Application} rendering. + * @property {number} UTILITY=-50 Lowest priority used for {@link PIXI.prepare.BasePrepare} utility. + */ +var UPDATE_PRIORITY = exports.UPDATE_PRIORITY = { + INTERACTION: 50, + HIGH: 25, + NORMAL: 0, + LOW: -25, + UTILITY: -50 +}; -},{"./utils/maxRecommendedTextures":116}],43:[function(require,module,exports){ +},{}],47:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -8074,7 +8931,7 @@ var Bounds = function () { exports.default = Bounds; -},{"../math":66}],44:[function(require,module,exports){ +},{"../math":70}],48:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -8141,42 +8998,46 @@ var Container = function (_DisplayObject) { /** - * Adds a child or multiple children to the container. + * Adds one or more children to the container. * - * Multple items can be added like so: `myContainer.addChild(thinkOne, thingTwo, thingThree)` + * Multiple items can be added like so: `myContainer.addChild(thingOne, thingTwo, thingThree)` * * @param {...PIXI.DisplayObject} child - The DisplayObject(s) to add to the container * @return {PIXI.DisplayObject} The first child that was added. */ ; - Container.prototype.addChild = function addChild() { - for (var _len = arguments.length, childs = Array(_len), _key = 0; _key < _len; _key++) { - childs[_key] = arguments[_key]; - } - - for (var i = 0; i < childs.length; ++i) { - var child = childs[i]; + Container.prototype.addChild = function addChild(child) { + var argumentsLength = arguments.length; - // if the child has a parent then lets remove it as Pixi objects can only exist in one place + // if there is only one argument we can bypass looping through the them + if (argumentsLength > 1) { + // loop through the arguments property and add all children + // use it the right way (.length and [i]) so that this function can still be optimised by JS runtimes + for (var i = 0; i < argumentsLength; i++) { + this.addChild(arguments[i]); + } + } else { + // if the child has a parent then lets remove it as PixiJS objects can only exist in one place if (child.parent) { child.parent.removeChild(child); } child.parent = this; - - // ensure a transform will be recalculated.. - this.transform._parentID = -1; - this._boundsID++; + // ensure child transform will be recalculated + child.transform._parentID = -1; this.children.push(child); + // ensure bounds will be recalculated + this._boundsID++; + // TODO - lets either do all callbacks or all events.. not both! this.onChildrenChange(this.children.length - 1); child.emit('added', this); } - return childs[0]; + return child; }; /** @@ -8198,9 +9059,14 @@ var Container = function (_DisplayObject) { } child.parent = this; + // ensure child transform will be recalculated + child.transform._parentID = -1; this.children.splice(index, 0, child); + // ensure bounds will be recalculated + this._boundsID++; + // TODO - lets either do all callbacks or all events.. not both! this.onChildrenChange(index); child.emit('added', this); @@ -8264,6 +9130,7 @@ var Container = function (_DisplayObject) { (0, _utils.removeItems)(this.children, currentIndex, 1); // remove from old position this.children.splice(index, 0, child); // add at new position + this.onChildrenChange(index); }; @@ -8284,33 +9151,42 @@ var Container = function (_DisplayObject) { }; /** - * Removes a child from the container. + * Removes one or more children from the container. * - * @param {...PIXI.DisplayObject} childs - The DisplayObject(s) to remove + * @param {...PIXI.DisplayObject} child - The DisplayObject(s) to remove * @return {PIXI.DisplayObject} The first child that was removed. */ - Container.prototype.removeChild = function removeChild() { - for (var _len2 = arguments.length, childs = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - childs[_key2] = arguments[_key2]; - } + Container.prototype.removeChild = function removeChild(child) { + var argumentsLength = arguments.length; - for (var i = 0; i < childs.length; ++i) { - var child = childs[i]; + // if there is only one argument we can bypass looping through the them + if (argumentsLength > 1) { + // loop through the arguments property and add all children + // use it the right way (.length and [i]) so that this function can still be optimised by JS runtimes + for (var i = 0; i < argumentsLength; i++) { + this.removeChild(arguments[i]); + } + } else { var index = this.children.indexOf(child); - if (index === -1) continue; + if (index === -1) return null; child.parent = null; + // ensure child transform will be recalculated + child.transform._parentID = -1; (0, _utils.removeItems)(this.children, index, 1); + // ensure bounds will be recalculated + this._boundsID++; + // TODO - lets either do all callbacks or all events.. not both! this.onChildrenChange(index); child.emit('removed', this); } - return childs[0]; + return child; }; /** @@ -8324,9 +9200,14 @@ var Container = function (_DisplayObject) { Container.prototype.removeChildAt = function removeChildAt(index) { var child = this.getChildAt(index); + // ensure child transform will be recalculated.. child.parent = null; + child.transform._parentID = -1; (0, _utils.removeItems)(this.children, index, 1); + // ensure bounds will be recalculated + this._boundsID++; + // TODO - lets either do all callbacks or all events.. not both! this.onChildrenChange(index); child.emit('removed', this); @@ -8357,8 +9238,13 @@ var Container = function (_DisplayObject) { for (var i = 0; i < removed.length; ++i) { removed[i].parent = null; + if (removed[i].transform) { + removed[i].transform._parentID = -1; + } } + this._boundsID++; + this.onChildrenChange(beginIndex); for (var _i = 0; _i < removed.length; ++_i) { @@ -8375,8 +9261,6 @@ var Container = function (_DisplayObject) { /** * Updates the transform on all children of this container for rendering - * - * @private */ @@ -8477,7 +9361,7 @@ var Container = function (_DisplayObject) { Container.prototype.renderAdvancedWebGL = function renderAdvancedWebGL(renderer) { - renderer.currentRenderer.flush(); + renderer.flush(); var filters = this._filters; var mask = this._mask; @@ -8505,8 +9389,6 @@ var Container = function (_DisplayObject) { renderer.maskManager.pushMask(this, this._mask); } - renderer.currentRenderer.start(); - // add this object to the batch, only rendered if it has a texture. this._renderWebGL(renderer); @@ -8515,7 +9397,7 @@ var Container = function (_DisplayObject) { this.children[_i2].renderWebGL(renderer); } - renderer.currentRenderer.flush(); + renderer.flush(); if (mask) { renderer.maskManager.popMask(this, this._mask); @@ -8524,8 +9406,6 @@ var Container = function (_DisplayObject) { if (filters && this._enabledFilters && this._enabledFilters.length) { renderer.filterManager.popFilter(); } - - renderer.currentRenderer.start(); }; /** @@ -8563,7 +9443,7 @@ var Container = function (_DisplayObject) { Container.prototype.renderCanvas = function renderCanvas(renderer) { // if not visible or the alpha is 0 then no need to render this - if (!this.visible || this.alpha <= 0 || !this.renderable) { + if (!this.visible || this.worldAlpha <= 0 || !this.renderable) { return; } @@ -8589,6 +9469,10 @@ var Container = function (_DisplayObject) { * have been set to that value * @param {boolean} [options.children=false] - if set to true, all the children will have their destroy * method called as well. 'options' will be passed on to those calls. + * @param {boolean} [options.texture=false] - Only used for child Sprites if options.children is set to true + * Should it destroy the texture of the child sprite + * @param {boolean} [options.baseTexture=false] - Only used for child Sprites if options.children is set to true + * Should it destroy the base texture of the child sprite */ @@ -8610,7 +9494,6 @@ var Container = function (_DisplayObject) { * The width of the Container, setting this will actually modify the scale to achieve the value set * * @member {number} - * @memberof PIXI.Container# */ @@ -8618,15 +9501,9 @@ var Container = function (_DisplayObject) { key: 'width', get: function get() { return this.scale.x * this.getLocalBounds().width; - } - - /** - * Sets the width of the container by modifying the scale. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { var width = this.getLocalBounds().width; if (width !== 0) { @@ -8642,22 +9519,15 @@ var Container = function (_DisplayObject) { * The height of the Container, setting this will actually modify the scale to achieve the value set * * @member {number} - * @memberof PIXI.Container# */ }, { key: 'height', get: function get() { return this.scale.y * this.getLocalBounds().height; - } - - /** - * Sets the height of the container by modifying the scale. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { var height = this.getLocalBounds().height; if (height !== 0) { @@ -8679,7 +9549,7 @@ var Container = function (_DisplayObject) { exports.default = Container; Container.prototype.containerUpdateTransform = Container.prototype.updateTransform; -},{"../utils":115,"./DisplayObject":45}],45:[function(require,module,exports){ +},{"../utils":124,"./DisplayObject":49}],49:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -8692,6 +9562,10 @@ var _eventemitter2 = _interopRequireDefault(_eventemitter); var _const = require('../const'); +var _settings = require('../settings'); + +var _settings2 = _interopRequireDefault(_settings); + var _TransformStatic = require('./TransformStatic'); var _TransformStatic2 = _interopRequireDefault(_TransformStatic); @@ -8722,7 +9596,6 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" * * @class * @extends EventEmitter - * @mixes PIXI.interaction.interactiveTarget * @memberof PIXI */ var DisplayObject = function (_EventEmitter) { @@ -8736,7 +9609,7 @@ var DisplayObject = function (_EventEmitter) { var _this = _possibleConstructorReturn(this, _EventEmitter.call(this)); - var TransformClass = _const.TRANSFORM_MODE.DEFAULT === _const.TRANSFORM_MODE.STATIC ? _TransformStatic2.default : _Transform2.default; + var TransformClass = _settings2.default.TRANSFORM_MODE === _const.TRANSFORM_MODE.STATIC ? _TransformStatic2.default : _Transform2.default; _this.tempDisplayObjectParent = null; @@ -8820,10 +9693,33 @@ var DisplayObject = function (_EventEmitter) { /** * The original, cached mask of the object * - * @member {PIXI.Rectangle} + * @member {PIXI.Graphics|PIXI.Sprite} * @private */ _this._mask = null; + + /** + * If the object has been destroyed via destroy(). If true, it should not be used. + * + * @member {boolean} + * @private + * @readonly + */ + _this._destroyed = false; + + /** + * Fired when this DisplayObject is added to a Container. + * + * @event PIXI.DisplayObject#added + * @param {PIXI.Container} container - The container added to. + */ + + /** + * Fired when this DisplayObject is removed from a Container. + * + * @event PIXI.DisplayObject#removed + * @param {PIXI.Container} container - The container removed from. + */ return _this; } @@ -9042,7 +9938,7 @@ var DisplayObject = function (_EventEmitter) { }; /** - * Convenience function to set the postion, scale, skew and pivot at once. + * Convenience function to set the position, scale, skew and pivot at once. * * @param {number} [x=0] - The X position * @param {number} [y=0] - The Y position @@ -9107,6 +10003,8 @@ var DisplayObject = function (_EventEmitter) { this.interactive = false; this.interactiveChildren = false; + + this._destroyed = true; }; /** @@ -9114,7 +10012,6 @@ var DisplayObject = function (_EventEmitter) { * An alias to position.x * * @member {number} - * @memberof PIXI.DisplayObject# */ @@ -9131,15 +10028,9 @@ var DisplayObject = function (_EventEmitter) { key: 'x', get: function get() { return this.position.x; - } - - /** - * Sets the X position of the object. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.transform.position.x = value; } @@ -9148,22 +10039,15 @@ var DisplayObject = function (_EventEmitter) { * An alias to position.y * * @member {number} - * @memberof PIXI.DisplayObject# */ }, { key: 'y', get: function get() { return this.position.y; - } - - /** - * Sets the Y position of the object. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.transform.position.y = value; } @@ -9171,7 +10055,6 @@ var DisplayObject = function (_EventEmitter) { * Current transform of the object based on world (parent) factors * * @member {PIXI.Matrix} - * @memberof PIXI.DisplayObject# * @readonly */ @@ -9185,7 +10068,6 @@ var DisplayObject = function (_EventEmitter) { * Current transform of the object based on local factors: position, scale, other stuff * * @member {PIXI.Matrix} - * @memberof PIXI.DisplayObject# * @readonly */ @@ -9200,22 +10082,15 @@ var DisplayObject = function (_EventEmitter) { * Assignment by value since pixi-v4. * * @member {PIXI.Point|PIXI.ObservablePoint} - * @memberof PIXI.DisplayObject# */ }, { key: 'position', get: function get() { return this.transform.position; - } - - /** - * Copies the point to the position of the object. - * - * @param {PIXI.Point} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.transform.position.copy(value); } @@ -9224,22 +10099,15 @@ var DisplayObject = function (_EventEmitter) { * Assignment by value since pixi-v4. * * @member {PIXI.Point|PIXI.ObservablePoint} - * @memberof PIXI.DisplayObject# */ }, { key: 'scale', get: function get() { return this.transform.scale; - } - - /** - * Copies the point to the scale of the object. - * - * @param {PIXI.Point} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.transform.scale.copy(value); } @@ -9248,22 +10116,15 @@ var DisplayObject = function (_EventEmitter) { * Assignment by value since pixi-v4. * * @member {PIXI.Point|PIXI.ObservablePoint} - * @memberof PIXI.DisplayObject# */ }, { key: 'pivot', get: function get() { return this.transform.pivot; - } - - /** - * Copies the point to the pivot of the object. - * - * @param {PIXI.Point} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.transform.pivot.copy(value); } @@ -9272,22 +10133,15 @@ var DisplayObject = function (_EventEmitter) { * Assignment by value since pixi-v4. * * @member {PIXI.ObservablePoint} - * @memberof PIXI.DisplayObject# */ }, { key: 'skew', get: function get() { return this.transform.skew; - } - - /** - * Copies the point to the skew of the object. - * - * @param {PIXI.Point} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.transform.skew.copy(value); } @@ -9295,30 +10149,22 @@ var DisplayObject = function (_EventEmitter) { * The rotation of the object in radians. * * @member {number} - * @memberof PIXI.DisplayObject# */ }, { key: 'rotation', get: function get() { return this.transform.rotation; - } - - /** - * Sets the rotation of the object. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.transform.rotation = value; } /** - * Indicates if the sprite is globally visible. + * Indicates if the object is globally visible. * * @member {boolean} - * @memberof PIXI.DisplayObject# * @readonly */ @@ -9347,22 +10193,15 @@ var DisplayObject = function (_EventEmitter) { * @todo For the moment, PIXI.CanvasRenderer doesn't support PIXI.Sprite as mask. * * @member {PIXI.Graphics|PIXI.Sprite} - * @memberof PIXI.DisplayObject# */ }, { key: 'mask', get: function get() { return this._mask; - } - - /** - * Sets the mask. - * - * @param {PIXI.Graphics|PIXI.Sprite} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { if (this._mask) { this._mask.renderable = true; } @@ -9379,23 +10218,16 @@ var DisplayObject = function (_EventEmitter) { * * IMPORTANT: This is a webGL only feature and will be ignored by the canvas renderer. * To remove filters simply set this property to 'null' * - * @member {PIXI.AbstractFilter[]} - * @memberof PIXI.DisplayObject# + * @member {PIXI.Filter[]} */ }, { key: 'filters', get: function get() { return this._filters && this._filters.slice(); - } - - /** - * Shallow copies the array to the filters of the object. - * - * @param {PIXI.Filter[]} value - The filters to set. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._filters = value && value.slice(); } }]); @@ -9409,7 +10241,7 @@ var DisplayObject = function (_EventEmitter) { exports.default = DisplayObject; DisplayObject.prototype.displayObjectUpdateTransform = DisplayObject.prototype.updateTransform; -},{"../const":42,"../math":66,"./Bounds":43,"./Transform":46,"./TransformStatic":48,"eventemitter3":19}],46:[function(require,module,exports){ +},{"../const":46,"../math":70,"../settings":101,"./Bounds":47,"./Transform":50,"./TransformStatic":52,"eventemitter3":20}],50:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -9485,27 +10317,25 @@ var Transform = function (_TransformBase) { */ _this._rotation = 0; - _this._sr = Math.sin(0); - _this._cr = Math.cos(0); - _this._cy = Math.cos(0); // skewY); - _this._sy = Math.sin(0); // skewY); - _this._nsx = Math.sin(0); // skewX); - _this._cx = Math.cos(0); // skewX); + _this._cx = 1; // cos rotation + skewY; + _this._sx = 0; // sin rotation + skewY; + _this._cy = 0; // cos rotation + Math.PI/2 - skewX; + _this._sy = 1; // sin rotation + Math.PI/2 - skewX; return _this; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ Transform.prototype.updateSkew = function updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 }; /** @@ -9515,15 +10345,14 @@ var Transform = function (_TransformBase) { Transform.prototype.updateLocalTransform = function updateLocalTransform() { var lt = this.localTransform; - var a = this._cr * this.scale.x; - var b = this._sr * this.scale.x; - var c = -this._sr * this.scale.y; - var d = this._cr * this.scale.y; - - lt.a = this._cy * a + this._sy * c; - lt.b = this._cy * b + this._sy * d; - lt.c = this._nsx * a + this._cx * c; - lt.d = this._nsx * b + this._cx * d; + + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - (this.pivot.x * lt.a + this.pivot.y * lt.c); + lt.ty = this.position.y - (this.pivot.x * lt.b + this.pivot.y * lt.d); }; /** @@ -9534,24 +10363,20 @@ var Transform = function (_TransformBase) { Transform.prototype.updateTransform = function updateTransform(parentTransform) { - var pt = parentTransform.worldTransform; - var wt = this.worldTransform; var lt = this.localTransform; - var a = this._cr * this.scale.x; - var b = this._sr * this.scale.x; - var c = -this._sr * this.scale.y; - var d = this._cr * this.scale.y; - - lt.a = this._cy * a + this._sy * c; - lt.b = this._cy * b + this._sy * d; - lt.c = this._nsx * a + this._cx * c; - lt.d = this._nsx * b + this._cx * d; + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - (this.pivot.x * lt.a + this.pivot.y * lt.c); lt.ty = this.position.y - (this.pivot.x * lt.b + this.pivot.y * lt.d); // concat the parent matrix with the objects transform. + var pt = parentTransform.worldTransform; + var wt = this.worldTransform; + wt.a = lt.a * pt.a + lt.b * pt.c; wt.b = lt.a * pt.b + lt.b * pt.d; wt.c = lt.c * pt.a + lt.d * pt.c; @@ -9577,7 +10402,6 @@ var Transform = function (_TransformBase) { * The rotation of the object in radians. * * @member {number} - * @memberof PIXI.Transform# */ @@ -9585,18 +10409,11 @@ var Transform = function (_TransformBase) { key: 'rotation', get: function get() { return this._rotation; - } - - /** - * Set the rotation of the transform. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } }]); @@ -9605,7 +10422,7 @@ var Transform = function (_TransformBase) { exports.default = Transform; -},{"../math":66,"./TransformBase":47}],47:[function(require,module,exports){ +},{"../math":70,"./TransformBase":51}],51:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -9692,7 +10509,7 @@ TransformBase.prototype.updateWorldTransform = TransformBase.prototype.updateTra TransformBase.IDENTITY = new TransformBase(); -},{"../math":66}],48:[function(require,module,exports){ +},{"../math":70}],52:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -9721,208 +10538,188 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" * @memberof PIXI */ var TransformStatic = function (_TransformBase) { - _inherits(TransformStatic, _TransformBase); - - /** - * - */ - function TransformStatic() { - _classCallCheck(this, TransformStatic); - - /** - * The coordinate of the object relative to the local coordinates of the parent. - * - * @member {PIXI.ObservablePoint} - */ - var _this = _possibleConstructorReturn(this, _TransformBase.call(this)); - - _this.position = new _math.ObservablePoint(_this.onChange, _this, 0, 0); + _inherits(TransformStatic, _TransformBase); /** - * The scale factor of the object. * - * @member {PIXI.ObservablePoint} */ - _this.scale = new _math.ObservablePoint(_this.onChange, _this, 1, 1); + function TransformStatic() { + _classCallCheck(this, TransformStatic); - /** - * The pivot point of the displayObject that it rotates around - * - * @member {PIXI.ObservablePoint} - */ - _this.pivot = new _math.ObservablePoint(_this.onChange, _this, 0, 0); - - /** - * The skew amount, on the x and y axis. - * - * @member {PIXI.ObservablePoint} - */ - _this.skew = new _math.ObservablePoint(_this.updateSkew, _this, 0, 0); + /** + * The coordinate of the object relative to the local coordinates of the parent. + * + * @member {PIXI.ObservablePoint} + */ + var _this = _possibleConstructorReturn(this, _TransformBase.call(this)); - _this._rotation = 0; + _this.position = new _math.ObservablePoint(_this.onChange, _this, 0, 0); - _this._sr = Math.sin(0); - _this._cr = Math.cos(0); - _this._cy = Math.cos(0); // skewY); - _this._sy = Math.sin(0); // skewY); - _this._nsx = Math.sin(0); // skewX); - _this._cx = Math.cos(0); // skewX); + /** + * The scale factor of the object. + * + * @member {PIXI.ObservablePoint} + */ + _this.scale = new _math.ObservablePoint(_this.onChange, _this, 1, 1); - _this._localID = 0; - _this._currentLocalID = 0; - return _this; - } + /** + * The pivot point of the displayObject that it rotates around + * + * @member {PIXI.ObservablePoint} + */ + _this.pivot = new _math.ObservablePoint(_this.onChange, _this, 0, 0); - /** - * Called when a value changes. - * - * @private - */ + /** + * The skew amount, on the x and y axis. + * + * @member {PIXI.ObservablePoint} + */ + _this.skew = new _math.ObservablePoint(_this.updateSkew, _this, 0, 0); + _this._rotation = 0; - TransformStatic.prototype.onChange = function onChange() { - this._localID++; - }; + _this._cx = 1; // cos rotation + skewY; + _this._sx = 0; // sin rotation + skewY; + _this._cy = 0; // cos rotation + Math.PI/2 - skewX; + _this._sy = 1; // sin rotation + Math.PI/2 - skewX; - /** - * Called when skew changes - * - * @private - */ + _this._localID = 0; + _this._currentLocalID = 0; + return _this; + } + /** + * Called when a value changes. + * + * @private + */ - TransformStatic.prototype.updateSkew = function updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); - this._localID++; - }; + TransformStatic.prototype.onChange = function onChange() { + this._localID++; + }; - /** - * Updates only local matrix - */ + /** + * Called when skew or rotation changes + * + * @private + */ - TransformStatic.prototype.updateLocalTransform = function updateLocalTransform() { - var lt = this.localTransform; + TransformStatic.prototype.updateSkew = function updateSkew() { + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 - if (this._localID !== this._currentLocalID) { - // get the matrix values of the displayobject based on its transform properties.. - var a = this._cr * this.scale._x; - var b = this._sr * this.scale._x; - var c = -this._sr * this.scale._y; - var d = this._cr * this.scale._y; + this._localID++; + }; - lt.a = this._cy * a + this._sy * c; - lt.b = this._cy * b + this._sy * d; - lt.c = this._nsx * a + this._cx * c; - lt.d = this._nsx * b + this._cx * d; + /** + * Updates only local matrix + */ - lt.tx = this.position._x - (this.pivot._x * lt.a + this.pivot._y * lt.c); - lt.ty = this.position._y - (this.pivot._x * lt.b + this.pivot._y * lt.d); - this._currentLocalID = this._localID; - // force an update.. - this._parentID = -1; - } - }; + TransformStatic.prototype.updateLocalTransform = function updateLocalTransform() { + var lt = this.localTransform; - /** - * Updates the values of the object and applies the parent's transform. - * - * @param {PIXI.Transform} parentTransform - The transform of the parent of this object - */ + if (this._localID !== this._currentLocalID) { + // get the matrix values of the displayobject based on its transform properties.. + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; + lt.tx = this.position._x - (this.pivot._x * lt.a + this.pivot._y * lt.c); + lt.ty = this.position._y - (this.pivot._x * lt.b + this.pivot._y * lt.d); + this._currentLocalID = this._localID; - TransformStatic.prototype.updateTransform = function updateTransform(parentTransform) { - var pt = parentTransform.worldTransform; - var wt = this.worldTransform; - var lt = this.localTransform; + // force an update.. + this._parentID = -1; + } + }; - if (this._localID !== this._currentLocalID) { - // get the matrix values of the displayobject based on its transform properties.. - var a = this._cr * this.scale._x; - var b = this._sr * this.scale._x; - var c = -this._sr * this.scale._y; - var d = this._cr * this.scale._y; + /** + * Updates the values of the object and applies the parent's transform. + * + * @param {PIXI.Transform} parentTransform - The transform of the parent of this object + */ - lt.a = this._cy * a + this._sy * c; - lt.b = this._cy * b + this._sy * d; - lt.c = this._nsx * a + this._cx * c; - lt.d = this._nsx * b + this._cx * d; - lt.tx = this.position._x - (this.pivot._x * lt.a + this.pivot._y * lt.c); - lt.ty = this.position._y - (this.pivot._x * lt.b + this.pivot._y * lt.d); - this._currentLocalID = this._localID; + TransformStatic.prototype.updateTransform = function updateTransform(parentTransform) { + var lt = this.localTransform; - // force an update.. - this._parentID = -1; - } + if (this._localID !== this._currentLocalID) { + // get the matrix values of the displayobject based on its transform properties.. + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; - if (this._parentID !== parentTransform._worldID) { - // concat the parent matrix with the objects transform. - wt.a = lt.a * pt.a + lt.b * pt.c; - wt.b = lt.a * pt.b + lt.b * pt.d; - wt.c = lt.c * pt.a + lt.d * pt.c; - wt.d = lt.c * pt.b + lt.d * pt.d; - wt.tx = lt.tx * pt.a + lt.ty * pt.c + pt.tx; - wt.ty = lt.tx * pt.b + lt.ty * pt.d + pt.ty; + lt.tx = this.position._x - (this.pivot._x * lt.a + this.pivot._y * lt.c); + lt.ty = this.position._y - (this.pivot._x * lt.b + this.pivot._y * lt.d); + this._currentLocalID = this._localID; - this._parentID = parentTransform._worldID; + // force an update.. + this._parentID = -1; + } - // update the id of the transform.. - this._worldID++; - } - }; + if (this._parentID !== parentTransform._worldID) { + // concat the parent matrix with the objects transform. + var pt = parentTransform.worldTransform; + var wt = this.worldTransform; - /** - * Decomposes a matrix and sets the transforms properties based on it. - * - * @param {PIXI.Matrix} matrix - The matrix to decompose - */ + wt.a = lt.a * pt.a + lt.b * pt.c; + wt.b = lt.a * pt.b + lt.b * pt.d; + wt.c = lt.c * pt.a + lt.d * pt.c; + wt.d = lt.c * pt.b + lt.d * pt.d; + wt.tx = lt.tx * pt.a + lt.ty * pt.c + pt.tx; + wt.ty = lt.tx * pt.b + lt.ty * pt.d + pt.ty; + this._parentID = parentTransform._worldID; - TransformStatic.prototype.setFromMatrix = function setFromMatrix(matrix) { - matrix.decompose(this); - this._localID++; - }; + // update the id of the transform.. + this._worldID++; + } + }; - /** - * The rotation of the object in radians. - * - * @member {number} - * @memberof PIXI.TransformStatic# - */ + /** + * Decomposes a matrix and sets the transforms properties based on it. + * + * @param {PIXI.Matrix} matrix - The matrix to decompose + */ - _createClass(TransformStatic, [{ - key: 'rotation', - get: function get() { - return this._rotation; - } + TransformStatic.prototype.setFromMatrix = function setFromMatrix(matrix) { + matrix.decompose(this); + this._localID++; + }; /** - * Sets the rotation of the transform. + * The rotation of the object in radians. * - * @param {number} value - The value to set to. + * @member {number} */ - , - set: function set(value) { - this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID++; - } - }]); - return TransformStatic; + + _createClass(TransformStatic, [{ + key: 'rotation', + get: function get() { + return this._rotation; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { + this._rotation = value; + this.updateSkew(); + } + }]); + + return TransformStatic; }(_TransformBase3.default); exports.default = TransformStatic; -},{"../math":66,"./TransformBase":47}],49:[function(require,module,exports){ +},{"../math":70,"./TransformBase":51}],53:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -9993,8 +10790,11 @@ var Graphics = function (_Container) { /** * + * @param {boolean} [nativeLines=false] - If true the lines will be draw using LINES instead of TRIANGLE_STRIP */ function Graphics() { + var nativeLines = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + _classCallCheck(this, Graphics); /** @@ -10015,6 +10815,13 @@ var Graphics = function (_Container) { */ _this.lineWidth = 0; + /** + * If true the lines will be draw using LINES instead of TRIANGLE_STRIP + * + * @member {boolean} + */ + _this.nativeLines = nativeLines; + /** * The color of any lines drawn. * @@ -10433,7 +11240,7 @@ var Graphics = function (_Container) { startAngle += Math.PI * 2; } - var sweep = anticlockwise ? (startAngle - endAngle) * -1 : endAngle - startAngle; + var sweep = endAngle - startAngle; var segs = Math.ceil(Math.abs(sweep) / (Math.PI * 2)) * 40; if (sweep === 0) { @@ -10443,14 +11250,18 @@ var Graphics = function (_Container) { var startX = cx + Math.cos(startAngle) * radius; var startY = cy + Math.sin(startAngle) * radius; - if (this.currentPath) { - this.currentPath.shape.points.push(startX, startY); + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + var points = this.currentPath ? this.currentPath.shape.points : null; + + if (points) { + if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { + points.push(startX, startY); + } } else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } - var points = this.currentPath.shape.points; - var theta = sweep / (segs * 2); var theta2 = theta * 2; @@ -10590,7 +11401,7 @@ var Graphics = function (_Container) { /** * Draws a polygon using the given path. * - * @param {number[]|PIXI.Point[]} path - The path data used to construct the polygon. + * @param {number[]|PIXI.Point[]|PIXI.Polygon} path - The path data used to construct the polygon. * @return {PIXI.Graphics} This Graphics object. Good for chaining method calls */ @@ -10638,11 +11449,15 @@ var Graphics = function (_Container) { this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; } + this.currentPath = null; + this._spriteRect = null; + return this; }; @@ -10694,26 +11509,13 @@ var Graphics = function (_Container) { var rect = this.graphicsData[0].shape; if (!this._spriteRect) { - if (!Graphics._SPRITE_TEXTURE) { - Graphics._SPRITE_TEXTURE = _RenderTexture2.default.create(10, 10); - - var canvas = document.createElement('canvas'); - - canvas.width = 10; - canvas.height = 10; - - var context = canvas.getContext('2d'); - - context.fillStyle = 'white'; - context.fillRect(0, 0, 10, 10); + this._spriteRect = new _Sprite2.default(new _Texture2.default(_Texture2.default.WHITE)); + } - Graphics._SPRITE_TEXTURE = _Texture2.default.fromCanvas(canvas); - } + var sprite = this._spriteRect; - this._spriteRect = new _Sprite2.default(Graphics._SPRITE_TEXTURE); - } if (this.tint === 0xffffff) { - this._spriteRect.tint = this.graphicsData[0].fillColor; + sprite.tint = this.graphicsData[0].fillColor; } else { var t1 = tempColor1; var t2 = tempColor2; @@ -10725,20 +11527,21 @@ var Graphics = function (_Container) { t1[1] *= t2[1]; t1[2] *= t2[2]; - this._spriteRect.tint = (0, _utils.rgb2hex)(t1); + sprite.tint = (0, _utils.rgb2hex)(t1); } - this._spriteRect.alpha = this.graphicsData[0].fillAlpha; - this._spriteRect.worldAlpha = this.worldAlpha * this._spriteRect.alpha; + sprite.alpha = this.graphicsData[0].fillAlpha; + sprite.worldAlpha = this.worldAlpha * sprite.alpha; + sprite.blendMode = this.blendMode; - Graphics._SPRITE_TEXTURE._frame.width = rect.width; - Graphics._SPRITE_TEXTURE._frame.height = rect.height; + sprite._texture._frame.width = rect.width; + sprite._texture._frame.height = rect.height; - this._spriteRect.transform.worldTransform = this.transform.worldTransform; + sprite.transform.worldTransform = this.transform.worldTransform; - this._spriteRect.anchor.set(-rect.x / rect.width, -rect.y / rect.height); - this._spriteRect._onAnchorUpdate(); + sprite.anchor.set(-rect.x / rect.width, -rect.y / rect.height); + sprite._onAnchorUpdate(); - this._spriteRect._renderWebGL(renderer); + sprite._renderWebGL(renderer); }; /** @@ -10769,7 +11572,6 @@ var Graphics = function (_Container) { this.boundsDirty = this.dirty; this.updateLocalBounds(); - this.dirty++; this.cachedSpriteDirty = true; } @@ -10801,6 +11603,16 @@ var Graphics = function (_Container) { // only deal with fills.. if (data.shape) { if (data.shape.contains(tempPoint.x, tempPoint.y)) { + if (data.holes) { + for (var _i = 0; _i < data.holes.length; _i++) { + var hole = data.holes[_i]; + + if (hole.contains(tempPoint.x, tempPoint.y)) { + return false; + } + } + } + return true; } } @@ -10872,16 +11684,39 @@ var Graphics = function (_Container) { } else { // POLY var points = shape.points; - - for (var j = 0; j < points.length; j += 2) { + var x2 = 0; + var y2 = 0; + var dx = 0; + var dy = 0; + var rw = 0; + var rh = 0; + var cx = 0; + var cy = 0; + + for (var j = 0; j + 2 < points.length; j += 2) { x = points[j]; y = points[j + 1]; + x2 = points[j + 2]; + y2 = points[j + 3]; + dx = Math.abs(x2 - x); + dy = Math.abs(y2 - y); + h = lineWidth; + w = Math.sqrt(dx * dx + dy * dy); + + if (w < 1e-9) { + continue; + } - minX = x - lineWidth < minX ? x - lineWidth : minX; - maxX = x + lineWidth > maxX ? x + lineWidth : maxX; + rw = (h / w * dy + dx) / 2; + rh = (h / w * dx + dy) / 2; + cx = (x2 + x) / 2; + cy = (y2 + y) / 2; - minY = y - lineWidth < minY ? y - lineWidth : minY; - maxY = y + lineWidth > maxY ? y + lineWidth : maxY; + minX = cx - rw < minX ? cx - rw : minX; + maxX = cx + rw > maxX ? cx + rw : maxX; + + minY = cy - rh < minY ? cy - rh : minY; + maxY = cy + rh > maxY ? cy + rh : maxY; } } } @@ -10895,10 +11730,10 @@ var Graphics = function (_Container) { var padding = this.boundsPadding; this._localBounds.minX = minX - padding; - this._localBounds.maxX = maxX + padding * 2; + this._localBounds.maxX = maxX + padding; this._localBounds.minY = minY - padding; - this._localBounds.maxY = maxY + padding * 2; + this._localBounds.maxY = maxY + padding; }; /** @@ -10919,7 +11754,7 @@ var Graphics = function (_Container) { this.currentPath = null; - var data = new _GraphicsData2.default(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); + var data = new _GraphicsData2.default(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, this.nativeLines, shape); this.graphicsData.push(data); @@ -10953,12 +11788,17 @@ var Graphics = function (_Container) { canvasRenderer = new _CanvasRenderer2.default(); } - tempMatrix.tx = -bounds.x; - tempMatrix.ty = -bounds.y; + this.transform.updateLocalTransform(); + this.transform.localTransform.copy(tempMatrix); + + tempMatrix.invert(); - canvasRenderer.render(this, canvasBuffer, false, tempMatrix); + tempMatrix.tx -= bounds.x; + tempMatrix.ty -= bounds.y; - var texture = _Texture2.default.fromCanvas(canvasBuffer.baseTexture._canvasRenderTarget.canvas, scaleMode); + canvasRenderer.render(this, canvasBuffer, true, tempMatrix); + + var texture = _Texture2.default.fromCanvas(canvasBuffer.baseTexture._canvasRenderTarget.canvas, scaleMode, 'graphics'); texture.baseTexture.resolution = resolution; texture.baseTexture.update(); @@ -11010,6 +11850,10 @@ var Graphics = function (_Container) { * options have been set to that value * @param {boolean} [options.children=false] - if set to true, all the children will have * their destroy method called as well. 'options' will be passed on to those calls. + * @param {boolean} [options.texture=false] - Only used for child Sprites if options.children is set to true + * Should it destroy the texture of the child sprite + * @param {boolean} [options.baseTexture=false] - Only used for child Sprites if options.children is set to true + * Should it destroy the base texture of the child sprite */ @@ -11047,7 +11891,7 @@ exports.default = Graphics; Graphics._SPRITE_TEXTURE = null; -},{"../const":42,"../display/Bounds":43,"../display/Container":44,"../math":66,"../renderers/canvas/CanvasRenderer":73,"../sprites/Sprite":97,"../textures/RenderTexture":107,"../textures/Texture":108,"../utils":115,"./GraphicsData":50,"./utils/bezierCurveTo":52}],50:[function(require,module,exports){ +},{"../const":46,"../display/Bounds":47,"../display/Container":48,"../math":70,"../renderers/canvas/CanvasRenderer":77,"../sprites/Sprite":102,"../textures/RenderTexture":113,"../textures/Texture":115,"../utils":124,"./GraphicsData":54,"./utils/bezierCurveTo":56}],54:[function(require,module,exports){ "use strict"; exports.__esModule = true; @@ -11069,15 +11913,20 @@ var GraphicsData = function () { * @param {number} fillColor - the color of the fill * @param {number} fillAlpha - the alpha of the fill * @param {boolean} fill - whether or not the shape is filled with a colour + * @param {boolean} nativeLines - the method for drawing lines * @param {PIXI.Circle|PIXI.Rectangle|PIXI.Ellipse|PIXI.Polygon} shape - The shape object to draw. */ - function GraphicsData(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) { + function GraphicsData(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, nativeLines, shape) { _classCallCheck(this, GraphicsData); /** * @member {number} the width of the line to draw */ this.lineWidth = lineWidth; + /** + * @member {boolean} if true the liens will be draw using LINES instead of TRIANGLE_STRIP + */ + this.nativeLines = nativeLines; /** * @member {number} the color of the line to draw @@ -11135,7 +11984,7 @@ var GraphicsData = function () { GraphicsData.prototype.clone = function clone() { - return new GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.fill, this.shape); + return new GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.fill, this.nativeLines, this.shape); }; /** @@ -11164,7 +12013,7 @@ var GraphicsData = function () { exports.default = GraphicsData; -},{}],51:[function(require,module,exports){ +},{}],55:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -11183,12 +12032,12 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons * @author Mat Groves * * Big thanks to the very clever Matt DesLauriers https://github.com/mattdesl/ - * for creating the original pixi version! + * for creating the original PixiJS version! * Also a thanks to https://github.com/bchevalier for tweaking the tint and alpha so that they * now share 4 bytes on the vertex buffer * * Heavily inspired by LibGDX's CanvasGraphicsRenderer: - * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/CanvasGraphicsRenderer.java + * https://github.com/libgdx/libgdx/blob/1.0.0/gdx/src/com/badlogic/gdx/graphics/glutils/ShapeRenderer.java */ /** @@ -11433,7 +12282,7 @@ exports.default = CanvasGraphicsRenderer; _CanvasRenderer2.default.registerPlugin('graphics', CanvasGraphicsRenderer); -},{"../../const":42,"../../renderers/canvas/CanvasRenderer":73}],52:[function(require,module,exports){ +},{"../../const":46,"../../renderers/canvas/CanvasRenderer":77}],56:[function(require,module,exports){ "use strict"; exports.__esModule = true; @@ -11483,7 +12332,7 @@ function bezierCurveTo(fromX, fromY, cpX, cpY, cpX2, cpY2, toX, toY) { return path; } -},{}],53:[function(require,module,exports){ +},{}],57:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -11626,7 +12475,13 @@ var GraphicsRenderer = function (_ObjectRenderer) { shaderTemp.uniforms.tint = (0, _utils.hex2rgb)(graphics.tint); shaderTemp.uniforms.alpha = graphics.worldAlpha; - webGLData.vao.bind().draw(gl.TRIANGLE_STRIP, webGLData.indices.length).unbind(); + renderer.bindVao(webGLData.vao); + + if (webGLData.nativeLines) { + gl.drawArrays(gl.LINES, 0, webGLData.points.length / 6); + } else { + webGLData.vao.draw(gl.TRIANGLE_STRIP, webGLData.indices.length); + } } }; @@ -11667,6 +12522,7 @@ var GraphicsRenderer = function (_ObjectRenderer) { } var webGLData = void 0; + var webGLDataNativeLines = void 0; // loop through the graphics datas and construct each one.. // if the object is a complex fill then the new stencil buffer technique will be used @@ -11677,20 +12533,27 @@ var GraphicsRenderer = function (_ObjectRenderer) { // TODO - this can be simplified webGLData = this.getWebGLData(webGL, 0); + if (data.nativeLines && data.lineWidth) { + webGLDataNativeLines = this.getWebGLData(webGL, 0, true); + webGL.lastIndex++; + } + if (data.type === _const.SHAPES.POLY) { - (0, _buildPoly2.default)(data, webGLData); + (0, _buildPoly2.default)(data, webGLData, webGLDataNativeLines); } if (data.type === _const.SHAPES.RECT) { - (0, _buildRectangle2.default)(data, webGLData); + (0, _buildRectangle2.default)(data, webGLData, webGLDataNativeLines); } else if (data.type === _const.SHAPES.CIRC || data.type === _const.SHAPES.ELIP) { - (0, _buildCircle2.default)(data, webGLData); + (0, _buildCircle2.default)(data, webGLData, webGLDataNativeLines); } else if (data.type === _const.SHAPES.RREC) { - (0, _buildRoundedRectangle2.default)(data, webGLData); + (0, _buildRoundedRectangle2.default)(data, webGLData, webGLDataNativeLines); } webGL.lastIndex++; } + this.renderer.bindVao(null); + // upload all the dirty data... for (var _i2 = 0; _i2 < webGL.data.length; _i2++) { webGLData = webGL.data[_i2]; @@ -11706,16 +12569,17 @@ var GraphicsRenderer = function (_ObjectRenderer) { * @private * @param {WebGLRenderingContext} gl - the current WebGL drawing context * @param {number} type - TODO @Alvin + * @param {number} nativeLines - indicate whether the webGLData use for nativeLines. * @return {*} TODO */ - GraphicsRenderer.prototype.getWebGLData = function getWebGLData(gl, type) { + GraphicsRenderer.prototype.getWebGLData = function getWebGLData(gl, type, nativeLines) { var webGLData = gl.data[gl.data.length - 1]; - if (!webGLData || webGLData.points.length > 320000) { + if (!webGLData || webGLData.nativeLines !== nativeLines || webGLData.points.length > 320000) { webGLData = this.graphicsDataPool.pop() || new _WebGLGraphicsData2.default(this.renderer.gl, this.primitiveShader, this.renderer.state.attribsState); - + webGLData.nativeLines = nativeLines; webGLData.reset(type); gl.data.push(webGLData); } @@ -11733,7 +12597,7 @@ exports.default = GraphicsRenderer; _WebGLRenderer2.default.registerPlugin('graphics', GraphicsRenderer); -},{"../../const":42,"../../renderers/webgl/WebGLRenderer":80,"../../renderers/webgl/utils/ObjectRenderer":90,"../../utils":115,"./WebGLGraphicsData":54,"./shaders/PrimitiveShader":55,"./utils/buildCircle":56,"./utils/buildPoly":58,"./utils/buildRectangle":59,"./utils/buildRoundedRectangle":60}],54:[function(require,module,exports){ +},{"../../const":46,"../../renderers/webgl/WebGLRenderer":84,"../../renderers/webgl/utils/ObjectRenderer":94,"../../utils":124,"./WebGLGraphicsData":58,"./shaders/PrimitiveShader":59,"./utils/buildCircle":60,"./utils/buildPoly":62,"./utils/buildRectangle":63,"./utils/buildRoundedRectangle":64}],58:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -11769,7 +12633,7 @@ var WebGLGraphicsData = function () { */ this.gl = gl; - // TODO does this need to be split before uploding?? + // TODO does this need to be split before uploading?? /** * An array of color components (r,g,b) * @member {number[]} @@ -11805,6 +12669,12 @@ var WebGLGraphicsData = function () { */ this.dirty = true; + /** + * Whether this graphics is nativeLines or not + * @member {boolean} + */ + this.nativeLines = false; + this.glPoints = null; this.glIndices = null; @@ -11870,7 +12740,7 @@ var WebGLGraphicsData = function () { exports.default = WebGLGraphicsData; -},{"pixi-gl-core":7}],55:[function(require,module,exports){ +},{"pixi-gl-core":7}],59:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -11915,7 +12785,7 @@ var PrimitiveShader = function (_Shader) { exports.default = PrimitiveShader; -},{"../../../Shader":41}],56:[function(require,module,exports){ +},{"../../../Shader":44}],60:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -11940,8 +12810,9 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * @private * @param {PIXI.WebGLGraphicsData} graphicsData - The graphics object to draw * @param {object} webGLData - an object containing all the webGL-specific information to create this shape + * @param {object} webGLDataNativeLines - an object containing all the webGL-specific information to create nativeLines */ -function buildCircle(graphicsData, webGLData) { +function buildCircle(graphicsData, webGLData, webGLDataNativeLines) { // need to convert points to a nice regular data var circleData = graphicsData.shape; var x = circleData.x; @@ -11958,6 +12829,10 @@ function buildCircle(graphicsData, webGLData) { height = circleData.height; } + if (width === 0 || height === 0) { + return; + } + var totalSegs = Math.floor(30 * Math.sqrt(circleData.radius)) || Math.floor(15 * Math.sqrt(circleData.width + circleData.height)); var seg = Math.PI * 2 / totalSegs; @@ -11997,24 +12872,31 @@ function buildCircle(graphicsData, webGLData) { graphicsData.points.push(x + Math.sin(seg * _i) * width, y + Math.cos(seg * _i) * height); } - (0, _buildLine2.default)(graphicsData, webGLData); + (0, _buildLine2.default)(graphicsData, webGLData, webGLDataNativeLines); graphicsData.points = tempPoints; } } -},{"../../../const":42,"../../../utils":115,"./buildLine":57}],57:[function(require,module,exports){ +},{"../../../const":46,"../../../utils":124,"./buildLine":61}],61:[function(require,module,exports){ 'use strict'; exports.__esModule = true; -exports.default = buildLine; + +exports.default = function (graphicsData, webGLData, webGLDataNativeLines) { + if (graphicsData.nativeLines) { + buildNativeLine(graphicsData, webGLDataNativeLines); + } else { + buildLine(graphicsData, webGLData); + } +}; var _math = require('../../../math'); var _utils = require('../../../utils'); /** - * Builds a line to draw + * Builds a line to draw using the poligon method. * * Ignored from docs since it is not directly exposed. * @@ -12212,7 +13094,61 @@ function buildLine(graphicsData, webGLData) { indices.push(indexStart - 1); } -},{"../../../math":66,"../../../utils":115}],58:[function(require,module,exports){ +/** + * Builds a line to draw using the gl.drawArrays(gl.LINES) method + * + * Ignored from docs since it is not directly exposed. + * + * @ignore + * @private + * @param {PIXI.WebGLGraphicsData} graphicsData - The graphics object containing all the necessary properties + * @param {object} webGLData - an object containing all the webGL-specific information to create this shape + */ + + +/** + * Builds a line to draw + * + * Ignored from docs since it is not directly exposed. + * + * @ignore + * @private + * @param {PIXI.WebGLGraphicsData} graphicsData - The graphics object containing all the necessary properties + * @param {object} webGLData - an object containing all the webGL-specific information to create this shape + * @param {object} webGLDataNativeLines - an object containing all the webGL-specific information to create nativeLines + */ +function buildNativeLine(graphicsData, webGLData) { + var i = 0; + var points = graphicsData.points; + + if (points.length === 0) return; + + var verts = webGLData.points; + var length = points.length / 2; + + // sort color + var color = (0, _utils.hex2rgb)(graphicsData.lineColor); + var alpha = graphicsData.lineAlpha; + var r = color[0] * alpha; + var g = color[1] * alpha; + var b = color[2] * alpha; + + for (i = 1; i < length; i++) { + var p1x = points[(i - 1) * 2]; + var p1y = points[(i - 1) * 2 + 1]; + + var p2x = points[i * 2]; + var p2y = points[i * 2 + 1]; + + verts.push(p1x, p1y); + verts.push(r, g, b, alpha); + + verts.push(p2x, p2y); + verts.push(r, g, b, alpha); + } +} + +},{"../../../math":70,"../../../utils":124}],62:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -12239,8 +13175,9 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * @private * @param {PIXI.WebGLGraphicsData} graphicsData - The graphics object containing all the necessary properties * @param {object} webGLData - an object containing all the webGL-specific information to create this shape + * @param {object} webGLDataNativeLines - an object containing all the webGL-specific information to create nativeLines */ -function buildPoly(graphicsData, webGLData) { +function buildPoly(graphicsData, webGLData, webGLDataNativeLines) { graphicsData.points = graphicsData.shape.points.slice(); var points = graphicsData.points; @@ -12293,11 +13230,11 @@ function buildPoly(graphicsData, webGLData) { } if (graphicsData.lineWidth > 0) { - (0, _buildLine2.default)(graphicsData, webGLData); + (0, _buildLine2.default)(graphicsData, webGLData, webGLDataNativeLines); } } -},{"../../../utils":115,"./buildLine":57,"earcut":18}],59:[function(require,module,exports){ +},{"../../../utils":124,"./buildLine":61,"earcut":19}],63:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -12320,8 +13257,9 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * @private * @param {PIXI.WebGLGraphicsData} graphicsData - The graphics object containing all the necessary properties * @param {object} webGLData - an object containing all the webGL-specific information to create this shape + * @param {object} webGLDataNativeLines - an object containing all the webGL-specific information to create nativeLines */ -function buildRectangle(graphicsData, webGLData) { +function buildRectangle(graphicsData, webGLData, webGLDataNativeLines) { // --- // // need to convert points to a nice regular data // @@ -12366,13 +13304,13 @@ function buildRectangle(graphicsData, webGLData) { graphicsData.points = [x, y, x + width, y, x + width, y + height, x, y + height, x, y]; - (0, _buildLine2.default)(graphicsData, webGLData); + (0, _buildLine2.default)(graphicsData, webGLData, webGLDataNativeLines); graphicsData.points = tempPoints; } } -},{"../../../utils":115,"./buildLine":57}],60:[function(require,module,exports){ +},{"../../../utils":124,"./buildLine":61}],64:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -12399,8 +13337,9 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * @private * @param {PIXI.WebGLGraphicsData} graphicsData - The graphics object containing all the necessary properties * @param {object} webGLData - an object containing all the webGL-specific information to create this shape + * @param {object} webGLDataNativeLines - an object containing all the webGL-specific information to create nativeLines */ -function buildRoundedRectangle(graphicsData, webGLData) { +function buildRoundedRectangle(graphicsData, webGLData, webGLDataNativeLines) { var rrectData = graphicsData.shape; var x = rrectData.x; var y = rrectData.y; @@ -12453,12 +13392,31 @@ function buildRoundedRectangle(graphicsData, webGLData) { graphicsData.points = recPoints; - (0, _buildLine2.default)(graphicsData, webGLData); + (0, _buildLine2.default)(graphicsData, webGLData, webGLDataNativeLines); graphicsData.points = tempPoints; } } +/** + * Calculate a single point for a quadratic bezier curve. + * Utility function used by quadraticBezierCurve. + * Ignored from docs since it is not directly exposed. + * + * @ignore + * @private + * @param {number} n1 - first number + * @param {number} n2 - second number + * @param {number} perc - percentage + * @return {number} the result + * + */ +function getPt(n1, n2, perc) { + var diff = n2 - n1; + + return n1 + diff * perc; +} + /** * Calculate the points for a quadratic bezier curve. (helper function..) * Based on: https://stackoverflow.com/questions/785097/how-do-i-implement-a-bezier-curve-in-c @@ -12489,12 +13447,6 @@ function quadraticBezierCurve(fromX, fromY, cpX, cpY, toX, toY) { var x = 0; var y = 0; - function getPt(n1, n2, perc) { - var diff = n2 - n1; - - return n1 + diff * perc; - } - for (var i = 0, j = 0; i <= n; ++i) { j = i / n; @@ -12514,11 +13466,11 @@ function quadraticBezierCurve(fromX, fromY, cpX, cpY, toX, toY) { return points; } -},{"../../../utils":115,"./buildLine":57,"earcut":18}],61:[function(require,module,exports){ +},{"../../../utils":124,"./buildLine":61,"earcut":19}],65:[function(require,module,exports){ 'use strict'; exports.__esModule = true; -exports.Filter = exports.SpriteMaskFilter = exports.Quad = exports.RenderTarget = exports.ObjectRenderer = exports.WebGLManager = exports.Shader = exports.CanvasRenderTarget = exports.TextureUvs = exports.VideoBaseTexture = exports.BaseRenderTexture = exports.RenderTexture = exports.BaseTexture = exports.Texture = exports.CanvasGraphicsRenderer = exports.GraphicsRenderer = exports.GraphicsData = exports.Graphics = exports.TextStyle = exports.Text = exports.SpriteRenderer = exports.CanvasTinter = exports.CanvasSpriteRenderer = exports.Sprite = exports.TransformBase = exports.TransformStatic = exports.Transform = exports.Container = exports.DisplayObject = exports.glCore = exports.WebGLRenderer = exports.CanvasRenderer = exports.ticker = exports.utils = undefined; +exports.autoDetectRenderer = exports.Application = exports.Filter = exports.SpriteMaskFilter = exports.Quad = exports.RenderTarget = exports.ObjectRenderer = exports.WebGLManager = exports.Shader = exports.CanvasRenderTarget = exports.TextureUvs = exports.VideoBaseTexture = exports.BaseRenderTexture = exports.RenderTexture = exports.BaseTexture = exports.Texture = exports.Spritesheet = exports.CanvasGraphicsRenderer = exports.GraphicsRenderer = exports.GraphicsData = exports.Graphics = exports.TextMetrics = exports.TextStyle = exports.Text = exports.SpriteRenderer = exports.CanvasTinter = exports.CanvasSpriteRenderer = exports.Sprite = exports.TransformBase = exports.TransformStatic = exports.Transform = exports.Container = exports.DisplayObject = exports.Bounds = exports.glCore = exports.WebGLRenderer = exports.CanvasRenderer = exports.ticker = exports.utils = exports.settings = undefined; var _const = require('./const'); @@ -12553,6 +13505,15 @@ Object.defineProperty(exports, 'glCore', { } }); +var _Bounds = require('./display/Bounds'); + +Object.defineProperty(exports, 'Bounds', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_Bounds).default; + } +}); + var _DisplayObject = require('./display/DisplayObject'); Object.defineProperty(exports, 'DisplayObject', { @@ -12652,6 +13613,15 @@ Object.defineProperty(exports, 'TextStyle', { } }); +var _TextMetrics = require('./text/TextMetrics'); + +Object.defineProperty(exports, 'TextMetrics', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_TextMetrics).default; + } +}); + var _Graphics = require('./graphics/Graphics'); Object.defineProperty(exports, 'Graphics', { @@ -12688,6 +13658,15 @@ Object.defineProperty(exports, 'CanvasGraphicsRenderer', { } }); +var _Spritesheet = require('./textures/Spritesheet'); + +Object.defineProperty(exports, 'Spritesheet', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_Spritesheet).default; + } +}); + var _Texture = require('./textures/Texture'); Object.defineProperty(exports, 'Texture', { @@ -12813,7 +13792,24 @@ Object.defineProperty(exports, 'Filter', { return _interopRequireDefault(_Filter).default; } }); -exports.autoDetectRenderer = autoDetectRenderer; + +var _Application = require('./Application'); + +Object.defineProperty(exports, 'Application', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_Application).default; + } +}); + +var _autoDetectRenderer = require('./autoDetectRenderer'); + +Object.defineProperty(exports, 'autoDetectRenderer', { + enumerable: true, + get: function get() { + return _autoDetectRenderer.autoDetectRenderer; + } +}); var _utils = require('./utils'); @@ -12823,6 +13819,10 @@ var _ticker = require('./ticker'); var ticker = _interopRequireWildcard(_ticker); +var _settings = require('./settings'); + +var _settings2 = _interopRequireDefault(_settings); + var _CanvasRenderer = require('./renderers/canvas/CanvasRenderer'); var _CanvasRenderer2 = _interopRequireDefault(_CanvasRenderer); @@ -12835,47 +13835,15 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -/** - * @namespace PIXI - */ +exports.settings = _settings2.default; exports.utils = utils; exports.ticker = ticker; exports.CanvasRenderer = _CanvasRenderer2.default; -exports.WebGLRenderer = _WebGLRenderer2.default; +exports.WebGLRenderer = _WebGLRenderer2.default; /** + * @namespace PIXI + */ - -/** - * This helper function will automatically detect which renderer you should be using. - * WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by - * the browser then this function will return a canvas renderer - * - * @memberof PIXI - * @param {number} [width=800] - the width of the renderers view - * @param {number} [height=600] - the height of the renderers view - * @param {object} [options] - The optional renderer parameters - * @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional - * @param {boolean} [options.transparent=false] - If the render view is transparent, default false - * @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment) - * @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, enable this if you - * need to call toDataUrl on the webgl context - * @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer, retina would be 2 - * @param {boolean} [noWebGL=false] - prevents selection of WebGL renderer, even if such is present - * @return {PIXI.WebGLRenderer|PIXI.CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer - */ -function autoDetectRenderer() { - var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 800; - var height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 600; - var options = arguments[2]; - var noWebGL = arguments[3]; - - if (!noWebGL && utils.isWebGLSupported()) { - return new _WebGLRenderer2.default(width, height, options); - } - - return new _CanvasRenderer2.default(width, height, options); -} - -},{"./Shader":41,"./const":42,"./display/Container":44,"./display/DisplayObject":45,"./display/Transform":46,"./display/TransformBase":47,"./display/TransformStatic":48,"./graphics/Graphics":49,"./graphics/GraphicsData":50,"./graphics/canvas/CanvasGraphicsRenderer":51,"./graphics/webgl/GraphicsRenderer":53,"./math":66,"./renderers/canvas/CanvasRenderer":73,"./renderers/canvas/utils/CanvasRenderTarget":75,"./renderers/webgl/WebGLRenderer":80,"./renderers/webgl/filters/Filter":82,"./renderers/webgl/filters/spriteMask/SpriteMaskFilter":85,"./renderers/webgl/managers/WebGLManager":89,"./renderers/webgl/utils/ObjectRenderer":90,"./renderers/webgl/utils/Quad":91,"./renderers/webgl/utils/RenderTarget":92,"./sprites/Sprite":97,"./sprites/canvas/CanvasSpriteRenderer":98,"./sprites/canvas/CanvasTinter":99,"./sprites/webgl/SpriteRenderer":101,"./text/Text":103,"./text/TextStyle":104,"./textures/BaseRenderTexture":105,"./textures/BaseTexture":106,"./textures/RenderTexture":107,"./textures/Texture":108,"./textures/TextureUvs":109,"./textures/VideoBaseTexture":110,"./ticker":112,"./utils":115,"pixi-gl-core":7}],62:[function(require,module,exports){ +},{"./Application":43,"./Shader":44,"./autoDetectRenderer":45,"./const":46,"./display/Bounds":47,"./display/Container":48,"./display/DisplayObject":49,"./display/Transform":50,"./display/TransformBase":51,"./display/TransformStatic":52,"./graphics/Graphics":53,"./graphics/GraphicsData":54,"./graphics/canvas/CanvasGraphicsRenderer":55,"./graphics/webgl/GraphicsRenderer":57,"./math":70,"./renderers/canvas/CanvasRenderer":77,"./renderers/canvas/utils/CanvasRenderTarget":79,"./renderers/webgl/WebGLRenderer":84,"./renderers/webgl/filters/Filter":86,"./renderers/webgl/filters/spriteMask/SpriteMaskFilter":89,"./renderers/webgl/managers/WebGLManager":93,"./renderers/webgl/utils/ObjectRenderer":94,"./renderers/webgl/utils/Quad":95,"./renderers/webgl/utils/RenderTarget":96,"./settings":101,"./sprites/Sprite":102,"./sprites/canvas/CanvasSpriteRenderer":103,"./sprites/canvas/CanvasTinter":104,"./sprites/webgl/SpriteRenderer":106,"./text/Text":108,"./text/TextMetrics":109,"./text/TextStyle":110,"./textures/BaseRenderTexture":111,"./textures/BaseTexture":112,"./textures/RenderTexture":113,"./textures/Spritesheet":114,"./textures/Texture":115,"./textures/TextureUvs":116,"./textures/VideoBaseTexture":117,"./ticker":120,"./utils":124,"pixi-gl-core":7}],66:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -12948,8 +13916,8 @@ init(); * This is the small part of gameofbombs.com portal system. It works. * * @author Ivan @ivanpopelyshev - * - * @namespace PIXI.GroupD8 + * @class + * @memberof PIXI */ var GroupD8 = { E: 0, @@ -12991,7 +13959,7 @@ var GroupD8 = { /** * Adds 180 degrees to rotation. Commutative operation. * - * @method + * @memberof PIXI.GroupD8 * @param {number} rotation - The number to rotate. * @returns {number} rotated number */ @@ -13002,6 +13970,7 @@ var GroupD8 = { /** * I dont know why sometimes width and heights needs to be swapped. We'll fix it later. * + * @memberof PIXI.GroupD8 * @param {number} rotation - The number to check. * @returns {boolean} Whether or not the width/height should be swapped. */ @@ -13010,6 +13979,7 @@ var GroupD8 = { }, /** + * @memberof PIXI.GroupD8 * @param {number} dx - TODO * @param {number} dy - TODO * @@ -13044,6 +14014,7 @@ var GroupD8 = { /** * Helps sprite to compensate texture packer rotation. * + * @memberof PIXI.GroupD8 * @param {PIXI.Matrix} matrix - sprite world matrix * @param {number} rotation - The rotation factor to use. * @param {number} tx - sprite anchoring @@ -13064,7 +14035,7 @@ var GroupD8 = { exports.default = GroupD8; -},{"./Matrix":63}],63:[function(require,module,exports){ +},{"./Matrix":67}],67:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -13080,7 +14051,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** - * The pixi Matrix class as an object, which makes it a lot faster, + * The PixiJS Matrix class as an object, which makes it a lot faster, * here is a representation of it : * | a | b | tx| * | c | d | ty| @@ -13091,46 +14062,58 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons */ var Matrix = function () { /** - * + * @param {number} [a=1] - x scale + * @param {number} [b=0] - y skew + * @param {number} [c=0] - x skew + * @param {number} [d=1] - y scale + * @param {number} [tx=0] - x translation + * @param {number} [ty=0] - y translation */ function Matrix() { + var a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1; + var b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + var c = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; + var d = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1; + var tx = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0; + var ty = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0; + _classCallCheck(this, Matrix); /** * @member {number} * @default 1 */ - this.a = 1; + this.a = a; /** * @member {number} * @default 0 */ - this.b = 0; + this.b = b; /** * @member {number} * @default 0 */ - this.c = 0; + this.c = c; /** * @member {number} * @default 1 */ - this.d = 1; + this.d = d; /** * @member {number} * @default 0 */ - this.tx = 0; + this.tx = tx; /** * @member {number} * @default 0 */ - this.ty = 0; + this.ty = ty; this.array = null; } @@ -13428,7 +14411,7 @@ var Matrix = function () { * Decomposes the matrix (x, y, scaleX, scaleY, and rotation) and sets the properties on to a transform. * * @param {PIXI.Transform|PIXI.TransformStatic} transform - The transform to apply the properties to. - * @return {PIXI.Transform|PIXI.TransformStatic} The transform with the newly applied properies + * @return {PIXI.Transform|PIXI.TransformStatic} The transform with the newly applied properties */ @@ -13439,10 +14422,10 @@ var Matrix = function () { var c = this.c; var d = this.d; - var skewX = Math.atan2(-c, d); + var skewX = -Math.atan2(-c, d); var skewY = Math.atan2(b, a); - var delta = Math.abs(1 - skewX / skewY); + var delta = Math.abs(skewX + skewY); if (delta < 0.00001) { transform.rotation = skewY; @@ -13583,7 +14566,7 @@ var Matrix = function () { exports.default = Matrix; -},{"./Point":65}],64:[function(require,module,exports){ +},{"./Point":69}],68:[function(require,module,exports){ "use strict"; exports.__esModule = true; @@ -13659,7 +14642,6 @@ var ObservablePoint = function () { * The position of the displayObject on the x axis relative to the local coordinates of the parent. * * @member {number} - * @memberof PIXI.ObservablePoint# */ @@ -13667,15 +14649,9 @@ var ObservablePoint = function () { key: "x", get: function get() { return this._x; - } - - /** - * Sets the X component. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { if (this._x !== value) { this._x = value; this.cb.call(this.scope); @@ -13686,22 +14662,15 @@ var ObservablePoint = function () { * The position of the displayObject on the x axis relative to the local coordinates of the parent. * * @member {number} - * @memberof PIXI.ObservablePoint# */ }, { key: "y", get: function get() { return this._y; - } - - /** - * Sets the Y component. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { if (this._y !== value) { this._y = value; this.cb.call(this.scope); @@ -13714,7 +14683,7 @@ var ObservablePoint = function () { exports.default = ObservablePoint; -},{}],65:[function(require,module,exports){ +},{}],69:[function(require,module,exports){ "use strict"; exports.__esModule = true; @@ -13805,7 +14774,7 @@ var Point = function () { exports.default = Point; -},{}],66:[function(require,module,exports){ +},{}],70:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -13893,7 +14862,7 @@ Object.defineProperty(exports, 'RoundedRectangle', { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -},{"./GroupD8":62,"./Matrix":63,"./ObservablePoint":64,"./Point":65,"./shapes/Circle":67,"./shapes/Ellipse":68,"./shapes/Polygon":69,"./shapes/Rectangle":70,"./shapes/RoundedRectangle":71}],67:[function(require,module,exports){ +},{"./GroupD8":66,"./Matrix":67,"./ObservablePoint":68,"./Point":69,"./shapes/Circle":71,"./shapes/Ellipse":72,"./shapes/Polygon":73,"./shapes/Rectangle":74,"./shapes/RoundedRectangle":75}],71:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -14007,7 +14976,7 @@ var Circle = function () { exports.default = Circle; -},{"../../const":42,"./Rectangle":70}],68:[function(require,module,exports){ +},{"../../const":46,"./Rectangle":74}],72:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -14129,7 +15098,7 @@ var Ellipse = function () { exports.default = Ellipse; -},{"../../const":42,"./Rectangle":70}],69:[function(require,module,exports){ +},{"../../const":46,"./Rectangle":74}],73:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -14240,7 +15209,7 @@ var Polygon = function () { // https://github.com/substack/point-in-polygon/blob/master/index.js var length = this.points.length / 2; - for (var i = 0, j = length - 1; i < length; j = ++i) { + for (var i = 0, j = length - 1; i < length; j = i++) { var xi = this.points[i * 2]; var yi = this.points[i * 2 + 1]; var xj = this.points[j * 2]; @@ -14260,7 +15229,7 @@ var Polygon = function () { exports.default = Polygon; -},{"../../const":42,"../Point":65}],70:[function(require,module,exports){ +},{"../../const":46,"../Point":69}],74:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -14297,25 +15266,25 @@ var Rectangle = function () { * @member {number} * @default 0 */ - this.x = x; + this.x = Number(x); /** * @member {number} * @default 0 */ - this.y = y; + this.y = Number(y); /** * @member {number} * @default 0 */ - this.width = width; + this.width = Number(width); /** * @member {number} * @default 0 */ - this.height = height; + this.height = Number(height); /** * The type of the object, mainly used to avoid `instanceof` checks @@ -14332,7 +15301,6 @@ var Rectangle = function () { * returns the left edge of the rectangle * * @member {number} - * @memberof PIXI.Rectangle# */ @@ -14349,7 +15317,7 @@ var Rectangle = function () { * Copies another rectangle to this one. * * @param {PIXI.Rectangle} rectangle - The rectangle to copy. - * @return {PIXI.Rectanle} Returns itself. + * @return {PIXI.Rectangle} Returns itself. */ @@ -14447,19 +15415,15 @@ var Rectangle = function () { /** * Enlarges this rectangle to include the passed rectangle. * - * @param {PIXI.Rectangle} rect - The rectangle to include. + * @param {PIXI.Rectangle} rectangle - The rectangle to include. */ - Rectangle.prototype.enlarge = function enlarge(rect) { - if (rect === Rectangle.EMPTY) { - return; - } - - var x1 = Math.min(this.x, rect.x); - var x2 = Math.max(this.x + this.width, rect.x + rect.width); - var y1 = Math.min(this.y, rect.y); - var y2 = Math.max(this.y + this.height, rect.y + rect.height); + Rectangle.prototype.enlarge = function enlarge(rectangle) { + var x1 = Math.min(this.x, rectangle.x); + var x2 = Math.max(this.x + this.width, rectangle.x + rectangle.width); + var y1 = Math.min(this.y, rectangle.y); + var y2 = Math.max(this.y + this.height, rectangle.y + rectangle.height); this.x = x1; this.width = x2 - x1; @@ -14477,7 +15441,6 @@ var Rectangle = function () { * returns the right edge of the rectangle * * @member {number} - * @memberof PIXI.Rectangle */ }, { @@ -14490,7 +15453,6 @@ var Rectangle = function () { * returns the top edge of the rectangle * * @member {number} - * @memberof PIXI.Rectangle */ }, { @@ -14503,7 +15465,6 @@ var Rectangle = function () { * returns the bottom edge of the rectangle * * @member {number} - * @memberof PIXI.Rectangle */ }, { @@ -14531,7 +15492,7 @@ var Rectangle = function () { exports.default = Rectangle; -},{"../../const":42}],71:[function(require,module,exports){ +},{"../../const":46}],75:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -14548,103 +15509,123 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons * @memberof PIXI */ var RoundedRectangle = function () { - /** - * @param {number} [x=0] - The X coordinate of the upper-left corner of the rounded rectangle - * @param {number} [y=0] - The Y coordinate of the upper-left corner of the rounded rectangle - * @param {number} [width=0] - The overall width of this rounded rectangle - * @param {number} [height=0] - The overall height of this rounded rectangle - * @param {number} [radius=20] - Controls the radius of the rounded corners - */ - function RoundedRectangle() { - var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; - var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - var width = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; - var height = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; - var radius = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 20; - - _classCallCheck(this, RoundedRectangle); - /** - * @member {number} - * @default 0 + * @param {number} [x=0] - The X coordinate of the upper-left corner of the rounded rectangle + * @param {number} [y=0] - The Y coordinate of the upper-left corner of the rounded rectangle + * @param {number} [width=0] - The overall width of this rounded rectangle + * @param {number} [height=0] - The overall height of this rounded rectangle + * @param {number} [radius=20] - Controls the radius of the rounded corners */ - this.x = x; + function RoundedRectangle() { + var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + var width = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; + var height = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; + var radius = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 20; - /** - * @member {number} - * @default 0 - */ - this.y = y; + _classCallCheck(this, RoundedRectangle); - /** - * @member {number} - * @default 0 - */ - this.width = width; + /** + * @member {number} + * @default 0 + */ + this.x = x; - /** - * @member {number} - * @default 0 - */ - this.height = height; + /** + * @member {number} + * @default 0 + */ + this.y = y; - /** - * @member {number} - * @default 20 - */ - this.radius = radius; + /** + * @member {number} + * @default 0 + */ + this.width = width; + + /** + * @member {number} + * @default 0 + */ + this.height = height; + + /** + * @member {number} + * @default 20 + */ + this.radius = radius; + + /** + * The type of the object, mainly used to avoid `instanceof` checks + * + * @member {number} + * @readonly + * @default PIXI.SHAPES.RREC + * @see PIXI.SHAPES + */ + this.type = _const.SHAPES.RREC; + } /** - * The type of the object, mainly used to avoid `instanceof` checks + * Creates a clone of this Rounded Rectangle * - * @member {number} - * @readonly - * @default PIXI.SHAPES.RREC - * @see PIXI.SHAPES + * @return {PIXI.RoundedRectangle} a copy of the rounded rectangle */ - this.type = _const.SHAPES.RREC; - } - - /** - * Creates a clone of this Rounded Rectangle - * - * @return {PIXI.RoundedRectangle} a copy of the rounded rectangle - */ - RoundedRectangle.prototype.clone = function clone() { - return new RoundedRectangle(this.x, this.y, this.width, this.height, this.radius); - }; + RoundedRectangle.prototype.clone = function clone() { + return new RoundedRectangle(this.x, this.y, this.width, this.height, this.radius); + }; - /** - * Checks whether the x and y coordinates given are contained within this Rounded Rectangle - * - * @param {number} x - The X coordinate of the point to test - * @param {number} y - The Y coordinate of the point to test - * @return {boolean} Whether the x/y coordinates are within this Rounded Rectangle - */ + /** + * Checks whether the x and y coordinates given are contained within this Rounded Rectangle + * + * @param {number} x - The X coordinate of the point to test + * @param {number} y - The Y coordinate of the point to test + * @return {boolean} Whether the x/y coordinates are within this Rounded Rectangle + */ - RoundedRectangle.prototype.contains = function contains(x, y) { - if (this.width <= 0 || this.height <= 0) { - return false; - } + RoundedRectangle.prototype.contains = function contains(x, y) { + if (this.width <= 0 || this.height <= 0) { + return false; + } + if (x >= this.x && x <= this.x + this.width) { + if (y >= this.y && y <= this.y + this.height) { + if (y >= this.y + this.radius && y <= this.y + this.height - this.radius || x >= this.x + this.radius && x <= this.x + this.width - this.radius) { + return true; + } + var dx = x - (this.x + this.radius); + var dy = y - (this.y + this.radius); + var radius2 = this.radius * this.radius; - if (x >= this.x && x <= this.x + this.width) { - if (y >= this.y && y <= this.y + this.height) { - return true; - } - } + if (dx * dx + dy * dy <= radius2) { + return true; + } + dx = x - (this.x + this.width - this.radius); + if (dx * dx + dy * dy <= radius2) { + return true; + } + dy = y - (this.y + this.height - this.radius); + if (dx * dx + dy * dy <= radius2) { + return true; + } + dx = x - (this.x + this.radius); + if (dx * dx + dy * dy <= radius2) { + return true; + } + } + } - return false; - }; + return false; + }; - return RoundedRectangle; + return RoundedRectangle; }(); exports.default = RoundedRectangle; -},{"../../const":42}],72:[function(require,module,exports){ +},{"../../const":46}],76:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -14657,6 +15638,10 @@ var _math = require('../math'); var _const = require('../const'); +var _settings = require('../settings'); + +var _settings2 = _interopRequireDefault(_settings); + var _Container = require('../display/Container'); var _Container2 = _interopRequireDefault(_Container); @@ -14680,8 +15665,8 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" var tempMatrix = new _math.Matrix(); /** - * The SystemRenderer is the base for a Pixi Renderer. It is extended by the {@link PIXI.CanvasRenderer} - * and {@link PIXI.WebGLRenderer} which can be used for rendering a Pixi scene. + * The SystemRenderer is the base for a PixiJS Renderer. It is extended by the {@link PIXI.CanvasRenderer} + * and {@link PIXI.WebGLRenderer} which can be used for rendering a PixiJS scene. * * @abstract * @class @@ -14692,42 +15677,53 @@ var tempMatrix = new _math.Matrix(); var SystemRenderer = function (_EventEmitter) { _inherits(SystemRenderer, _EventEmitter); + // eslint-disable-next-line valid-jsdoc /** * @param {string} system - The name of the system this renderer is for. - * @param {number} [width=800] - the width of the canvas view - * @param {number} [height=600] - the height of the canvas view * @param {object} [options] - The optional renderer parameters + * @param {number} [options.width=800] - the width of the screen + * @param {number} [options.height=600] - the height of the screen * @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional * @param {boolean} [options.transparent=false] - If the render view is transparent, default false * @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false * @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment) * @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer. The * resolution of the renderer retina would be 2. - * @param {boolean} [options.clearBeforeRender=true] - This sets if the CanvasRenderer will clear the canvas or + * @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, + * enable this if you need to call toDataUrl on the webgl context. + * @param {boolean} [options.clearBeforeRender=true] - This sets if the renderer will clear the canvas or * not before the new render pass. * @param {number} [options.backgroundColor=0x000000] - The background color of the rendered area * (shown if not transparent). - * @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering, + * @param {boolean} [options.roundPixels=false] - If true PixiJS will Math.floor() x/y values when rendering, * stopping pixel interpolation. */ - function SystemRenderer(system, width, height, options) { + function SystemRenderer(system, options, arg2, arg3) { _classCallCheck(this, SystemRenderer); var _this = _possibleConstructorReturn(this, _EventEmitter.call(this)); (0, _utils.sayHello)(system); - // prepare options - if (options) { - for (var i in _const.DEFAULT_RENDER_OPTIONS) { - if (typeof options[i] === 'undefined') { - options[i] = _const.DEFAULT_RENDER_OPTIONS[i]; - } - } - } else { - options = _const.DEFAULT_RENDER_OPTIONS; + // Support for constructor(system, screenWidth, screenHeight, options) + if (typeof options === 'number') { + options = Object.assign({ + width: options, + height: arg2 || _settings2.default.RENDER_OPTIONS.height + }, arg3); } + // Add the default render options + options = Object.assign({}, _settings2.default.RENDER_OPTIONS, options); + + /** + * The supplied constructor options. + * + * @member {Object} + * @readOnly + */ + _this.options = options; + /** * The type of the renderer. * @@ -14738,20 +15734,13 @@ var SystemRenderer = function (_EventEmitter) { _this.type = _const.RENDERER_TYPE.UNKNOWN; /** - * The width of the canvas view + * Measurements of the screen. (0, 0, screenWidth, screenHeight) * - * @member {number} - * @default 800 - */ - _this.width = width || 800; - - /** - * The height of the canvas view + * Its safe to use as filterArea or hitArea for whole stage * - * @member {number} - * @default 600 + * @member {PIXI.Rectangle} */ - _this.height = height || 600; + _this.screen = new _math.Rectangle(0, 0, options.width, options.height); /** * The canvas element that everything is drawn to @@ -14766,7 +15755,7 @@ var SystemRenderer = function (_EventEmitter) { * @member {number} * @default 1 */ - _this.resolution = options.resolution; + _this.resolution = options.resolution || _settings2.default.RESOLUTION; /** * Whether the render view is transparent @@ -14776,7 +15765,7 @@ var SystemRenderer = function (_EventEmitter) { _this.transparent = options.transparent; /** - * Whether the render view should be resized automatically + * Whether css dimensions of canvas view should be resized to screen dimensions automatically * * @member {boolean} */ @@ -14799,8 +15788,8 @@ var SystemRenderer = function (_EventEmitter) { /** * This sets if the CanvasRenderer will clear the canvas or not before the new render pass. - * If the scene is NOT transparent Pixi will use a canvas sized fillRect operation every - * frame to set the canvas background color. If the scene is transparent Pixi will use clearRect + * If the scene is NOT transparent PixiJS will use a canvas sized fillRect operation every + * frame to set the canvas background color. If the scene is transparent PixiJS will use clearRect * to clear the canvas every frame. Disable this by setting this to false. For example if * your game has a canvas filling background image you often don't need this set. * @@ -14810,7 +15799,7 @@ var SystemRenderer = function (_EventEmitter) { _this.clearBeforeRender = options.clearBeforeRender; /** - * If true Pixi will Math.floor() x/y values when rendering, stopping pixel interpolation. + * If true PixiJS will Math.floor() x/y values when rendering, stopping pixel interpolation. * Handy for crisp pixel art and speed on legacy devices. * * @member {boolean} @@ -14862,23 +15851,31 @@ var SystemRenderer = function (_EventEmitter) { } /** - * Resizes the canvas view to the specified width and height + * Same as view.width, actual number of pixels in the canvas by horizontal * - * @param {number} width - the new width of the canvas view - * @param {number} height - the new height of the canvas view + * @member {number} + * @readonly + * @default 800 */ - SystemRenderer.prototype.resize = function resize(width, height) { - this.width = width * this.resolution; - this.height = height * this.resolution; + /** + * Resizes the screen and canvas to the specified width and height + * Canvas dimensions are multiplied by resolution + * + * @param {number} screenWidth - the new width of the screen + * @param {number} screenHeight - the new height of the screen + */ + SystemRenderer.prototype.resize = function resize(screenWidth, screenHeight) { + this.screen.width = screenWidth; + this.screen.height = screenHeight; - this.view.width = this.width; - this.view.height = this.height; + this.view.width = screenWidth * this.resolution; + this.view.height = screenHeight * this.resolution; if (this.autoResize) { - this.view.style.width = this.width / this.resolution + 'px'; - this.view.style.height = this.height / this.resolution + 'px'; + this.view.style.width = screenWidth + 'px'; + this.view.style.height = screenHeight + 'px'; } }; @@ -14920,11 +15917,10 @@ var SystemRenderer = function (_EventEmitter) { this.type = _const.RENDERER_TYPE.UNKNOWN; - this.width = 0; - this.height = 0; - this.view = null; + this.screen = null; + this.resolution = 0; this.transparent = false; @@ -14933,6 +15929,8 @@ var SystemRenderer = function (_EventEmitter) { this.blendModes = null; + this.options = null; + this.preserveDrawingBuffer = false; this.clearBeforeRender = false; @@ -14942,7 +15940,6 @@ var SystemRenderer = function (_EventEmitter) { this._backgroundColorRgba = null; this._backgroundColorString = null; - this.backgroundColor = 0; this._tempDisplayObjectParent = null; this._lastObjectRendered = null; }; @@ -14951,23 +15948,35 @@ var SystemRenderer = function (_EventEmitter) { * The background color to fill if not transparent * * @member {number} - * @memberof PIXI.SystemRenderer# */ _createClass(SystemRenderer, [{ - key: 'backgroundColor', + key: 'width', get: function get() { - return this._backgroundColor; + return this.view.width; } /** - * Sets the background color. + * Same as view.height, actual number of pixels in the canvas by vertical * - * @param {number} value - The value to set to. + * @member {number} + * @readonly + * @default 600 */ - , - set: function set(value) { + + }, { + key: 'height', + get: function get() { + return this.view.height; + } + }, { + key: 'backgroundColor', + get: function get() { + return this._backgroundColor; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._backgroundColor = value; this._backgroundColorString = (0, _utils.hex2string)(value); (0, _utils.hex2rgb)(value, this._backgroundColorRgba); @@ -14979,7 +15988,7 @@ var SystemRenderer = function (_EventEmitter) { exports.default = SystemRenderer; -},{"../const":42,"../display/Container":44,"../math":66,"../textures/RenderTexture":107,"../utils":115,"eventemitter3":19}],73:[function(require,module,exports){ +},{"../const":46,"../display/Container":48,"../math":70,"../settings":101,"../textures/RenderTexture":113,"../utils":124,"eventemitter3":20}],77:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -15004,6 +16013,10 @@ var _utils = require('../../utils'); var _const = require('../../const'); +var _settings = require('../../settings'); + +var _settings2 = _interopRequireDefault(_settings); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -15024,39 +16037,47 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" var CanvasRenderer = function (_SystemRenderer) { _inherits(CanvasRenderer, _SystemRenderer); + // eslint-disable-next-line valid-jsdoc /** - * @param {number} [width=800] - the width of the canvas view - * @param {number} [height=600] - the height of the canvas view * @param {object} [options] - The optional renderer parameters + * @param {number} [options.width=800] - the width of the screen + * @param {number} [options.height=600] - the height of the screen * @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional * @param {boolean} [options.transparent=false] - If the render view is transparent, default false * @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false * @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment) * @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer. The * resolution of the renderer retina would be 2. - * @param {boolean} [options.clearBeforeRender=true] - This sets if the CanvasRenderer will clear the canvas or + * @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, + * enable this if you need to call toDataUrl on the webgl context. + * @param {boolean} [options.clearBeforeRender=true] - This sets if the renderer will clear the canvas or * not before the new render pass. * @param {number} [options.backgroundColor=0x000000] - The background color of the rendered area * (shown if not transparent). - * @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when rendering, + * @param {boolean} [options.roundPixels=false] - If true PixiJS will Math.floor() x/y values when rendering, * stopping pixel interpolation. */ - function CanvasRenderer(width, height) { - var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - + function CanvasRenderer(options, arg2, arg3) { _classCallCheck(this, CanvasRenderer); - var _this = _possibleConstructorReturn(this, _SystemRenderer.call(this, 'Canvas', width, height, options)); + var _this = _possibleConstructorReturn(this, _SystemRenderer.call(this, 'Canvas', options, arg2, arg3)); _this.type = _const.RENDERER_TYPE.CANVAS; /** - * The canvas 2d context that everything is drawn with. + * The root canvas 2d context that everything is drawn with. * * @member {CanvasRenderingContext2D} */ _this.rootContext = _this.view.getContext('2d', { alpha: _this.transparent }); + /** + * The currently active canvas 2d context (could change with renderTextures) + * + * @member {CanvasRenderingContext2D} + */ + _this.context = _this.rootContext; + /** * Boolean flag controlling canvas refresh. * @@ -15095,10 +16116,21 @@ var CanvasRenderer = function (_SystemRenderer) { _this.blendModes = (0, _mapCanvasBlendModesToPixi2.default)(); _this._activeBlendMode = null; - _this.context = null; _this.renderingToScreen = false; - _this.resize(width, height); + _this.resize(_this.options.width, _this.options.height); + + /** + * Fired after rendering finishes. + * + * @event PIXI.CanvasRenderer#postrender + */ + + /** + * Fired before rendering starts. + * + * @event PIXI.CanvasRenderer#prerender + */ return _this; } @@ -15124,6 +16156,8 @@ var CanvasRenderer = function (_SystemRenderer) { this.emit('prerender'); + var rootResolution = this.resolution; + if (renderTexture) { renderTexture = renderTexture.baseTexture || renderTexture; @@ -15152,11 +16186,15 @@ var CanvasRenderer = function (_SystemRenderer) { if (transform) { transform.copy(tempWt); + + // lets not forget to flag the parent transform as dirty... + this._tempDisplayObjectParent.transform._worldID = -1; } else { tempWt.identity(); } displayObject.parent = this._tempDisplayObjectParent; + displayObject.updateTransform(); displayObject.parent = cacheParent; // displayObject.hitArea = //TODO add a temp hit area @@ -15164,6 +16202,7 @@ var CanvasRenderer = function (_SystemRenderer) { context.setTransform(1, 0, 0, 1, 0, 0); context.globalAlpha = 1; + this._activeBlendMode = _const.BLEND_MODES.NORMAL; context.globalCompositeOperation = this.blendModes[_const.BLEND_MODES.NORMAL]; if (navigator.isCocoonJS && this.view.screencanvas) { @@ -15191,9 +16230,31 @@ var CanvasRenderer = function (_SystemRenderer) { displayObject.renderCanvas(this); this.context = tempContext; + this.resolution = rootResolution; + this.emit('postrender'); }; + /** + * Clear the canvas of renderer. + * + * @param {string} [clearColor] - Clear the canvas with this color, except the canvas is transparent. + */ + + + CanvasRenderer.prototype.clear = function clear(clearColor) { + var context = this.context; + + clearColor = clearColor || this._backgroundColorString; + + if (!this.transparent && clearColor) { + context.fillStyle = clearColor; + context.fillRect(0, 0, this.width, this.height); + } else { + context.clearRect(0, 0, this.width, this.height); + } + }; + /** * Sets the blend mode of the renderer. * @@ -15206,6 +16267,7 @@ var CanvasRenderer = function (_SystemRenderer) { return; } + this._activeBlendMode = blendMode; this.context.globalCompositeOperation = this.blendModes[blendMode]; }; @@ -15237,30 +16299,58 @@ var CanvasRenderer = function (_SystemRenderer) { * * @extends PIXI.SystemRenderer#resize * - * @param {number} width - The new width of the canvas view - * @param {number} height - The new height of the canvas view + * @param {number} screenWidth - the new width of the screen + * @param {number} screenHeight - the new height of the screen */ - CanvasRenderer.prototype.resize = function resize(width, height) { - _SystemRenderer.prototype.resize.call(this, width, height); + CanvasRenderer.prototype.resize = function resize(screenWidth, screenHeight) { + _SystemRenderer.prototype.resize.call(this, screenWidth, screenHeight); // reset the scale mode.. oddly this seems to be reset when the canvas is resized. - // surely a browser bug?? Let pixi fix that for you.. + // surely a browser bug?? Let PixiJS fix that for you.. if (this.smoothProperty) { - this.rootContext[this.smoothProperty] = _const.SCALE_MODES.DEFAULT === _const.SCALE_MODES.LINEAR; + this.rootContext[this.smoothProperty] = _settings2.default.SCALE_MODE === _const.SCALE_MODES.LINEAR; } }; + /** + * Checks if blend mode has changed. + */ + + + CanvasRenderer.prototype.invalidateBlendMode = function invalidateBlendMode() { + this._activeBlendMode = this.blendModes.indexOf(this.context.globalCompositeOperation); + }; + return CanvasRenderer; }(_SystemRenderer3.default); -exports.default = CanvasRenderer; +/** + * Collection of installed plugins. These are included by default in PIXI, but can be excluded + * by creating a custom build. Consult the README for more information about creating custom + * builds and excluding plugins. + * @name PIXI.CanvasRenderer#plugins + * @type {object} + * @readonly + * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements. + * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer. + * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events. + * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects. + */ +/** + * Adds a plugin to the renderer. + * + * @method PIXI.CanvasRenderer#registerPlugin + * @param {string} pluginName - The name of the plugin. + * @param {Function} ctor - The constructor function or class for the plugin. + */ +exports.default = CanvasRenderer; _utils.pluginTarget.mixin(CanvasRenderer); -},{"../../const":42,"../../utils":115,"../SystemRenderer":72,"./utils/CanvasMaskManager":74,"./utils/CanvasRenderTarget":75,"./utils/mapCanvasBlendModesToPixi":77}],74:[function(require,module,exports){ +},{"../../const":46,"../../settings":101,"../../utils":124,"../SystemRenderer":76,"./utils/CanvasMaskManager":78,"./utils/CanvasRenderTarget":79,"./utils/mapCanvasBlendModesToPixi":81}],78:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -15411,6 +16501,7 @@ var CanvasMaskManager = function () { CanvasMaskManager.prototype.popMask = function popMask(renderer) { renderer.context.restore(); + renderer.invalidateBlendMode(); }; /** @@ -15428,14 +16519,18 @@ var CanvasMaskManager = function () { exports.default = CanvasMaskManager; -},{"../../../const":42}],75:[function(require,module,exports){ +},{"../../../const":46}],79:[function(require,module,exports){ 'use strict'; exports.__esModule = true; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); -var _const = require('../../../const'); +var _settings = require('../../../settings'); + +var _settings2 = _interopRequireDefault(_settings); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -15468,7 +16563,7 @@ var CanvasRenderTarget = function () { */ this.context = this.canvas.getContext('2d'); - this.resolution = resolution || _const.RESOLUTION; + this.resolution = resolution || _settings2.default.RESOLUTION; this.resize(width, height); } @@ -15513,7 +16608,6 @@ var CanvasRenderTarget = function () { * The width of the canvas buffer in pixels. * * @member {number} - * @memberof PIXI.CanvasRenderTarget# */ @@ -15521,15 +16615,9 @@ var CanvasRenderTarget = function () { key: 'width', get: function get() { return this.canvas.width; - } - - /** - * Sets the width. - * - * @param {number} val - The value to set. - */ - , - set: function set(val) { + }, + set: function set(val) // eslint-disable-line require-jsdoc + { this.canvas.width = val; } @@ -15537,22 +16625,15 @@ var CanvasRenderTarget = function () { * The height of the canvas buffer in pixels. * * @member {number} - * @memberof PIXI.CanvasRenderTarget# */ }, { key: 'height', get: function get() { return this.canvas.height; - } - - /** - * Sets the height. - * - * @param {number} val - The value to set. - */ - , - set: function set(val) { + }, + set: function set(val) // eslint-disable-line require-jsdoc + { this.canvas.height = val; } }]); @@ -15562,7 +16643,7 @@ var CanvasRenderTarget = function () { exports.default = CanvasRenderTarget; -},{"../../../const":42}],76:[function(require,module,exports){ +},{"../../../settings":101}],80:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -15571,7 +16652,7 @@ exports.default = canUseNewCanvasBlendModes; * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) { @@ -15623,7 +16704,7 @@ function canUseNewCanvasBlendModes() { return data[0] === 255 && data[1] === 0 && data[2] === 0; } -},{}],77:[function(require,module,exports){ +},{}],81:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -15641,6 +16722,8 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de * Maps blend combinations to Canvas. * * @memberof PIXI + * @function mapCanvasBlendModesToPixi + * @private * @param {string[]} [array=[]] - The array to output into. * @return {string[]} Mapped modes. */ @@ -15685,17 +16768,27 @@ function mapCanvasBlendModesToPixi() { array[_const.BLEND_MODES.COLOR] = 'source-over'; array[_const.BLEND_MODES.LUMINOSITY] = 'source-over'; } + // not-premultiplied, only for webgl + array[_const.BLEND_MODES.NORMAL_NPM] = array[_const.BLEND_MODES.NORMAL]; + array[_const.BLEND_MODES.ADD_NPM] = array[_const.BLEND_MODES.ADD]; + array[_const.BLEND_MODES.SCREEN_NPM] = array[_const.BLEND_MODES.SCREEN]; return array; } -},{"../../../const":42,"./canUseNewCanvasBlendModes":76}],78:[function(require,module,exports){ +},{"../../../const":46,"./canUseNewCanvasBlendModes":80}],82:[function(require,module,exports){ 'use strict'; exports.__esModule = true; var _const = require('../../const'); +var _settings = require('../../settings'); + +var _settings2 = _interopRequireDefault(_settings); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** @@ -15716,10 +16809,9 @@ var TextureGarbageCollector = function () { this.count = 0; this.checkCount = 0; - this.maxIdle = 60 * 60; - this.checkCountMax = 60 * 10; - - this.mode = _const.GC_MODES.DEFAULT; + this.maxIdle = _settings2.default.GC_MAX_IDLE; + this.checkCountMax = _settings2.default.GC_MAX_CHECK_COUNT; + this.mode = _settings2.default.GC_MODE; } /** @@ -15789,7 +16881,8 @@ var TextureGarbageCollector = function () { TextureGarbageCollector.prototype.unload = function unload(displayObject) { var tm = this.renderer.textureManager; - if (displayObject._texture) { + // only destroy non generated textures + if (displayObject._texture && displayObject._texture._glRenderTargets) { tm.destroyTexture(displayObject._texture, true); } @@ -15803,7 +16896,7 @@ var TextureGarbageCollector = function () { exports.default = TextureGarbageCollector; -},{"../../const":42}],79:[function(require,module,exports){ +},{"../../const":46,"../../settings":101}],83:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -15882,12 +16975,16 @@ var TextureManager = function () { * Updates and/or Creates a WebGL texture for the renderer's context. * * @param {PIXI.BaseTexture|PIXI.Texture} texture - the texture to update + * @param {number} location - the location the texture will be bound to. * @return {GLTexture} The gl texture. */ ; - TextureManager.prototype.updateTexture = function updateTexture(texture) { - texture = texture.baseTexture || texture; + TextureManager.prototype.updateTexture = function updateTexture(texture, location) { + // assume it good! + // texture = texture.baseTexture || texture; + + var gl = this.gl; var isRenderTexture = !!texture._glRenderTargets; @@ -15895,6 +16992,28 @@ var TextureManager = function () { return null; } + var boundTextures = this.renderer.boundTextures; + + // if the location is undefined then this may have been called by n event. + // this being the case the texture may already be bound to a slot. As a texture can only be bound once + // we need to find its current location if it exists. + if (location === undefined) { + location = 0; + + // TODO maybe we can use texture bound ids later on... + // check if texture is already bound.. + for (var i = 0; i < boundTextures.length; ++i) { + if (boundTextures[i] === texture) { + location = i; + break; + } + } + } + + boundTextures[location] = texture; + + gl.activeTexture(gl.TEXTURE0 + location); + var glTexture = texture._glTextures[this.renderer.CONTEXT_UID]; if (!glTexture) { @@ -15905,7 +17024,8 @@ var TextureManager = function () { texture._glRenderTargets[this.renderer.CONTEXT_UID] = renderTarget; glTexture = renderTarget.texture; } else { - glTexture = new _pixiGlCore.GLTexture(this.gl); + glTexture = new _pixiGlCore.GLTexture(this.gl, null, null, null, null); + glTexture.bind(location); glTexture.premultiplyAlpha = true; glTexture.upload(texture.source); } @@ -15939,7 +17059,7 @@ var TextureManager = function () { glTexture.enableLinearScaling(); } } - // the textur ealrady exists so we only need to update it.. + // the texture already exists so we only need to update it.. else if (isRenderTexture) { texture._glRenderTargets[this.renderer.CONTEXT_UID].resize(texture.width, texture.height); } else { @@ -15964,12 +17084,18 @@ var TextureManager = function () { return; } - if (texture._glTextures[this.renderer.CONTEXT_UID]) { - texture._glTextures[this.renderer.CONTEXT_UID].destroy(); + var uid = this.renderer.CONTEXT_UID; + var glTextures = texture._glTextures; + var glRenderTargets = texture._glRenderTargets; + + if (glTextures[uid]) { + this.renderer.unbindTexture(texture); + + glTextures[uid].destroy(); texture.off('update', this.updateTexture, this); texture.off('dispose', this.destroyTexture, this); - delete texture._glTextures[this.renderer.CONTEXT_UID]; + delete glTextures[uid]; if (!skipRemove) { var i = this._managedTextures.indexOf(texture); @@ -15979,6 +17105,11 @@ var TextureManager = function () { } } } + + if (glRenderTargets && glRenderTargets[uid]) { + glRenderTargets[uid].destroy(); + delete glRenderTargets[uid]; + } }; /** @@ -16021,7 +17152,7 @@ var TextureManager = function () { exports.default = TextureManager; -},{"../../const":42,"../../utils":115,"./utils/RenderTarget":92,"pixi-gl-core":7}],80:[function(require,module,exports){ +},{"../../const":46,"../../utils":124,"./utils/RenderTarget":96,"pixi-gl-core":7}],84:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -16054,6 +17185,10 @@ var _TextureManager = require('./TextureManager'); var _TextureManager2 = _interopRequireDefault(_TextureManager); +var _BaseTexture = require('../../textures/BaseTexture'); + +var _BaseTexture2 = _interopRequireDefault(_BaseTexture); + var _TextureGarbageCollector = require('./TextureGarbageCollector'); var _TextureGarbageCollector2 = _interopRequireDefault(_TextureGarbageCollector); @@ -16102,11 +17237,12 @@ var CONTEXT_UID = 0; var WebGLRenderer = function (_SystemRenderer) { _inherits(WebGLRenderer, _SystemRenderer); + // eslint-disable-next-line valid-jsdoc /** * - * @param {number} [width=0] - the width of the canvas view - * @param {number} [height=0] - the height of the canvas view * @param {object} [options] - The optional renderer parameters + * @param {number} [options.width=800] - the width of the screen + * @param {number} [options.height=600] - the height of the screen * @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional * @param {boolean} [options.transparent=false] - If the render view is transparent, default false * @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false @@ -16116,27 +17252,37 @@ var WebGLRenderer = function (_SystemRenderer) { * FXAA is faster, but may not always look as great * @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer. * The resolution of the renderer retina would be 2. - * @param {boolean} [options.clearBeforeRender=true] - This sets if the CanvasRenderer will clear + * @param {boolean} [options.clearBeforeRender=true] - This sets if the renderer will clear * the canvas or not before the new render pass. If you wish to set this to false, you *must* set * preserveDrawingBuffer to `true`. * @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation, * enable this if you need to call toDataUrl on the webgl context. - * @param {boolean} [options.roundPixels=false] - If true Pixi will Math.floor() x/y values when + * @param {boolean} [options.roundPixels=false] - If true PixiJS will Math.floor() x/y values when * rendering, stopping pixel interpolation. + * @param {number} [options.backgroundColor=0x000000] - The background color of the rendered area + * (shown if not transparent). + * @param {boolean} [options.legacy=false] - If true PixiJS will aim to ensure compatibility + * with older / less advanced devices. If you experiance unexplained flickering try setting this to true. + * @param {string} [options.powerPreference] - Parameter passed to webgl context, set to "high-performance" + * for devices with dual graphics card */ - function WebGLRenderer(width, height) { - var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - + function WebGLRenderer(options, arg2, arg3) { _classCallCheck(this, WebGLRenderer); + var _this = _possibleConstructorReturn(this, _SystemRenderer.call(this, 'WebGL', options, arg2, arg3)); + + _this.legacy = _this.options.legacy; + + if (_this.legacy) { + _pixiGlCore2.default.VertexArrayObject.FORCE_NATIVE = true; + } + /** * The type of this renderer as a standardised const * * @member {number} * @see PIXI.RENDERER_TYPE */ - var _this = _possibleConstructorReturn(this, _SystemRenderer.call(this, 'WebGL', width, height, options)); - _this.type = _const.RENDERER_TYPE.WEBGL; _this.handleContextLost = _this.handleContextLost.bind(_this); @@ -16153,10 +17299,11 @@ var WebGLRenderer = function (_SystemRenderer) { */ _this._contextOptions = { alpha: _this.transparent, - antialias: options.antialias, + antialias: _this.options.antialias, premultipliedAlpha: _this.transparent && _this.transparent !== 'notMultiplied', stencil: true, - preserveDrawingBuffer: options.preserveDrawingBuffer + preserveDrawingBuffer: _this.options.preserveDrawingBuffer, + powerPreference: _this.options.powerPreference }; _this._backgroundColorRgba[3] = _this.transparent ? 0 : 1; @@ -16197,12 +17344,12 @@ var WebGLRenderer = function (_SystemRenderer) { * @member {WebGLRenderingContext} */ // initialize the context so it is ready for the managers. - if (options.context) { + if (_this.options.context) { // checks to see if a context is valid.. - (0, _validateContext2.default)(options.context); + (0, _validateContext2.default)(_this.options.context); } - _this.gl = options.context || _pixiGlCore2.default.createContext(_this.view, _this._contextOptions); + _this.gl = _this.options.context || _pixiGlCore2.default.createContext(_this.view, _this._contextOptions); _this.CONTEXT_UID = CONTEXT_UID++; @@ -16215,6 +17362,28 @@ var WebGLRenderer = function (_SystemRenderer) { _this.renderingToScreen = true; + /** + * Holds the current state of textures bound to the GPU. + * @type {Array} + */ + _this.boundTextures = null; + + /** + * Holds the current shader + * + * @member {PIXI.Shader} + */ + _this._activeShader = null; + + _this._activeVao = null; + + /** + * Holds the current render target + * + * @member {PIXI.RenderTarget} + */ + _this._activeRenderTarget = null; + _this._initContext(); /** @@ -16226,23 +17395,28 @@ var WebGLRenderer = function (_SystemRenderer) { // map some webGL blend and drawmodes.. _this.drawModes = (0, _mapWebGLDrawModesToPixi2.default)(_this.gl); + _this._nextTextureLocation = 0; + + _this.setBlendMode(0); + /** - * Holds the current shader + * Fired after rendering finishes. * - * @member {PIXI.Shader} + * @event PIXI.WebGLRenderer#postrender */ - _this._activeShader = null; /** - * Holds the current render target + * Fired before rendering starts. * - * @member {PIXI.RenderTarget} + * @event PIXI.WebGLRenderer#prerender */ - _this._activeRenderTarget = null; - _this._activeTextureLocation = 999; - _this._activeTexture = null; - _this.setBlendMode(0); + /** + * Fired when the WebGL context is set. + * + * @event PIXI.WebGLRenderer#context + * @param {WebGLRenderingContext} gl - WebGL context. + */ return _this; } @@ -16261,6 +17435,14 @@ var WebGLRenderer = function (_SystemRenderer) { gl.getExtension('WEBGL_lose_context').restoreContext(); } + var maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS); + + this._activeShader = null; + this._activeVao = null; + + this.boundTextures = new Array(maxTextures); + this.emptyTextures = new Array(maxTextures); + // create a texture manager... this.textureManager = new _TextureManager2.default(this); this.textureGC = new _TextureGarbageCollector2.default(this); @@ -16272,10 +17454,27 @@ var WebGLRenderer = function (_SystemRenderer) { this.bindRenderTarget(this.rootRenderTarget); + // now lets fill up the textures with empty ones! + var emptyGLTexture = new _pixiGlCore2.default.GLTexture.fromData(gl, null, 1, 1); + + var tempObj = { _glTextures: {} }; + + tempObj._glTextures[this.CONTEXT_UID] = {}; + + for (var i = 0; i < maxTextures; i++) { + var empty = new _BaseTexture2.default(); + + empty._glTextures[this.CONTEXT_UID] = emptyGLTexture; + + this.boundTextures[i] = tempObj; + this.emptyTextures[i] = empty; + this.bindTexture(null, i); + } + this.emit('context', gl); // setup the width/height properties and gl viewport - this.resize(this.width, this.height); + this.resize(this.screen.width, this.screen.height); }; /** @@ -16300,6 +17499,8 @@ var WebGLRenderer = function (_SystemRenderer) { return; } + this._nextTextureLocation = 0; + if (!renderTexture) { this._lastObjectRendered = displayObject; } @@ -16352,7 +17553,7 @@ var WebGLRenderer = function (_SystemRenderer) { }; /** - * This shoudl be called if you wish to do some custom rendering + * This should be called if you wish to do some custom rendering * It will basically render anything that may be batched up such as sprites * */ @@ -16365,17 +17566,17 @@ var WebGLRenderer = function (_SystemRenderer) { /** * Resizes the webGL view to the specified width and height. * - * @param {number} width - the new width of the webGL view - * @param {number} height - the new height of the webGL view + * @param {number} screenWidth - the new width of the screen + * @param {number} screenHeight - the new height of the screen */ - WebGLRenderer.prototype.resize = function resize(width, height) { + WebGLRenderer.prototype.resize = function resize(screenWidth, screenHeight) { // if(width * this.resolution === this.width && height * this.resolution === this.height)return; - _SystemRenderer3.default.prototype.resize.call(this, width, height); + _SystemRenderer3.default.prototype.resize.call(this, screenWidth, screenHeight); - this.rootRenderTarget.resize(width, height); + this.rootRenderTarget.resize(screenWidth, screenHeight); if (this._activeRenderTarget === this.rootRenderTarget) { this.rootRenderTarget.activate(); @@ -16419,6 +17620,26 @@ var WebGLRenderer = function (_SystemRenderer) { this._activeRenderTarget.transform = matrix; }; + /** + * Erases the render texture and fills the drawing area with a colour + * + * @param {PIXI.RenderTexture} renderTexture - The render texture to clear + * @param {number} [clearColor] - The colour + * @return {PIXI.WebGLRenderer} Returns itself. + */ + + + WebGLRenderer.prototype.clearRenderTexture = function clearRenderTexture(renderTexture, clearColor) { + var baseTexture = renderTexture.baseTexture; + var renderTarget = baseTexture._glRenderTargets[this.CONTEXT_UID]; + + if (renderTarget) { + renderTarget.clear(clearColor); + } + + return this; + }; + /** * Binds a render texture for rendering * @@ -16433,18 +17654,14 @@ var WebGLRenderer = function (_SystemRenderer) { if (renderTexture) { var baseTexture = renderTexture.baseTexture; - var gl = this.gl; if (!baseTexture._glRenderTargets[this.CONTEXT_UID]) { - this.textureManager.updateTexture(baseTexture); - gl.bindTexture(gl.TEXTURE_2D, null); - } else { - // the texture needs to be unbound if its being rendererd too.. - this._activeTextureLocation = baseTexture._id; - gl.activeTexture(gl.TEXTURE0 + baseTexture._id); - gl.bindTexture(gl.TEXTURE_2D, null); + // bind the current texture + this.textureManager.updateTexture(baseTexture, 0); } + this.unbindTexture(baseTexture); + renderTarget = baseTexture._glRenderTargets[this.CONTEXT_UID]; renderTarget.setFrame(renderTexture.frame); } else { @@ -16484,57 +17701,100 @@ var WebGLRenderer = function (_SystemRenderer) { * Changes the current shader to the one given in parameter * * @param {PIXI.Shader} shader - the new shader + * @param {boolean} [autoProject=true] - Whether automatically set the projection matrix * @return {PIXI.WebGLRenderer} Returns itself. */ - WebGLRenderer.prototype.bindShader = function bindShader(shader) { + WebGLRenderer.prototype.bindShader = function bindShader(shader, autoProject) { // TODO cache if (this._activeShader !== shader) { this._activeShader = shader; shader.bind(); - // automatically set the projection matrix - shader.uniforms.projectionMatrix = this._activeRenderTarget.projectionMatrix.toArray(true); + // `autoProject` normally would be a default parameter set to true + // but because of how Babel transpiles default parameters + // it hinders the performance of this method. + if (autoProject !== false) { + // automatically set the projection matrix + shader.uniforms.projectionMatrix = this._activeRenderTarget.projectionMatrix.toArray(true); + } } return this; }; /** - * Binds the texture ... @mat + * Binds the texture. This will return the location of the bound texture. + * It may not be the same as the one you pass in. This is due to optimisation that prevents + * needless binding of textures. For example if the texture is already bound it will return the + * current location of the texture instead of the one provided. To bypass this use force location * * @param {PIXI.Texture} texture - the new texture - * @param {number} location - the texture location - * @return {PIXI.WebGLRenderer} Returns itself. + * @param {number} location - the suggested texture location + * @param {boolean} forceLocation - force the location + * @return {number} bound texture location */ - WebGLRenderer.prototype.bindTexture = function bindTexture(texture) { - var location = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - + WebGLRenderer.prototype.bindTexture = function bindTexture(texture, location, forceLocation) { + texture = texture || this.emptyTextures[location]; texture = texture.baseTexture || texture; + texture.touched = this.textureGC.count; - var gl = this.gl; - - // TODO test perf of cache? + if (!forceLocation) { + // TODO - maybe look into adding boundIds.. save us the loop? + for (var i = 0; i < this.boundTextures.length; i++) { + if (this.boundTextures[i] === texture) { + return i; + } + } - if (this._activeTextureLocation !== location) // - { - this._activeTextureLocation = location; - gl.activeTexture(gl.TEXTURE0 + location); + if (location === undefined) { + this._nextTextureLocation++; + this._nextTextureLocation %= this.boundTextures.length; + location = this.boundTextures.length - this._nextTextureLocation - 1; } + } else { + location = location || 0; + } - // TODO - can we cache this texture too? - this._activeTexture = texture; + var gl = this.gl; + var glTexture = texture._glTextures[this.CONTEXT_UID]; - if (!texture._glTextures[this.CONTEXT_UID]) { + if (!glTexture) { // this will also bind the texture.. - this.textureManager.updateTexture(texture); + this.textureManager.updateTexture(texture, location); } else { - texture.touched = this.textureGC.count; // bind the current texture - texture._glTextures[this.CONTEXT_UID].bind(); + this.boundTextures[location] = texture; + gl.activeTexture(gl.TEXTURE0 + location); + gl.bindTexture(gl.TEXTURE_2D, glTexture.texture); + } + + return location; + }; + + /** + * unbinds the texture ... + * + * @param {PIXI.Texture} texture - the texture to unbind + * @return {PIXI.WebGLRenderer} Returns itself. + */ + + + WebGLRenderer.prototype.unbindTexture = function unbindTexture(texture) { + var gl = this.gl; + + texture = texture.baseTexture || texture; + + for (var i = 0; i < this.boundTextures.length; i++) { + if (this.boundTextures[i] === texture) { + this.boundTextures[i] = this.emptyTextures[i]; + + gl.activeTexture(gl.TEXTURE0 + i); + gl.bindTexture(gl.TEXTURE_2D, this.emptyTextures[i]._glTextures[this.CONTEXT_UID].texture); + } } return this; @@ -16551,6 +17811,31 @@ var WebGLRenderer = function (_SystemRenderer) { return new _pixiGlCore2.default.VertexArrayObject(this.gl, this.state.attribState); }; + /** + * Changes the current Vao to the one given in parameter + * + * @param {PIXI.VertexArrayObject} vao - the new Vao + * @return {PIXI.WebGLRenderer} Returns itself. + */ + + + WebGLRenderer.prototype.bindVao = function bindVao(vao) { + if (this._activeVao === vao) { + return this; + } + + if (vao) { + vao.bind(); + } else if (this._activeVao) { + // TODO this should always be true i think? + this._activeVao.unbind(); + } + + this._activeVao = vao; + + return this; + }; + /** * Resets the WebGL state so you can render things however you fancy! * @@ -16563,8 +17848,6 @@ var WebGLRenderer = function (_SystemRenderer) { this._activeShader = null; this._activeRenderTarget = this.rootRenderTarget; - this._activeTextureLocation = 999; - this._activeTexture = null; // bind the main frame buffer (the screen); this.rootRenderTarget.activate(); @@ -16594,8 +17877,8 @@ var WebGLRenderer = function (_SystemRenderer) { WebGLRenderer.prototype.handleContextRestored = function handleContextRestored() { - this._initContext(); this.textureManager.removeAll(); + this._initContext(); }; /** @@ -16648,12 +17931,31 @@ var WebGLRenderer = function (_SystemRenderer) { return WebGLRenderer; }(_SystemRenderer3.default); -exports.default = WebGLRenderer; +/** + * Collection of installed plugins. These are included by default in PIXI, but can be excluded + * by creating a custom build. Consult the README for more information about creating custom + * builds and excluding plugins. + * @name PIXI.WebGLRenderer#plugins + * @type {object} + * @readonly + * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements. + * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer. + * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events. + * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects. + */ +/** + * Adds a plugin to the renderer. + * + * @method PIXI.WebGLRenderer#registerPlugin + * @param {string} pluginName - The name of the plugin. + * @param {Function} ctor - The constructor function or class for the plugin. + */ +exports.default = WebGLRenderer; _utils.pluginTarget.mixin(WebGLRenderer); -},{"../../const":42,"../../utils":115,"../SystemRenderer":72,"./TextureGarbageCollector":78,"./TextureManager":79,"./WebGLState":81,"./managers/FilterManager":86,"./managers/MaskManager":87,"./managers/StencilManager":88,"./utils/ObjectRenderer":90,"./utils/RenderTarget":92,"./utils/mapWebGLDrawModesToPixi":95,"./utils/validateContext":96,"pixi-gl-core":7}],81:[function(require,module,exports){ +},{"../../const":46,"../../textures/BaseTexture":112,"../../utils":124,"../SystemRenderer":76,"./TextureGarbageCollector":82,"./TextureManager":83,"./WebGLState":85,"./managers/FilterManager":90,"./managers/MaskManager":91,"./managers/StencilManager":92,"./utils/ObjectRenderer":94,"./utils/RenderTarget":96,"./utils/mapWebGLDrawModesToPixi":99,"./utils/validateContext":100,"pixi-gl-core":7}],85:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -16746,16 +18048,18 @@ var WebGLState = function () { WebGLState.prototype.push = function push() { // next state.. - var state = this.stack[++this.stackIndex]; + var state = this.stack[this.stackIndex]; if (!state) { state = this.stack[this.stackIndex] = new Uint8Array(16); } + ++this.stackIndex; + // copy state.. // set active state so we can force overrides of gl state for (var i = 0; i < this.activeState.length; i++) { - this.activeState[i] = state[i]; + state[i] = this.activeState[i]; } }; @@ -16817,7 +18121,13 @@ var WebGLState = function () { this.activeState[BLEND_FUNC] = value; - this.gl.blendFunc(this.blendModes[value][0], this.blendModes[value][1]); + var mode = this.blendModes[value]; + + if (mode.length === 2) { + this.gl.blendFunc(mode[0], mode[1]); + } else { + this.gl.blendFuncSeparate(mode[0], mode[1], mode[2], mode[3]); + } }; /** @@ -16907,7 +18217,7 @@ var WebGLState = function () { this.nativeVaoExtension.bindVertexArrayOES(null); } - // reset all attributs.. + // reset all attributes.. this.resetAttributes(); // set active state so we can force overrides of gl state @@ -16925,7 +18235,7 @@ var WebGLState = function () { exports.default = WebGLState; -},{"./utils/mapWebGLBlendModesToPixi":94}],82:[function(require,module,exports){ +},{"./utils/mapWebGLBlendModesToPixi":98}],86:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -16940,6 +18250,10 @@ var _utils = require('../../../utils'); var _const = require('../../../const'); +var _settings = require('../../../settings'); + +var _settings2 = _interopRequireDefault(_settings); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -16976,12 +18290,17 @@ var Filter = function () { */ this.fragmentSrc = fragmentSrc || Filter.defaultFragmentSrc; - this.blendMode = _const.BLEND_MODES.NORMAL; + this._blendMode = _const.BLEND_MODES.NORMAL; - // pull out the vertex and shader uniforms if they are not specified.. - // currently this does not extract structs only default types this.uniformData = uniforms || (0, _extractUniformsFromSrc2.default)(this.vertexSrc, this.fragmentSrc, 'projectionMatrix|uSampler'); + /** + * An object containing the current values of custom uniforms. + * @example Updating the value of a custom uniform + * filter.uniforms.time = performance.now(); + * + * @member {object} + */ this.uniforms = {}; for (var i in this.uniformData) { @@ -16990,7 +18309,7 @@ var Filter = function () { // this is where we store shader references.. // TODO we could cache this! - this.glShaders = []; + this.glShaders = {}; // used for cacheing.. sure there is a better way! if (!SOURCE_KEY_MAP[this.vertexSrc + this.fragmentSrc]) { @@ -17014,7 +18333,7 @@ var Filter = function () { * * @member {number} */ - this.resolution = 1; + this.resolution = _settings2.default.RESOLUTION; /** * If enabled is true the filter is applied, if false it will not. @@ -17022,6 +18341,14 @@ var Filter = function () { * @member {boolean} */ this.enabled = true; + + /** + * If enabled, PixiJS will fit the filter area into boundaries for better performance. + * Switch it off if it does not work for specific shader. + * + * @member {boolean} + */ + this.autoFit = true; } /** @@ -17031,10 +18358,14 @@ var Filter = function () { * @param {PIXI.RenderTarget} input - The input render target. * @param {PIXI.RenderTarget} output - The target to output to. * @param {boolean} clear - Should the output be cleared before rendering to it + * @param {object} [currentState] - It's current state of filter. + * There are some useful properties in the currentState : + * target, filters, sourceFrame, destinationFrame, renderTarget, resolution */ - Filter.prototype.apply = function apply(filterManager, input, output, clear) { + Filter.prototype.apply = function apply(filterManager, input, output, clear, currentState) // eslint-disable-line no-unused-vars + { // --- // // this.uniforms.filterMatrix = filterManager.calculateSpriteMatrix(tempMatrix, window.panda ); @@ -17046,14 +18377,31 @@ var Filter = function () { }; /** - * The default vertex shader source + * Sets the blendmode of the filter * - * @static - * @constant + * @member {number} + * @default PIXI.BLEND_MODES.NORMAL */ - _createClass(Filter, null, [{ + _createClass(Filter, [{ + key: 'blendMode', + get: function get() { + return this._blendMode; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { + this._blendMode = value; + } + + /** + * The default vertex shader source + * + * @static + * @constant + */ + + }], [{ key: 'defaultVertexSrc', get: function get() { return ['attribute vec2 aVertexPosition;', 'attribute vec2 aTextureCoord;', 'uniform mat3 projectionMatrix;', 'uniform mat3 filterMatrix;', 'varying vec2 vTextureCoord;', 'varying vec2 vFilterCoord;', 'void main(void){', ' gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);', ' vFilterCoord = ( filterMatrix * vec3( aTextureCoord, 1.0) ).xy;', ' vTextureCoord = aTextureCoord ;', '}'].join('\n'); @@ -17080,7 +18428,7 @@ var Filter = function () { exports.default = Filter; -},{"../../../const":42,"../../../utils":115,"./extractUniformsFromSrc":83}],83:[function(require,module,exports){ +},{"../../../const":46,"../../../settings":101,"../../../utils":124,"./extractUniformsFromSrc":87}],87:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -17102,12 +18450,12 @@ function extractUniformsFromSrc(vertexSrc, fragmentSrc, mask) { } function extractUniformsFromString(string) { - var maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea)$'); + var maskRegex = new RegExp('^(projectionMatrix|uSampler|filterArea|filterClamp)$'); var uniforms = {}; var nameSplit = void 0; - // clean the lines a little - remove extra spaces / teabs etc + // clean the lines a little - remove extra spaces / tabs etc // then split along ';' var lines = string.replace(/\s+/g, ' ').split(/\s*;\s*/); @@ -17124,7 +18472,7 @@ function extractUniformsFromString(string) { if (name.indexOf('[') > -1) { // array! - nameSplit = name.split(/\[|\]/); + nameSplit = name.split(/\[|]/); name = nameSplit[0]; size *= Number(nameSplit[1]); } @@ -17142,7 +18490,7 @@ function extractUniformsFromString(string) { return uniforms; } -},{"pixi-gl-core":7}],84:[function(require,module,exports){ +},{"pixi-gl-core":7}],88:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -17152,14 +18500,14 @@ exports.calculateSpriteMatrix = calculateSpriteMatrix; var _math = require('../../../math'); -/* +/** * Calculates the mapped matrix * @param filterArea {Rectangle} The filter area * @param sprite {Sprite} the target sprite * @param outputMatrix {Matrix} @alvin */ // TODO playing around here.. this is temporary - (will end up in the shader) -// thia returns a matrix that will normalise map filter cords in the filter to screen space +// this returns a matrix that will normalise map filter cords in the filter to screen space function calculateScreenSpaceMatrix(outputMatrix, filterArea, textureSize) { // let worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX), // let texture = {width:1136, height:700};//sprite._texture.baseTexture; @@ -17224,7 +18572,7 @@ function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite) { return mappedMatrix; } -},{"../../../math":66}],85:[function(require,module,exports){ +},{"../../../math":70}],89:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -17235,6 +18583,8 @@ var _Filter3 = _interopRequireDefault(_Filter2); var _math = require('../../../../math'); +var _path = require('path'); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -17243,9 +18593,6 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } -// @see https://github.com/substack/brfs/issues/25 - // eslint-disable-line no-undef - /** * The SpriteMaskFilter class * @@ -17253,7 +18600,6 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" * @extends PIXI.Filter * @memberof PIXI */ - var SpriteMaskFilter = function (_Filter) { _inherits(SpriteMaskFilter, _Filter); @@ -17265,7 +18611,7 @@ var SpriteMaskFilter = function (_Filter) { var maskMatrix = new _math.Matrix(); - var _this = _possibleConstructorReturn(this, _Filter.call(this, "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 projectionMatrix;\nuniform mat3 otherMatrix;\n\nvarying vec2 vMaskCoord;\nvarying vec2 vTextureCoord;\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n\n vTextureCoord = aTextureCoord;\n vMaskCoord = ( otherMatrix * vec3( aTextureCoord, 1.0) ).xy;\n}\n", "#define GLSLIFY 1\nvarying vec2 vMaskCoord;\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uSampler;\nuniform float alpha;\nuniform sampler2D mask;\n\nvoid main(void)\n{\n // check clip! this will stop the mask bleeding out from the edges\n vec2 text = abs( vMaskCoord - 0.5 );\n text = step(0.5, text);\n\n float clip = 1.0 - max(text.y, text.x);\n vec4 original = texture2D(uSampler, vTextureCoord);\n vec4 masky = texture2D(mask, vMaskCoord);\n\n original *= (masky.r * masky.a * alpha * clip);\n\n gl_FragColor = original;\n}\n")); + var _this = _possibleConstructorReturn(this, _Filter.call(this, 'attribute vec2 aVertexPosition;\r\nattribute vec2 aTextureCoord;\r\n\r\nuniform mat3 projectionMatrix;\r\nuniform mat3 otherMatrix;\r\n\r\nvarying vec2 vMaskCoord;\r\nvarying vec2 vTextureCoord;\r\n\r\nvoid main(void)\r\n{\r\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\r\n\r\n vTextureCoord = aTextureCoord;\r\n vMaskCoord = ( otherMatrix * vec3( aTextureCoord, 1.0) ).xy;\r\n}\r\n', 'varying vec2 vMaskCoord;\r\nvarying vec2 vTextureCoord;\r\n\r\nuniform sampler2D uSampler;\r\nuniform float alpha;\r\nuniform sampler2D mask;\r\n\r\nvoid main(void)\r\n{\r\n // check clip! this will stop the mask bleeding out from the edges\r\n vec2 text = abs( vMaskCoord - 0.5 );\r\n text = step(0.5, text);\r\n\r\n float clip = 1.0 - max(text.y, text.x);\r\n vec4 original = texture2D(uSampler, vTextureCoord);\r\n vec4 masky = texture2D(mask, vMaskCoord);\r\n\r\n original *= (masky.r * masky.a * alpha * clip);\r\n\r\n gl_FragColor = original;\r\n}\r\n')); sprite.renderable = false; @@ -17298,7 +18644,7 @@ var SpriteMaskFilter = function (_Filter) { exports.default = SpriteMaskFilter; -},{"../../../../math":66,"../Filter":82}],86:[function(require,module,exports){ +},{"../../../../math":70,"../Filter":86,"path":25}],90:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -17440,19 +18786,19 @@ var FilterManager = function (_WebGLManager) { if (filterData.stack[0].renderTarget.transform) {// // TODO we should fit the rect around the transform.. - } else { + } else if (filters[0].autoFit) { sourceFrame.fit(filterData.stack[0].destinationFrame); } - // lets pplay the padding After we fit the element to the screen. - // this should stop the strange side effects that can occour when cropping to the edges + // lets apply the padding After we fit the element to the screen. + // this should stop the strange side effects that can occur when cropping to the edges sourceFrame.pad(padding); destinationFrame.width = sourceFrame.width; destinationFrame.height = sourceFrame.height; // lets play the padding after we fit the element to the screen. - // this should stop the strange side effects that can occour when cropping to the edges + // this should stop the strange side effects that can occur when cropping to the edges var renderTarget = this.getPotRenderTarget(renderer.gl, sourceFrame.width, sourceFrame.height, resolution); @@ -17461,14 +18807,13 @@ var FilterManager = function (_WebGLManager) { currentState.resolution = resolution; currentState.renderTarget = renderTarget; - // bind the render taget to draw the shape in the top corner.. + // bind the render target to draw the shape in the top corner.. renderTarget.setFrame(destinationFrame, sourceFrame); + // bind the render target renderer.bindRenderTarget(renderTarget); - - // clear the renderTarget - renderer.clear(); // [0.5,0.5,0.5, 1.0]); + renderTarget.clear(); }; /** @@ -17488,7 +18833,7 @@ var FilterManager = function (_WebGLManager) { var filters = currentState.filters; if (filters.length === 1) { - filters[0].apply(this, currentState.renderTarget, lastState.renderTarget, false); + filters[0].apply(this, currentState.renderTarget, lastState.renderTarget, false, currentState); this.freePotRenderTarget(currentState.renderTarget); } else { var flip = currentState.renderTarget; @@ -17496,10 +18841,13 @@ var FilterManager = function (_WebGLManager) { flop.setFrame(currentState.destinationFrame, currentState.sourceFrame); + // finally lets clear the render target before drawing to it.. + flop.clear(); + var i = 0; for (i = 0; i < filters.length - 1; ++i) { - filters[i].apply(this, flip, flop, true); + filters[i].apply(this, flip, flop, true, currentState); var t = flip; @@ -17507,7 +18855,7 @@ var FilterManager = function (_WebGLManager) { flop = t; } - filters[i].apply(this, flip, lastState.renderTarget, false); + filters[i].apply(this, flip, lastState.renderTarget, false, currentState); this.freePotRenderTarget(flip); this.freePotRenderTarget(flop); @@ -17532,6 +18880,8 @@ var FilterManager = function (_WebGLManager) { FilterManager.prototype.applyFilter = function applyFilter(filter, input, output, clear) { var renderer = this.renderer; + var gl = renderer.gl; + var shader = filter.glShaders[renderer.CONTEXT_UID]; // cacheing.. @@ -17549,14 +18899,16 @@ var FilterManager = function (_WebGLManager) { } // TODO - this only needs to be done once? + renderer.bindVao(null); + this.quad.initVao(shader); } + renderer.bindVao(this.quad.vao); + renderer.bindRenderTarget(output); if (clear) { - var gl = renderer.gl; - gl.disable(gl.SCISSOR_TEST); renderer.clear(); // [1, 1, 1, 1]); gl.enable(gl.SCISSOR_TEST); @@ -17569,17 +18921,23 @@ var FilterManager = function (_WebGLManager) { renderer.bindShader(shader); - // this syncs the pixi filters uniforms with glsl uniforms - this.syncUniforms(shader, filter); + // free unit 0 for us, doesn't matter what was there + // don't try to restore it, because syncUniforms can upload it to another slot + // and it'll be a problem + var tex = this.renderer.emptyTextures[0]; - // bind the input texture.. - input.texture.bind(0); - // when you manually bind a texture, please switch active texture location to it - renderer._activeTextureLocation = 0; + this.renderer.boundTextures[0] = tex; + // this syncs the PixiJS filters uniforms with glsl uniforms + this.syncUniforms(shader, filter); renderer.state.setBlendMode(filter.blendMode); - this.quad.draw(); + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, input.texture.texture); + + this.quad.vao.draw(this.renderer.gl.TRIANGLES, 6, 0); + + gl.bindTexture(gl.TEXTURE_2D, tex._glTextures[this.renderer.CONTEXT_UID].texture); }; /** @@ -17594,12 +18952,16 @@ var FilterManager = function (_WebGLManager) { var uniformData = filter.uniformData; var uniforms = filter.uniforms; - // 0 is reserverd for the pixi texture so we start at 1! + // 0 is reserved for the PixiJS texture so we start at 1! var textureCount = 1; var currentState = void 0; - if (shader.uniforms.data.filterArea) { + // filterArea and filterClamp that are handled by FilterManager directly + // they must not appear in uniformData + + if (shader.uniforms.filterArea) { currentState = this.filterData.stack[this.filterData.index]; + var filterArea = shader.uniforms.filterArea; filterArea[0] = currentState.renderTarget.size.width; @@ -17612,8 +18974,8 @@ var FilterManager = function (_WebGLManager) { // use this to clamp displaced texture coords so they belong to filterArea // see displacementFilter fragment shader for an example - if (shader.uniforms.data.filterClamp) { - currentState = this.filterData.stack[this.filterData.index]; + if (shader.uniforms.filterClamp) { + currentState = currentState || this.filterData.stack[this.filterData.index]; var filterClamp = shader.uniforms.filterClamp; @@ -17627,27 +18989,28 @@ var FilterManager = function (_WebGLManager) { // TODO Cacheing layer.. for (var i in uniformData) { - if (uniformData[i].type === 'sampler2D') { - shader.uniforms[i] = textureCount; - + if (uniformData[i].type === 'sampler2D' && uniforms[i] !== 0) { if (uniforms[i].baseTexture) { - this.renderer.bindTexture(uniforms[i].baseTexture, textureCount); + shader.uniforms[i] = this.renderer.bindTexture(uniforms[i].baseTexture, textureCount); } else { + shader.uniforms[i] = textureCount; + + // TODO // this is helpful as renderTargets can also be set. // Although thinking about it, we could probably // make the filter texture cache return a RenderTexture // rather than a renderTarget var gl = this.renderer.gl; - this.renderer._activeTextureLocation = gl.TEXTURE0 + textureCount; - + this.renderer.boundTextures[textureCount] = this.renderer.emptyTextures[textureCount]; gl.activeTexture(gl.TEXTURE0 + textureCount); + uniforms[i].texture.bind(); } textureCount++; } else if (uniformData[i].type === 'mat3') { - // check if its pixi matrix.. + // check if its PixiJS matrix.. if (uniforms[i].a !== undefined) { shader.uniforms[i] = uniforms[i].toArray(true); } else { @@ -17756,7 +19119,7 @@ var FilterManager = function (_WebGLManager) { FilterManager.prototype.destroy = function destroy() { - this.shaderCache = []; + this.shaderCache = {}; this.emptyPool(); }; @@ -17776,7 +19139,7 @@ var FilterManager = function (_WebGLManager) { FilterManager.prototype.getPotRenderTarget = function getPotRenderTarget(gl, minWidth, minHeight, resolution) { - // TODO you coud return a bigger texture if there is not one in the pool? + // TODO you could return a bigger texture if there is not one in the pool? minWidth = _bitTwiddle2.default.nextPow2(minWidth * resolution); minHeight = _bitTwiddle2.default.nextPow2(minHeight * resolution); @@ -17786,7 +19149,21 @@ var FilterManager = function (_WebGLManager) { this.pool[key] = []; } - var renderTarget = this.pool[key].pop() || new _RenderTarget2.default(gl, minWidth, minHeight, null, 1); + var renderTarget = this.pool[key].pop(); + + // creating render target will cause texture to be bound! + if (!renderTarget) { + // temporary bypass cache.. + var tex = this.renderer.boundTextures[0]; + + gl.activeTexture(gl.TEXTURE0); + + // internally - this will cause a texture to be bound.. + renderTarget = new _RenderTarget2.default(gl, minWidth, minHeight, null, 1); + + // set the current one back + gl.bindTexture(gl.TEXTURE_2D, tex._glTextures[this.renderer.CONTEXT_UID].texture); + } // manually tweak the resolution... // this will not modify the size of the frame buffer, just its resolution. @@ -17837,7 +19214,7 @@ var FilterManager = function (_WebGLManager) { exports.default = FilterManager; -},{"../../../Shader":41,"../../../math":66,"../filters/filterTransforms":84,"../utils/Quad":91,"../utils/RenderTarget":92,"./WebGLManager":89,"bit-twiddle":17}],87:[function(require,module,exports){ +},{"../../../Shader":44,"../../../math":70,"../filters/filterTransforms":88,"../utils/Quad":95,"../utils/RenderTarget":96,"./WebGLManager":93,"bit-twiddle":18}],91:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -17895,9 +19272,13 @@ var MaskManager = function (_WebGLManager) { MaskManager.prototype.pushMask = function pushMask(target, maskData) { + // TODO the root check means scissor rect will not + // be used on render textures more info here: + // https://github.com/pixijs/pixi.js/pull/3545 + if (maskData.texture) { this.pushSpriteMask(target, maskData); - } else if (this.enableScissor && !this.scissor && !this.renderer.stencilManager.stencilMaskStack.length && maskData.isFastRect()) { + } else if (this.enableScissor && !this.scissor && this.renderer._activeRenderTarget.root && !this.renderer.stencilManager.stencilMaskStack.length && maskData.isFastRect()) { var matrix = maskData.worldTransform; var rot = Math.atan2(matrix.b, matrix.a); @@ -18043,7 +19424,7 @@ var MaskManager = function (_WebGLManager) { exports.default = MaskManager; -},{"../filters/spriteMask/SpriteMaskFilter":85,"./WebGLManager":89}],88:[function(require,module,exports){ +},{"../filters/spriteMask/SpriteMaskFilter":89,"./WebGLManager":93}],92:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -18100,7 +19481,7 @@ var StencilManager = function (_WebGLManager) { }; /** - * Applies the Mask and adds it to the current filter stack. @alvin + * Applies the Mask and adds it to the current stencil stack. @alvin * * @param {PIXI.Graphics} graphics - The mask */ @@ -18112,28 +19493,25 @@ var StencilManager = function (_WebGLManager) { this.renderer._activeRenderTarget.attachStencilBuffer(); var gl = this.renderer.gl; - var sms = this.stencilMaskStack; + var prevMaskCount = this.stencilMaskStack.length; - if (sms.length === 0) { + if (prevMaskCount === 0) { gl.enable(gl.STENCIL_TEST); - gl.clear(gl.STENCIL_BUFFER_BIT); - gl.stencilFunc(gl.ALWAYS, 1, 1); } - sms.push(graphics); + this.stencilMaskStack.push(graphics); + // Increment the refference stencil value where the new mask overlaps with the old ones. gl.colorMask(false, false, false, false); + gl.stencilFunc(gl.EQUAL, prevMaskCount, this._getBitwiseMask()); gl.stencilOp(gl.KEEP, gl.KEEP, gl.INCR); - this.renderer.plugins.graphics.render(graphics); - gl.colorMask(true, true, true, true); - gl.stencilFunc(gl.NOTEQUAL, 0, sms.length); - gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); + this._useCurrent(); }; /** - * TODO @alvin + * Removes the last mask from the stencil stack. @alvin */ @@ -18141,25 +19519,47 @@ var StencilManager = function (_WebGLManager) { this.renderer.setObjectRenderer(this.renderer.plugins.graphics); var gl = this.renderer.gl; - var sms = this.stencilMaskStack; - - var graphics = sms.pop(); + var graphics = this.stencilMaskStack.pop(); - if (sms.length === 0) { + if (this.stencilMaskStack.length === 0) { // the stack is empty! gl.disable(gl.STENCIL_TEST); + gl.clear(gl.STENCIL_BUFFER_BIT); + gl.clearStencil(0); } else { + // Decrement the refference stencil value where the popped mask overlaps with the other ones gl.colorMask(false, false, false, false); gl.stencilOp(gl.KEEP, gl.KEEP, gl.DECR); - this.renderer.plugins.graphics.render(graphics); - gl.colorMask(true, true, true, true); - gl.stencilFunc(gl.NOTEQUAL, 0, sms.length); - gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); + this._useCurrent(); } }; + /** + * Setup renderer to use the current stencil data. + */ + + + StencilManager.prototype._useCurrent = function _useCurrent() { + var gl = this.renderer.gl; + + gl.colorMask(true, true, true, true); + gl.stencilFunc(gl.EQUAL, this.stencilMaskStack.length, this._getBitwiseMask()); + gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); + }; + + /** + * Fill 1s equal to the number of acitve stencil masks. + * + * @return {number} The bitwise mask. + */ + + + StencilManager.prototype._getBitwiseMask = function _getBitwiseMask() { + return (1 << this.stencilMaskStack.length) - 1; + }; + /** * Destroys the mask stack. * @@ -18177,7 +19577,7 @@ var StencilManager = function (_WebGLManager) { exports.default = StencilManager; -},{"./WebGLManager":89}],89:[function(require,module,exports){ +},{"./WebGLManager":93}],93:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -18232,7 +19632,7 @@ var WebGLManager = function () { exports.default = WebGLManager; -},{}],90:[function(require,module,exports){ +},{}],94:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -18310,7 +19710,7 @@ var ObjectRenderer = function (_WebGLManager) { exports.default = ObjectRenderer; -},{"../managers/WebGLManager":89}],91:[function(require,module,exports){ +},{"../managers/WebGLManager":93}],95:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -18341,7 +19741,7 @@ var Quad = function () { function Quad(gl, state) { _classCallCheck(this, Quad); - /* + /** * the current WebGL drawing context * * @member {WebGLRenderingContext} @@ -18371,23 +19771,31 @@ var Quad = function () { this.interleaved[i * 4 + 3] = this.uvs[i * 2 + 1]; } - /* - * @member {Uint16Array} An array containing the indices of the vertices + /** + * An array containing the indices of the vertices + * + * @member {Uint16Array} */ this.indices = (0, _createIndicesForQuads2.default)(1); - /* - * @member {glCore.GLBuffer} The vertex buffer + /** + * The vertex buffer + * + * @member {glCore.GLBuffer} */ this.vertexBuffer = _pixiGlCore2.default.GLBuffer.createVertexBuffer(gl, this.interleaved, gl.STATIC_DRAW); - /* - * @member {glCore.GLBuffer} The index buffer + /** + * The index buffer + * + * @member {glCore.GLBuffer} */ this.indexBuffer = _pixiGlCore2.default.GLBuffer.createIndexBuffer(gl, this.indices, gl.STATIC_DRAW); - /* - * @member {glCore.VertexArrayObject} The index buffer + /** + * The vertex array object + * + * @member {glCore.VertexArrayObject} */ this.vao = new _pixiGlCore2.default.VertexArrayObject(gl, state); } @@ -18446,19 +19854,6 @@ var Quad = function () { return this; }; - /** - * Draws the quad - * - * @return {PIXI.Quad} Returns itself. - */ - - - Quad.prototype.draw = function draw() { - this.vao.bind().draw(this.gl.TRIANGLES, 6, 0).unbind(); - - return this; - }; - /** * Binds the buffer and uploads the data * @@ -18496,7 +19891,7 @@ var Quad = function () { exports.default = Quad; -},{"../../../utils/createIndicesForQuads":113,"pixi-gl-core":7}],92:[function(require,module,exports){ +},{"../../../utils/createIndicesForQuads":122,"pixi-gl-core":7}],96:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -18505,8 +19900,14 @@ var _math = require('../../../math'); var _const = require('../../../const'); +var _settings = require('../../../settings'); + +var _settings2 = _interopRequireDefault(_settings); + var _pixiGlCore = require('pixi-gl-core'); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** @@ -18518,7 +19919,7 @@ var RenderTarget = function () { * @param {WebGLRenderingContext} gl - The current WebGL drawing context * @param {number} [width=0] - the horizontal range of the filter * @param {number} [height=0] - the vertical range of the filter - * @param {number} [scaleMode=PIXI.SCALE_MODES.DEFAULT] - See {@link PIXI.SCALE_MODES} for possible values + * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES} for possible values * @param {number} [resolution=1] - The current resolution / device pixel ratio * @param {boolean} [root=false] - Whether this object is the root element or not */ @@ -18570,7 +19971,7 @@ var RenderTarget = function () { * @member {number} * @default 1 */ - this.resolution = resolution || _const.RESOLUTION; + this.resolution = resolution || _settings2.default.RESOLUTION; /** * The projection matrix @@ -18627,10 +20028,10 @@ var RenderTarget = function () { * The scale mode. * * @member {number} - * @default PIXI.SCALE_MODES.DEFAULT + * @default PIXI.settings.SCALE_MODE * @see PIXI.SCALE_MODES */ - this.scaleMode = scaleMode || _const.SCALE_MODES.DEFAULT; + this.scaleMode = scaleMode !== undefined ? scaleMode : _settings2.default.SCALE_MODE; /** * Whether this object is the root element or not @@ -18705,7 +20106,7 @@ var RenderTarget = function () { RenderTarget.prototype.setFrame = function setFrame(destinationFrame, sourceFrame) { this.destinationFrame = destinationFrame || this.destinationFrame || this.defaultFrame; - this.sourceFrame = sourceFrame || this.sourceFrame || destinationFrame; + this.sourceFrame = sourceFrame || this.sourceFrame || this.destinationFrame; }; /** @@ -18718,7 +20119,7 @@ var RenderTarget = function () { // TOOD refactor usage of frame.. var gl = this.gl; - // make surethe texture is unbound! + // make sure the texture is unbound! this.frameBuffer.bind(); this.calculateProjection(this.destinationFrame, this.sourceFrame); @@ -18817,7 +20218,7 @@ var RenderTarget = function () { exports.default = RenderTarget; -},{"../../../const":42,"../../../math":66,"pixi-gl-core":7}],93:[function(require,module,exports){ +},{"../../../const":46,"../../../math":70,"../../../settings":101,"pixi-gl-core":7}],97:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -18890,7 +20291,7 @@ function generateIfTestSrc(maxIfs) { return src; } -},{"pixi-gl-core":7}],94:[function(require,module,exports){ +},{"pixi-gl-core":7}],98:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -18902,6 +20303,8 @@ var _const = require('../../../const'); * Maps gl blend combinations to WebGL. * * @memberof PIXI + * @function mapWebGLBlendModesToPixi + * @private * @param {WebGLRenderingContext} gl - The rendering context. * @param {string[]} [array=[]] - The array to output into. * @return {string[]} Mapped modes. @@ -18929,10 +20332,15 @@ function mapWebGLBlendModesToPixi(gl) { array[_const.BLEND_MODES.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; array[_const.BLEND_MODES.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + // not-premultiplied blend modes + array[_const.BLEND_MODES.NORMAL_NPM] = [gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + array[_const.BLEND_MODES.ADD_NPM] = [gl.SRC_ALPHA, gl.DST_ALPHA, gl.ONE, gl.DST_ALPHA]; + array[_const.BLEND_MODES.SCREEN_NPM] = [gl.SRC_ALPHA, gl.ONE_MINUS_SRC_COLOR, gl.ONE, gl.ONE_MINUS_SRC_COLOR]; + return array; } -},{"../../../const":42}],95:[function(require,module,exports){ +},{"../../../const":46}],99:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -18943,8 +20351,9 @@ var _const = require('../../../const'); /** * Generic Mask Stack data structure. * - * @class * @memberof PIXI + * @function mapWebGLDrawModesToPixi + * @private * @param {WebGLRenderingContext} gl - The current WebGL drawing context * @param {object} [object={}] - The object to map into * @return {object} The mapped draw modes. @@ -18963,7 +20372,7 @@ function mapWebGLDrawModesToPixi(gl) { return object; } -},{"../../../const":42}],96:[function(require,module,exports){ +},{"../../../const":46}],100:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -18971,7 +20380,7 @@ exports.default = validateContext; function validateContext(gl) { var attributes = gl.getContextAttributes(); - // this is going to be fairly simple for now.. but at least we have rom to grow! + // this is going to be fairly simple for now.. but at least we have room to grow! if (!attributes.stencil) { /* eslint-disable no-console */ console.warn('Provided WebGL context does not have a stencil buffer, masks may not render correctly'); @@ -18979,7 +20388,242 @@ function validateContext(gl) { } } -},{}],97:[function(require,module,exports){ +},{}],101:[function(require,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _maxRecommendedTextures = require('./utils/maxRecommendedTextures'); + +var _maxRecommendedTextures2 = _interopRequireDefault(_maxRecommendedTextures); + +var _canUploadSameBuffer = require('./utils/canUploadSameBuffer'); + +var _canUploadSameBuffer2 = _interopRequireDefault(_canUploadSameBuffer); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * User's customizable globals for overriding the default PIXI settings, such + * as a renderer's default resolution, framerate, float percision, etc. + * @example + * // Use the native window resolution as the default resolution + * // will support high-density displays when rendering + * PIXI.settings.RESOLUTION = window.devicePixelRatio. + * + * // Disable interpolation when scaling, will make texture be pixelated + * PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST; + * @namespace PIXI.settings + */ +exports.default = { + + /** + * Target frames per millisecond. + * + * @static + * @memberof PIXI.settings + * @type {number} + * @default 0.06 + */ + TARGET_FPMS: 0.06, + + /** + * If set to true WebGL will attempt make textures mimpaped by default. + * Mipmapping will only succeed if the base texture uploaded has power of two dimensions. + * + * @static + * @memberof PIXI.settings + * @type {boolean} + * @default true + */ + MIPMAP_TEXTURES: true, + + /** + * Default resolution / device pixel ratio of the renderer. + * + * @static + * @memberof PIXI.settings + * @type {number} + * @default 1 + */ + RESOLUTION: 1, + + /** + * Default filter resolution. + * + * @static + * @memberof PIXI.settings + * @type {number} + * @default 1 + */ + FILTER_RESOLUTION: 1, + + /** + * The maximum textures that this device supports. + * + * @static + * @memberof PIXI.settings + * @type {number} + * @default 32 + */ + SPRITE_MAX_TEXTURES: (0, _maxRecommendedTextures2.default)(32), + + // TODO: maybe change to SPRITE.BATCH_SIZE: 2000 + // TODO: maybe add PARTICLE.BATCH_SIZE: 15000 + + /** + * The default sprite batch size. + * + * The default aims to balance desktop and mobile devices. + * + * @static + * @memberof PIXI.settings + * @type {number} + * @default 4096 + */ + SPRITE_BATCH_SIZE: 4096, + + /** + * The prefix that denotes a URL is for a retina asset. + * + * @static + * @memberof PIXI.settings + * @type {RegExp} + * @example `@2x` + * @default /@([0-9\.]+)x/ + */ + RETINA_PREFIX: /@([0-9\.]+)x/, + + /** + * The default render options if none are supplied to {@link PIXI.WebGLRenderer} + * or {@link PIXI.CanvasRenderer}. + * + * @static + * @constant + * @memberof PIXI.settings + * @type {object} + * @property {HTMLCanvasElement} view=null + * @property {number} resolution=1 + * @property {boolean} antialias=false + * @property {boolean} forceFXAA=false + * @property {boolean} autoResize=false + * @property {boolean} transparent=false + * @property {number} backgroundColor=0x000000 + * @property {boolean} clearBeforeRender=true + * @property {boolean} preserveDrawingBuffer=false + * @property {boolean} roundPixels=false + * @property {number} width=800 + * @property {number} height=600 + * @property {boolean} legacy=false + */ + RENDER_OPTIONS: { + view: null, + antialias: false, + forceFXAA: false, + autoResize: false, + transparent: false, + backgroundColor: 0x000000, + clearBeforeRender: true, + preserveDrawingBuffer: false, + roundPixels: false, + width: 800, + height: 600, + legacy: false + }, + + /** + * Default transform type. + * + * @static + * @memberof PIXI.settings + * @type {PIXI.TRANSFORM_MODE} + * @default PIXI.TRANSFORM_MODE.STATIC + */ + TRANSFORM_MODE: 0, + + /** + * Default Garbage Collection mode. + * + * @static + * @memberof PIXI.settings + * @type {PIXI.GC_MODES} + * @default PIXI.GC_MODES.AUTO + */ + GC_MODE: 0, + + /** + * Default Garbage Collection max idle. + * + * @static + * @memberof PIXI.settings + * @type {number} + * @default 3600 + */ + GC_MAX_IDLE: 60 * 60, + + /** + * Default Garbage Collection maximum check count. + * + * @static + * @memberof PIXI.settings + * @type {number} + * @default 600 + */ + GC_MAX_CHECK_COUNT: 60 * 10, + + /** + * Default wrap modes that are supported by pixi. + * + * @static + * @memberof PIXI.settings + * @type {PIXI.WRAP_MODES} + * @default PIXI.WRAP_MODES.CLAMP + */ + WRAP_MODE: 0, + + /** + * The scale modes that are supported by pixi. + * + * @static + * @memberof PIXI.settings + * @type {PIXI.SCALE_MODES} + * @default PIXI.SCALE_MODES.LINEAR + */ + SCALE_MODE: 0, + + /** + * Default specify float precision in vertex shader. + * + * @static + * @memberof PIXI.settings + * @type {PIXI.PRECISION} + * @default PIXI.PRECISION.HIGH + */ + PRECISION_VERTEX: 'highp', + + /** + * Default specify float precision in fragment shader. + * + * @static + * @memberof PIXI.settings + * @type {PIXI.PRECISION} + * @default PIXI.PRECISION.MEDIUM + */ + PRECISION_FRAGMENT: 'mediump', + + /** + * Can we upload the same buffer in a single frame? + * + * @static + * @constant + * @memberof PIXI + * @type {boolean} + */ + CAN_UPLOAD_SAME_BUFFER: (0, _canUploadSameBuffer2.default)() + +}; + +},{"./utils/canUploadSameBuffer":121,"./utils/maxRecommendedTextures":126}],102:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -19093,7 +20737,7 @@ var Sprite = function (_Container) { /** * The shader that will be used to render the sprite. Set to null to remove a current shader. * - * @member {PIXI.AbstractFilter|PIXI.Shader} + * @member {PIXI.Filter|PIXI.Shader} */ _this.shader = null; @@ -19127,6 +20771,18 @@ var Sprite = function (_Container) { _this._transformID = -1; _this._textureID = -1; + + _this._transformTrimmedID = -1; + _this._textureTrimmedID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + _this.pluginName = 'sprite'; return _this; } @@ -19139,14 +20795,15 @@ var Sprite = function (_Container) { Sprite.prototype._onTextureUpdate = function _onTextureUpdate() { this._textureID = -1; + this._textureTrimmedID = -1; // so if _width is 0 then width was not set.. if (this._width) { - this.scale.x = (0, _utils.sign)(this.scale.x) * this._width / this.texture.orig.width; + this.scale.x = (0, _utils.sign)(this.scale.x) * this._width / this._texture.orig.width; } if (this._height) { - this.scale.y = (0, _utils.sign)(this.scale.y) * this._height / this.texture.orig.height; + this.scale.y = (0, _utils.sign)(this.scale.y) * this._height / this._texture.orig.height; } }; @@ -19159,6 +20816,7 @@ var Sprite = function (_Container) { Sprite.prototype._onAnchorUpdate = function _onAnchorUpdate() { this._transformID = -1; + this._transformTrimmedID = -1; }; /** @@ -19203,11 +20861,11 @@ var Sprite = function (_Container) { h1 = trim.y - anchor._y * orig.height; h0 = h1 + trim.height; } else { - w0 = orig.width * (1 - anchor._x); - w1 = orig.width * -anchor._x; + w1 = -anchor._x * orig.width; + w0 = w1 + orig.width; - h0 = orig.height * (1 - anchor._y); - h1 = orig.height * -anchor._y; + h1 = -anchor._y * orig.height; + h0 = h1 + orig.height; } // xy @@ -19236,8 +20894,13 @@ var Sprite = function (_Container) { Sprite.prototype.calculateTrimmedVertices = function calculateTrimmedVertices() { if (!this.vertexTrimmedData) { this.vertexTrimmedData = new Float32Array(8); + } else if (this._transformTrimmedID === this.transform._worldID && this._textureTrimmedID === this._texture._updateID) { + return; } + this._transformTrimmedID = this.transform._worldID; + this._textureTrimmedID = this._texture._updateID; + // lets do some special trim code! var texture = this._texture; var vertexData = this.vertexTrimmedData; @@ -19253,11 +20916,11 @@ var Sprite = function (_Container) { var tx = wt.tx; var ty = wt.ty; - var w0 = orig.width * (1 - anchor._x); - var w1 = orig.width * -anchor._x; + var w1 = -anchor._x * orig.width; + var w0 = w1 + orig.width; - var h0 = orig.height * (1 - anchor._y); - var h1 = orig.height * -anchor._y; + var h1 = -anchor._y * orig.height; + var h0 = h1 + orig.height; // xy vertexData[0] = a * w1 + c * h1 + tx; @@ -19288,8 +20951,8 @@ var Sprite = function (_Container) { Sprite.prototype._renderWebGL = function _renderWebGL(renderer) { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); }; /** @@ -19301,7 +20964,7 @@ var Sprite = function (_Container) { Sprite.prototype._renderCanvas = function _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); }; /** @@ -19330,18 +20993,18 @@ var Sprite = function (_Container) { /** * Gets the local bounds of the sprite object. * - * @param {Rectangle} rect - The output rectangle. - * @return {Rectangle} The bounds. + * @param {PIXI.Rectangle} rect - The output rectangle. + * @return {PIXI.Rectangle} The bounds. */ Sprite.prototype.getLocalBounds = function getLocalBounds(rect) { // we can do a fast local bounds if the sprite has no children! if (this.children.length === 0) { - this._bounds.minX = -this._texture.orig.width * this.anchor._x; - this._bounds.minY = -this._texture.orig.height * this.anchor._y; - this._bounds.maxX = this._texture.orig.width; - this._bounds.maxY = this._texture.orig.height; + this._bounds.minX = this._texture.orig.width * -this._anchor._x; + this._bounds.minY = this._texture.orig.height * -this._anchor._y; + this._bounds.maxX = this._texture.orig.width * (1 - this._anchor._x); + this._bounds.maxY = this._texture.orig.height * (1 - this._anchor._y); if (!rect) { if (!this._localBoundsRect) { @@ -19373,10 +21036,10 @@ var Sprite = function (_Container) { var x1 = -width * this.anchor.x; var y1 = 0; - if (tempPoint.x > x1 && tempPoint.x < x1 + width) { + if (tempPoint.x >= x1 && tempPoint.x < x1 + width) { y1 = -height * this.anchor.y; - if (tempPoint.y > y1 && tempPoint.y < y1 + height) { + if (tempPoint.y >= y1 && tempPoint.y < y1 + height) { return true; } } @@ -19421,7 +21084,7 @@ var Sprite = function (_Container) { * * @static * @param {number|string|PIXI.BaseTexture|HTMLCanvasElement|HTMLVideoElement} source Source to create texture from - * @return {PIXI.Texture} The newly created texture + * @return {PIXI.Sprite} The newly created sprite */ @@ -19456,7 +21119,7 @@ var Sprite = function (_Container) { * @static * @param {string} imageId - The image url of the texture * @param {boolean} [crossorigin=(auto)] - if you want to specify the cross-origin parameter - * @param {number} [scaleMode=PIXI.SCALE_MODES.DEFAULT] - if you want to specify the scale mode, + * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - if you want to specify the scale mode, * see {@link PIXI.SCALE_MODES} for possible values * @return {PIXI.Sprite} A new Sprite using a texture from the texture cache matching the image id */ @@ -19470,26 +21133,19 @@ var Sprite = function (_Container) { * The width of the sprite, setting this will actually modify the scale to achieve the value set * * @member {number} - * @memberof PIXI.Sprite# */ _createClass(Sprite, [{ key: 'width', get: function get() { - return Math.abs(this.scale.x) * this.texture.orig.width; - } - - /** - * Sets the width of the sprite by modifying the scale. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + return Math.abs(this.scale.x) * this._texture.orig.width; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { var s = (0, _utils.sign)(this.scale.x) || 1; - this.scale.x = s * value / this.texture.orig.width; + this.scale.x = s * value / this._texture.orig.width; this._width = value; } @@ -19497,25 +21153,18 @@ var Sprite = function (_Container) { * The height of the sprite, setting this will actually modify the scale to achieve the value set * * @member {number} - * @memberof PIXI.Sprite# */ }, { key: 'height', get: function get() { - return Math.abs(this.scale.y) * this.texture.orig.height; - } - - /** - * Sets the height of the sprite by modifying the scale. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + return Math.abs(this.scale.y) * this._texture.orig.height; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { var s = (0, _utils.sign)(this.scale.y) || 1; - this.scale.y = s * value / this.texture.orig.height; + this.scale.y = s * value / this._texture.orig.height; this._height = value; } @@ -19526,31 +21175,23 @@ var Sprite = function (_Container) { * Setting the anchor to 1,1 would mean the texture's origin point will be the bottom right corner * * @member {PIXI.ObservablePoint} - * @memberof PIXI.Sprite# */ }, { key: 'anchor', get: function get() { return this._anchor; - } - - /** - * Copies the anchor to the sprite. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._anchor.copy(value); } /** - * The tint applied to the sprite. This is a hex value. A value of - * 0xFFFFFF will remove any tint effect. + * The tint applied to the sprite. This is a hex value. + * A value of 0xFFFFFF will remove any tint effect. * * @member {number} - * @memberof PIXI.Sprite# * @default 0xFFFFFF */ @@ -19558,15 +21199,9 @@ var Sprite = function (_Container) { key: 'tint', get: function get() { return this._tint; - } - - /** - * Sets the tint of the sprite. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._tint = value; this._tintRGB = (value >> 16) + (value & 0xff00) + ((value & 0xff) << 16); } @@ -19575,22 +21210,15 @@ var Sprite = function (_Container) { * The texture that the sprite is using * * @member {PIXI.Texture} - * @memberof PIXI.Sprite# */ }, { key: 'texture', get: function get() { return this._texture; - } - - /** - * Sets the texture of the sprite. - * - * @param {PIXI.Texture} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { if (this._texture === value) { return; } @@ -19599,6 +21227,7 @@ var Sprite = function (_Container) { this.cachedTint = 0xFFFFFF; this._textureID = -1; + this._textureTrimmedID = -1; if (value) { // wait for the texture to load @@ -19616,7 +21245,7 @@ var Sprite = function (_Container) { exports.default = Sprite; -},{"../const":42,"../display/Container":44,"../math":66,"../textures/Texture":108,"../utils":115}],98:[function(require,module,exports){ +},{"../const":46,"../display/Container":48,"../math":70,"../textures/Texture":115,"../utils":124}],103:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -19643,7 +21272,7 @@ var canvasRenderWorldTransform = new _math.Matrix(); * @author Mat Groves * * Big thanks to the very clever Matt DesLauriers https://github.com/mattdesl/ - * for creating the original pixi version! + * for creating the original PixiJS version! * Also a thanks to https://github.com/bchevalier for tweaking the tint and alpha so that they now * share 4 bytes on the vertex buffer * @@ -19737,7 +21366,7 @@ var CanvasSpriteRenderer = function () { var resolution = texture.baseTexture.resolution; if (sprite.tint !== 0xFFFFFF) { - if (sprite.cachedTint !== sprite.tint) { + if (sprite.cachedTint !== sprite.tint || sprite.tintedTexture.tintId !== sprite._texture._updateID) { sprite.cachedTint = sprite.tint; // TODO clean up caching - how to clean up the caches? @@ -19769,7 +21398,7 @@ exports.default = CanvasSpriteRenderer; _CanvasRenderer2.default.registerPlugin('sprite', CanvasSpriteRenderer); -},{"../../const":42,"../../math":66,"../../renderers/canvas/CanvasRenderer":73,"./CanvasTinter":99}],99:[function(require,module,exports){ +},{"../../const":46,"../../math":70,"../../renderers/canvas/CanvasRenderer":77,"./CanvasTinter":104}],104:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -19785,7 +21414,8 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de /** * Utility methods for Sprite/Texture tinting. * - * @namespace PIXI.CanvasTinter + * @class + * @memberof PIXI */ var CanvasTinter = { /** @@ -19797,7 +21427,7 @@ var CanvasTinter = { * @return {HTMLCanvasElement} The tinted canvas */ getTintedTexture: function getTintedTexture(sprite, color) { - var texture = sprite.texture; + var texture = sprite._texture; color = CanvasTinter.roundColor(color); @@ -19805,16 +21435,24 @@ var CanvasTinter = { texture.tintCache = texture.tintCache || {}; - if (texture.tintCache[stringColor]) { - return texture.tintCache[stringColor]; - } + var cachedTexture = texture.tintCache[stringColor]; - // clone texture.. - var canvas = CanvasTinter.canvas || document.createElement('canvas'); + var canvas = void 0; + + if (cachedTexture) { + if (cachedTexture.tintId === texture._updateID) { + return texture.tintCache[stringColor]; + } + + canvas = texture.tintCache[stringColor]; + } else { + canvas = CanvasTinter.canvas || document.createElement('canvas'); + } - // CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); CanvasTinter.tintMethod(texture, color, canvas); + canvas.tintId = texture._updateID; + if (CanvasTinter.convertTintToImage) { // is this better? var tintImage = new Image(); @@ -19849,9 +21487,10 @@ var CanvasTinter = { crop.width *= resolution; crop.height *= resolution; - canvas.width = crop.width; - canvas.height = crop.height; + canvas.width = Math.ceil(crop.width); + canvas.height = Math.ceil(crop.height); + context.save(); context.fillStyle = '#' + ('00000' + (color | 0).toString(16)).substr(-6); context.fillRect(0, 0, crop.width, crop.height); @@ -19863,6 +21502,7 @@ var CanvasTinter = { context.globalCompositeOperation = 'destination-atop'; context.drawImage(texture.baseTexture.source, crop.x, crop.y, crop.width, crop.height, 0, 0, crop.width, crop.height); + context.restore(); }, /** @@ -19883,9 +21523,10 @@ var CanvasTinter = { crop.width *= resolution; crop.height *= resolution; - canvas.width = crop.width; - canvas.height = crop.height; + canvas.width = Math.ceil(crop.width); + canvas.height = Math.ceil(crop.height); + context.save(); context.globalCompositeOperation = 'copy'; context.fillStyle = '#' + ('00000' + (color | 0).toString(16)).substr(-6); context.fillRect(0, 0, crop.width, crop.height); @@ -19894,6 +21535,7 @@ var CanvasTinter = { context.drawImage(texture.baseTexture.source, crop.x, crop.y, crop.width, crop.height, 0, 0, crop.width, crop.height); // context.globalCompositeOperation = 'copy'; + context.restore(); }, @@ -19915,11 +21557,13 @@ var CanvasTinter = { crop.width *= resolution; crop.height *= resolution; - canvas.width = crop.width; - canvas.height = crop.height; + canvas.width = Math.ceil(crop.width); + canvas.height = Math.ceil(crop.height); + context.save(); context.globalCompositeOperation = 'copy'; context.drawImage(texture.baseTexture.source, crop.x, crop.y, crop.width, crop.height, 0, 0, crop.width, crop.height); + context.restore(); var rgbValues = (0, _utils.hex2rgb)(color); var r = rgbValues[0]; @@ -20005,7 +21649,7 @@ CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMul exports.default = CanvasTinter; -},{"../../renderers/canvas/utils/canUseNewCanvasBlendModes":76,"../../utils":115}],100:[function(require,module,exports){ +},{"../../renderers/canvas/utils/canUseNewCanvasBlendModes":80,"../../utils":124}],105:[function(require,module,exports){ "use strict"; exports.__esModule = true; @@ -20014,6 +21658,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons /** * @class + * @memberof PIXI */ var Buffer = function () { /** @@ -20057,7 +21702,7 @@ var Buffer = function () { exports.default = Buffer; -},{}],101:[function(require,module,exports){ +},{}],106:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -20086,7 +21731,11 @@ var _BatchBuffer = require('./BatchBuffer'); var _BatchBuffer2 = _interopRequireDefault(_BatchBuffer); -var _const = require('../../const'); +var _settings = require('../../settings'); + +var _settings2 = _interopRequireDefault(_settings); + +var _utils = require('../../utils'); var _pixiGlCore = require('pixi-gl-core'); @@ -20105,6 +21754,7 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var TICK = 0; +var TEXTURE_TICK = 0; /** * Renderer dedicated to drawing and batching sprites. @@ -20126,7 +21776,7 @@ var SpriteRenderer = function (_ObjectRenderer) { /** * Number of values sent in the vertex buffer. - * positionX, positionY, colorR, colorG, colorB = 5 + * aVertexPosition(2), aTextureCoord(1), aColor(1), aTextureId(1) = 5 * * @member {number} */ @@ -20142,11 +21792,11 @@ var SpriteRenderer = function (_ObjectRenderer) { _this.vertByteSize = _this.vertSize * 4; /** - * The number of images in the SpriteBatch before it flushes. + * The number of images in the SpriteRenderer before it flushes. * * @member {number} */ - _this.size = _const.SPRITE_BATCH_SIZE; // 2000 is a nice balance between mobile / desktop + _this.size = _settings2.default.SPRITE_BATCH_SIZE; // 2000 is a nice balance between mobile / desktop // the total number of bytes in our batch // let numVerts = this.size * 4 * this.vertByteSize; @@ -20169,10 +21819,9 @@ var SpriteRenderer = function (_ObjectRenderer) { * These shaders will also be generated on the fly as required. * @member {PIXI.Shader[]} */ - _this.shaders = null; + _this.shader = null; _this.currentIndex = 0; - TICK = 0; _this.groups = []; for (var k = 0; k < _this.size; k++) { @@ -20201,36 +21850,47 @@ var SpriteRenderer = function (_ObjectRenderer) { SpriteRenderer.prototype.onContextChange = function onContextChange() { var gl = this.renderer.gl; - // step 1: first check max textures the GPU can handle. - this.MAX_TEXTURES = Math.min(gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS), _const.SPRITE_MAX_TEXTURES); + if (this.renderer.legacy) { + this.MAX_TEXTURES = 1; + } else { + // step 1: first check max textures the GPU can handle. + this.MAX_TEXTURES = Math.min(gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS), _settings2.default.SPRITE_MAX_TEXTURES); - // step 2: check the maximum number of if statements the shader can have too.. - this.MAX_TEXTURES = (0, _checkMaxIfStatmentsInShader2.default)(this.MAX_TEXTURES, gl); + // step 2: check the maximum number of if statements the shader can have too.. + this.MAX_TEXTURES = (0, _checkMaxIfStatmentsInShader2.default)(this.MAX_TEXTURES, gl); + } - this.shaders = new Array(this.MAX_TEXTURES); - this.shaders[0] = (0, _generateMultiTextureShader2.default)(gl, 1); - this.shaders[1] = (0, _generateMultiTextureShader2.default)(gl, 2); + this.shader = (0, _generateMultiTextureShader2.default)(gl, this.MAX_TEXTURES); // create a couple of buffers this.indexBuffer = _pixiGlCore2.default.GLBuffer.createIndexBuffer(gl, this.indices, gl.STATIC_DRAW); // we use the second shader as the first one depending on your browser may omit aTextureId // as it is not used by the shader so is optimized out. - var shader = this.shaders[1]; - for (var i = 0; i < this.vaoMax; i++) { - this.vertexBuffers[i] = _pixiGlCore2.default.GLBuffer.createVertexBuffer(gl, null, gl.STREAM_DRAW); + this.renderer.bindVao(null); + + var attrs = this.shader.attributes; + for (var i = 0; i < this.vaoMax; i++) { /* eslint-disable max-len */ + var vertexBuffer = this.vertexBuffers[i] = _pixiGlCore2.default.GLBuffer.createVertexBuffer(gl, null, gl.STREAM_DRAW); + /* eslint-enable max-len */ // build the vao object that will render.. - this.vaos[i] = this.renderer.createVao().addIndex(this.indexBuffer).addAttribute(this.vertexBuffers[i], shader.attributes.aVertexPosition, gl.FLOAT, false, this.vertByteSize, 0).addAttribute(this.vertexBuffers[i], shader.attributes.aTextureCoord, gl.UNSIGNED_SHORT, true, this.vertByteSize, 2 * 4).addAttribute(this.vertexBuffers[i], shader.attributes.aColor, gl.UNSIGNED_BYTE, true, this.vertByteSize, 3 * 4).addAttribute(this.vertexBuffers[i], shader.attributes.aTextureId, gl.FLOAT, false, this.vertByteSize, 4 * 4); + var vao = this.renderer.createVao().addIndex(this.indexBuffer).addAttribute(vertexBuffer, attrs.aVertexPosition, gl.FLOAT, false, this.vertByteSize, 0).addAttribute(vertexBuffer, attrs.aTextureCoord, gl.UNSIGNED_SHORT, true, this.vertByteSize, 2 * 4).addAttribute(vertexBuffer, attrs.aColor, gl.UNSIGNED_BYTE, true, this.vertByteSize, 3 * 4); - /* eslint-disable max-len */ + if (attrs.aTextureId) { + vao.addAttribute(vertexBuffer, attrs.aTextureId, gl.FLOAT, false, this.vertByteSize, 4 * 4); + } + + this.vaos[i] = vao; } this.vao = this.vaos[0]; this.currentBlendMode = 99999; + + this.boundTextures = new Array(this.MAX_TEXTURES); }; /** @@ -20260,7 +21920,7 @@ var SpriteRenderer = function (_ObjectRenderer) { // get the uvs for the texture // if the uvs have not updated then no point rendering just yet! - if (!sprite.texture._uvs) { + if (!sprite._texture._uvs) { return; } @@ -20281,6 +21941,7 @@ var SpriteRenderer = function (_ObjectRenderer) { } var gl = this.renderer.gl; + var MAX_TEXTURES = this.MAX_TEXTURES; var np2 = _bitTwiddle2.default.nextPow2(this.currentIndex); var log2 = _bitTwiddle2.default.log2(np2); @@ -20292,6 +21953,10 @@ var SpriteRenderer = function (_ObjectRenderer) { var float32View = buffer.float32View; var uint32View = buffer.uint32View; + var boundTextures = this.boundTextures; + var rendererBoundTextures = this.renderer.boundTextures; + var touch = this.renderer.textureGC.count; + var index = 0; var nextTexture = void 0; var currentTexture = void 0; @@ -20299,11 +21964,8 @@ var SpriteRenderer = function (_ObjectRenderer) { var textureCount = 0; var currentGroup = groups[0]; var vertexData = void 0; - var tint = void 0; var uvs = void 0; - var textureId = void 0; - var blendMode = sprites[0].blendMode; - var shader = void 0; + var blendMode = _utils.premultiplyBlendMode[sprites[0]._texture.baseTexture.premultipliedAlpha ? 1 : 0][sprites[0].blendMode]; currentGroup.textureCount = 0; currentGroup.start = 0; @@ -20313,19 +21975,28 @@ var SpriteRenderer = function (_ObjectRenderer) { var i = void 0; - for (i = 0; i < this.currentIndex; i++) { + // copy textures.. + for (i = 0; i < MAX_TEXTURES; ++i) { + boundTextures[i] = rendererBoundTextures[i]; + boundTextures[i]._virtalBoundId = i; + } + + for (i = 0; i < this.currentIndex; ++i) { // upload the sprite elemetns... // they have all ready been calculated so we just need to push them into the buffer. var sprite = sprites[i]; nextTexture = sprite._texture.baseTexture; - if (blendMode !== sprite.blendMode) { - blendMode = sprite.blendMode; + var spriteBlendMode = _utils.premultiplyBlendMode[Number(nextTexture.premultipliedAlpha)][sprite.blendMode]; + + if (blendMode !== spriteBlendMode) { + // finish a group.. + blendMode = spriteBlendMode; // force the batch to break! currentTexture = null; - textureCount = this.MAX_TEXTURES; + textureCount = MAX_TEXTURES; TICK++; } @@ -20333,33 +22004,52 @@ var SpriteRenderer = function (_ObjectRenderer) { currentTexture = nextTexture; if (nextTexture._enabled !== TICK) { - if (textureCount === this.MAX_TEXTURES) { + if (textureCount === MAX_TEXTURES) { TICK++; - textureCount = 0; - currentGroup.size = i - currentGroup.start; + textureCount = 0; + currentGroup = groups[groupCount++]; - currentGroup.textureCount = 0; currentGroup.blend = blendMode; + currentGroup.textureCount = 0; currentGroup.start = i; } + nextTexture.touched = touch; + + if (nextTexture._virtalBoundId === -1) { + for (var j = 0; j < MAX_TEXTURES; ++j) { + var tIndex = (j + TEXTURE_TICK) % MAX_TEXTURES; + + var t = boundTextures[tIndex]; + + if (t._enabled !== TICK) { + TEXTURE_TICK++; + + t._virtalBoundId = -1; + + nextTexture._virtalBoundId = tIndex; + + boundTextures[tIndex] = nextTexture; + break; + } + } + } + nextTexture._enabled = TICK; - nextTexture._id = textureCount; - currentGroup.textures[currentGroup.textureCount++] = nextTexture; - textureCount++; + currentGroup.textureCount++; + currentGroup.ids[textureCount] = nextTexture._virtalBoundId; + currentGroup.textures[textureCount++] = nextTexture; } } vertexData = sprite.vertexData; // TODO this sum does not need to be set each frame.. - tint = sprite._tintRGB + (sprite.worldAlpha * 255 << 24); uvs = sprite._texture._uvs.uvsUint32; - textureId = nextTexture._id; if (this.renderer.roundPixels) { var resolution = this.renderer.resolution; @@ -20401,44 +22091,72 @@ var SpriteRenderer = function (_ObjectRenderer) { uint32View[index + 7] = uvs[1]; uint32View[index + 12] = uvs[2]; uint32View[index + 17] = uvs[3]; + /* eslint-disable max-len */ + var alpha = Math.min(sprite.worldAlpha, 1.0); + // we dont call extra function if alpha is 1.0, that's faster + var argb = alpha < 1.0 && nextTexture.premultipliedAlpha ? (0, _utils.premultiplyTint)(sprite._tintRGB, alpha) : sprite._tintRGB + (alpha * 255 << 24); - uint32View[index + 3] = uint32View[index + 8] = uint32View[index + 13] = uint32View[index + 18] = tint; - float32View[index + 4] = float32View[index + 9] = float32View[index + 14] = float32View[index + 19] = textureId; + uint32View[index + 3] = uint32View[index + 8] = uint32View[index + 13] = uint32View[index + 18] = argb; + float32View[index + 4] = float32View[index + 9] = float32View[index + 14] = float32View[index + 19] = nextTexture._virtalBoundId; + /* eslint-enable max-len */ index += 20; } currentGroup.size = i - currentGroup.start; - this.vertexCount++; + if (!_settings2.default.CAN_UPLOAD_SAME_BUFFER) { + // this is still needed for IOS performance.. + // it really does not like uploading to the same buffer in a single frame! + if (this.vaoMax <= this.vertexCount) { + this.vaoMax++; - if (this.vaoMax <= this.vertexCount) { - this.vaoMax++; - shader = this.shaders[1]; - this.vertexBuffers[this.vertexCount] = _pixiGlCore2.default.GLBuffer.createVertexBuffer(gl, null, gl.STREAM_DRAW); - // build the vao object that will render.. - this.vaos[this.vertexCount] = this.renderer.createVao().addIndex(this.indexBuffer).addAttribute(this.vertexBuffers[this.vertexCount], shader.attributes.aVertexPosition, gl.FLOAT, false, this.vertByteSize, 0).addAttribute(this.vertexBuffers[this.vertexCount], shader.attributes.aTextureCoord, gl.UNSIGNED_SHORT, true, this.vertByteSize, 2 * 4).addAttribute(this.vertexBuffers[this.vertexCount], shader.attributes.aColor, gl.UNSIGNED_BYTE, true, this.vertByteSize, 3 * 4).addAttribute(this.vertexBuffers[this.vertexCount], shader.attributes.aTextureId, gl.FLOAT, false, this.vertByteSize, 4 * 4); + var attrs = this.shader.attributes; + + /* eslint-disable max-len */ + var vertexBuffer = this.vertexBuffers[this.vertexCount] = _pixiGlCore2.default.GLBuffer.createVertexBuffer(gl, null, gl.STREAM_DRAW); + /* eslint-enable max-len */ + + // build the vao object that will render.. + var vao = this.renderer.createVao().addIndex(this.indexBuffer).addAttribute(vertexBuffer, attrs.aVertexPosition, gl.FLOAT, false, this.vertByteSize, 0).addAttribute(vertexBuffer, attrs.aTextureCoord, gl.UNSIGNED_SHORT, true, this.vertByteSize, 2 * 4).addAttribute(vertexBuffer, attrs.aColor, gl.UNSIGNED_BYTE, true, this.vertByteSize, 3 * 4); + + if (attrs.aTextureId) { + vao.addAttribute(vertexBuffer, attrs.aTextureId, gl.FLOAT, false, this.vertByteSize, 4 * 4); + } + + this.vaos[this.vertexCount] = vao; + } + + this.renderer.bindVao(this.vaos[this.vertexCount]); + + this.vertexBuffers[this.vertexCount].upload(buffer.vertices, 0, false); + + this.vertexCount++; + } else { + // lets use the faster option, always use buffer number 0 + this.vertexBuffers[this.vertexCount].upload(buffer.vertices, 0, true); } - this.vertexBuffers[this.vertexCount].upload(buffer.vertices, 0); - this.vao = this.vaos[this.vertexCount].bind(); + for (i = 0; i < MAX_TEXTURES; ++i) { + rendererBoundTextures[i]._virtalBoundId = -1; + } - // / render the groups.. - for (i = 0; i < groupCount; i++) { + // render the groups.. + for (i = 0; i < groupCount; ++i) { var group = groups[i]; var groupTextureCount = group.textureCount; - shader = this.shaders[groupTextureCount - 1]; - - if (!shader) { - shader = this.shaders[groupTextureCount - 1] = (0, _generateMultiTextureShader2.default)(gl, groupTextureCount); - // console.log("SHADER generated for " + textureCount + " textures") - } + for (var _j = 0; _j < groupTextureCount; _j++) { + currentTexture = group.textures[_j]; - this.renderer.bindShader(shader); + // reset virtual ids.. + // lets do a quick check.. + if (rendererBoundTextures[group.ids[_j]] !== currentTexture) { + this.renderer.bindTexture(currentTexture, group.ids[_j], true); + } - for (var j = 0; j < groupTextureCount; j++) { - this.renderer.bindTexture(group.textures[j], j); + // reset the virtualId.. + currentTexture._virtalBoundId = -1; } // set the blend mode.. @@ -20453,48 +22171,57 @@ var SpriteRenderer = function (_ObjectRenderer) { /** * Starts a new sprite batch. - * */ - SpriteRenderer.prototype.start = function start() {} - // this.renderer.bindShader(this.shader); - // TICK %= 1000; + SpriteRenderer.prototype.start = function start() { + this.renderer.bindShader(this.shader); + if (_settings2.default.CAN_UPLOAD_SAME_BUFFER) { + // bind buffer #0, we don't need others + this.renderer.bindVao(this.vaos[this.vertexCount]); + + this.vertexBuffers[this.vertexCount].bind(); + } + }; /** * Stops and flushes the current batch. * */ - ; + SpriteRenderer.prototype.stop = function stop() { this.flush(); - this.vao.unbind(); }; /** - * Destroys the SpriteBatch. + * Destroys the SpriteRenderer. * */ SpriteRenderer.prototype.destroy = function destroy() { for (var i = 0; i < this.vaoMax; i++) { - this.vertexBuffers[i].destroy(); - this.vaos[i].destroy(); + if (this.vertexBuffers[i]) { + this.vertexBuffers[i].destroy(); + } + if (this.vaos[i]) { + this.vaos[i].destroy(); + } } - this.indexBuffer.destroy(); + if (this.indexBuffer) { + this.indexBuffer.destroy(); + } this.renderer.off('prerender', this.onPrerender, this); _ObjectRenderer.prototype.destroy.call(this); - for (var _i = 0; _i < this.shaders.length; _i++) { - if (this.shaders[_i]) { - this.shaders[_i].destroy(); - } + if (this.shader) { + this.shader.destroy(); + this.shader = null; } this.vertexBuffers = null; @@ -20504,8 +22231,8 @@ var SpriteRenderer = function (_ObjectRenderer) { this.sprites = null; - for (var _i2 = 0; _i2 < this.buffers.length; _i2++) { - this.buffers[_i2].destroy(); + for (var _i = 0; _i < this.buffers.length; ++_i) { + this.buffers[_i].destroy(); } }; @@ -20517,7 +22244,7 @@ exports.default = SpriteRenderer; _WebGLRenderer2.default.registerPlugin('sprite', SpriteRenderer); -},{"../../const":42,"../../renderers/webgl/WebGLRenderer":80,"../../renderers/webgl/utils/ObjectRenderer":90,"../../renderers/webgl/utils/checkMaxIfStatmentsInShader":93,"../../utils/createIndicesForQuads":113,"./BatchBuffer":100,"./generateMultiTextureShader":102,"bit-twiddle":17,"pixi-gl-core":7}],102:[function(require,module,exports){ +},{"../../renderers/webgl/WebGLRenderer":84,"../../renderers/webgl/utils/ObjectRenderer":94,"../../renderers/webgl/utils/checkMaxIfStatmentsInShader":97,"../../settings":101,"../../utils":124,"../../utils/createIndicesForQuads":122,"./BatchBuffer":105,"./generateMultiTextureShader":107,"bit-twiddle":18,"pixi-gl-core":7}],107:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -20527,14 +22254,14 @@ var _Shader = require('../../Shader'); var _Shader2 = _interopRequireDefault(_Shader); -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +var _path = require('path'); - // eslint-disable-line no-undef +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var fragTemplate = ['varying vec2 vTextureCoord;', 'varying vec4 vColor;', 'varying float vTextureId;', 'uniform sampler2D uSamplers[%count%];', 'void main(void){', 'vec4 color;', 'float textureId = floor(vTextureId+0.5);', '%forloop%', 'gl_FragColor = color * vColor;', '}'].join('\n'); function generateMultiTextureShader(gl, maxTextures) { - var vertexSrc = "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\nattribute vec4 aColor;\nattribute float aTextureId;\n\nuniform mat3 projectionMatrix;\n\nvarying vec2 vTextureCoord;\nvarying vec4 vColor;\nvarying float vTextureId;\n\nvoid main(void){\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n\n vTextureCoord = aTextureCoord;\n vTextureId = aTextureId;\n vColor = vec4(aColor.rgb * aColor.a, aColor.a);\n}\n"; + var vertexSrc = 'precision highp float;\r\nattribute vec2 aVertexPosition;\r\nattribute vec2 aTextureCoord;\r\nattribute vec4 aColor;\r\nattribute float aTextureId;\r\n\r\nuniform mat3 projectionMatrix;\r\n\r\nvarying vec2 vTextureCoord;\r\nvarying vec4 vColor;\r\nvarying float vTextureId;\r\n\r\nvoid main(void){\r\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\r\n\r\n vTextureCoord = aTextureCoord;\r\n vTextureId = aTextureId;\r\n vColor = aColor;\r\n}\r\n'; var fragmentSrc = fragTemplate; fragmentSrc = fragmentSrc.replace(/%count%/gi, maxTextures); @@ -20580,7 +22307,7 @@ function generateSampleSrc(maxTextures) { return src; } -},{"../../Shader":41}],103:[function(require,module,exports){ +},{"../../Shader":44,"path":25}],108:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -20601,10 +22328,22 @@ var _utils = require('../utils'); var _const = require('../const'); +var _settings = require('../settings'); + +var _settings2 = _interopRequireDefault(_settings); + var _TextStyle = require('./TextStyle'); var _TextStyle2 = _interopRequireDefault(_TextStyle); +var _TextMetrics = require('./TextMetrics'); + +var _TextMetrics2 = _interopRequireDefault(_TextMetrics); + +var _trimCanvas = require('../utils/trimCanvas'); + +var _trimCanvas2 = _interopRequireDefault(_trimCanvas); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -20627,7 +22366,7 @@ var defaultDestroyOptions = { * A Text can be created directly from a string and a style object * * ```js - * let text = new PIXI.Text('This is a pixi text',{fontFamily : 'Arial', fontSize: 24, fill : 0xff1010, align : 'center'}); + * let text = new PIXI.Text('This is a PixiJS text',{fontFamily : 'Arial', fontSize: 24, fill : 0xff1010, align : 'center'}); * ``` * * @class @@ -20641,32 +22380,36 @@ var Text = function (_Sprite) { /** * @param {string} text - The string that you would like the text to display * @param {object|PIXI.TextStyle} [style] - The style parameters + * @param {HTMLCanvasElement} [canvas] - The canvas element for drawing text */ - function Text(text, style) { + function Text(text, style, canvas) { _classCallCheck(this, Text); - var canvas = document.createElement('canvas'); + canvas = canvas || document.createElement('canvas'); canvas.width = 3; canvas.height = 3; - var texture = _Texture2.default.fromCanvas(canvas); + var texture = _Texture2.default.fromCanvas(canvas, _settings2.default.SCALE_MODE, 'text'); texture.orig = new _math.Rectangle(); texture.trim = new _math.Rectangle(); + // base texture is already automatically added to the cache, now adding the actual texture + var _this = _possibleConstructorReturn(this, _Sprite.call(this, texture)); + + _Texture2.default.addToCache(_this._texture, _this._texture.baseTexture.textureCacheIds[0]); + /** * The canvas element that everything is drawn to * * @member {HTMLCanvasElement} */ - var _this = _possibleConstructorReturn(this, _Sprite.call(this, texture)); - _this.canvas = canvas; /** * The canvas 2d context that everything is drawn with - * @member {HTMLCanvasElement} + * @member {CanvasRenderingContext2D} */ _this.context = _this.canvas.getContext('2d'); @@ -20675,7 +22418,7 @@ var Text = function (_Sprite) { * @member {number} * @default 1 */ - _this.resolution = _const.RESOLUTION; + _this.resolution = _settings2.default.RESOLUTION; /** * Private tracker for the current text. @@ -20736,120 +22479,93 @@ var Text = function (_Sprite) { return; } - // build canvas api font setting from invididual components. Convert a numeric style.fontSize to px - var fontSizeString = typeof style.fontSize === 'number' ? style.fontSize + 'px' : style.fontSize; - - this._font = style.fontStyle + ' ' + style.fontVariant + ' ' + style.fontWeight + ' ' + fontSizeString + ' ' + style.fontFamily; - - this.context.font = this._font; - - // word wrap - // preserve original text - var outputText = style.wordWrap ? this.wordWrap(this._text) : this._text; - - // split text into lines - var lines = outputText.split(/(?:\r\n|\r|\n)/); - - // calculate text width - var lineWidths = new Array(lines.length); - var maxLineWidth = 0; - var fontProperties = this.determineFontProperties(this._font); - - for (var i = 0; i < lines.length; i++) { - var lineWidth = this.context.measureText(lines[i]).width + (lines[i].length - 1) * style.letterSpacing; - - lineWidths[i] = lineWidth; - maxLineWidth = Math.max(maxLineWidth, lineWidth); - } - - var width = maxLineWidth + style.strokeThickness; - - if (style.dropShadow) { - width += style.dropShadowDistance; - } - - width += style.padding * 2; - - this.canvas.width = Math.ceil((width + this.context.lineWidth) * this.resolution); - - // calculate text height - var lineHeight = this.style.lineHeight || fontProperties.fontSize + style.strokeThickness; + this._font = this._style.toFontString(); - var height = Math.max(lineHeight, fontProperties.fontSize + style.strokeThickness) + (lines.length - 1) * lineHeight; - - if (style.dropShadow) { - height += style.dropShadowDistance; - } + var context = this.context; + var measured = _TextMetrics2.default.measureText(this._text, this._style, this._style.wordWrap, this.canvas); + var width = measured.width; + var height = measured.height; + var lines = measured.lines; + var lineHeight = measured.lineHeight; + var lineWidths = measured.lineWidths; + var maxLineWidth = measured.maxLineWidth; + var fontProperties = measured.fontProperties; - this.canvas.height = Math.ceil((height + this._style.padding * 2) * this.resolution); + this.canvas.width = Math.ceil((width + style.padding * 2) * this.resolution); + this.canvas.height = Math.ceil((height + style.padding * 2) * this.resolution); - this.context.scale(this.resolution, this.resolution); + context.scale(this.resolution, this.resolution); - this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); + context.clearRect(0, 0, this.canvas.width, this.canvas.height); - this.context.font = this._font; - this.context.strokeStyle = style.stroke; - this.context.lineWidth = style.strokeThickness; - this.context.textBaseline = style.textBaseline; - this.context.lineJoin = style.lineJoin; - this.context.miterLimit = style.miterLimit; + context.font = this._font; + context.strokeStyle = style.stroke; + context.lineWidth = style.strokeThickness; + context.textBaseline = style.textBaseline; + context.lineJoin = style.lineJoin; + context.miterLimit = style.miterLimit; var linePositionX = void 0; var linePositionY = void 0; if (style.dropShadow) { + context.fillStyle = style.dropShadowColor; + context.globalAlpha = style.dropShadowAlpha; + context.shadowBlur = style.dropShadowBlur; + if (style.dropShadowBlur > 0) { - this.context.shadowColor = style.dropShadowColor; - this.context.shadowBlur = style.dropShadowBlur; - } else { - this.context.fillStyle = style.dropShadowColor; + context.shadowColor = style.dropShadowColor; } var xShadowOffset = Math.cos(style.dropShadowAngle) * style.dropShadowDistance; var yShadowOffset = Math.sin(style.dropShadowAngle) * style.dropShadowDistance; - for (var _i = 0; _i < lines.length; _i++) { + for (var i = 0; i < lines.length; i++) { linePositionX = style.strokeThickness / 2; - linePositionY = style.strokeThickness / 2 + _i * lineHeight + fontProperties.ascent; + linePositionY = style.strokeThickness / 2 + i * lineHeight + fontProperties.ascent; if (style.align === 'right') { - linePositionX += maxLineWidth - lineWidths[_i]; + linePositionX += maxLineWidth - lineWidths[i]; } else if (style.align === 'center') { - linePositionX += (maxLineWidth - lineWidths[_i]) / 2; + linePositionX += (maxLineWidth - lineWidths[i]) / 2; } if (style.fill) { - this.drawLetterSpacing(lines[_i], linePositionX + xShadowOffset + style.padding, linePositionY + yShadowOffset + style.padding); + this.drawLetterSpacing(lines[i], linePositionX + xShadowOffset + style.padding, linePositionY + yShadowOffset + style.padding); if (style.stroke && style.strokeThickness) { - this.context.strokeStyle = style.dropShadowColor; - this.drawLetterSpacing(lines[_i], linePositionX + xShadowOffset + style.padding, linePositionY + yShadowOffset + style.padding, true); - this.context.strokeStyle = style.stroke; + context.strokeStyle = style.dropShadowColor; + this.drawLetterSpacing(lines[i], linePositionX + xShadowOffset + style.padding, linePositionY + yShadowOffset + style.padding, true); + context.strokeStyle = style.stroke; } } } } + // reset the shadow blur and alpha that was set by the drop shadow, for the regular text + context.shadowBlur = 0; + context.globalAlpha = 1; + // set canvas text styles - this.context.fillStyle = this._generateFillStyle(style, lines); + context.fillStyle = this._generateFillStyle(style, lines); // draw lines line by line - for (var _i2 = 0; _i2 < lines.length; _i2++) { + for (var _i = 0; _i < lines.length; _i++) { linePositionX = style.strokeThickness / 2; - linePositionY = style.strokeThickness / 2 + _i2 * lineHeight + fontProperties.ascent; + linePositionY = style.strokeThickness / 2 + _i * lineHeight + fontProperties.ascent; if (style.align === 'right') { - linePositionX += maxLineWidth - lineWidths[_i2]; + linePositionX += maxLineWidth - lineWidths[_i]; } else if (style.align === 'center') { - linePositionX += (maxLineWidth - lineWidths[_i2]) / 2; + linePositionX += (maxLineWidth - lineWidths[_i]) / 2; } if (style.stroke && style.strokeThickness) { - this.drawLetterSpacing(lines[_i2], linePositionX + style.padding, linePositionY + style.padding, true); + this.drawLetterSpacing(lines[_i], linePositionX + style.padding, linePositionY + style.padding, true); } if (style.fill) { - this.drawLetterSpacing(lines[_i2], linePositionX + style.padding, linePositionY + style.padding); + this.drawLetterSpacing(lines[_i], linePositionX + style.padding, linePositionY + style.padding); } } @@ -20909,29 +22625,41 @@ var Text = function (_Sprite) { Text.prototype.updateTexture = function updateTexture() { + var canvas = this.canvas; + + if (this._style.trim) { + var trimmed = (0, _trimCanvas2.default)(canvas); + + canvas.width = trimmed.width; + canvas.height = trimmed.height; + this.context.putImageData(trimmed.data, 0, 0); + } + var texture = this._texture; var style = this._style; + var padding = style.trim ? 0 : style.padding; + var baseTexture = texture.baseTexture; - texture.baseTexture.hasLoaded = true; - texture.baseTexture.resolution = this.resolution; + baseTexture.hasLoaded = true; + baseTexture.resolution = this.resolution; - texture.baseTexture.realWidth = this.canvas.width; - texture.baseTexture.realHeight = this.canvas.height; - texture.baseTexture.width = this.canvas.width / this.resolution; - texture.baseTexture.height = this.canvas.height / this.resolution; - texture.trim.width = texture._frame.width = this.canvas.width / this.resolution; - texture.trim.height = texture._frame.height = this.canvas.height / this.resolution; + baseTexture.realWidth = canvas.width; + baseTexture.realHeight = canvas.height; + baseTexture.width = canvas.width / this.resolution; + baseTexture.height = canvas.height / this.resolution; - texture.trim.x = -style.padding; - texture.trim.y = -style.padding; + texture.trim.width = texture._frame.width = canvas.width / this.resolution; + texture.trim.height = texture._frame.height = canvas.height / this.resolution; + texture.trim.x = -padding; + texture.trim.y = -padding; - texture.orig.width = texture._frame.width - style.padding * 2; - texture.orig.height = texture._frame.height - style.padding * 2; + texture.orig.width = texture._frame.width - padding * 2; + texture.orig.height = texture._frame.height - padding * 2; // call sprite onTextureUpdate to update scale if _width or _height were set this._onTextureUpdate(); - texture.baseTexture.emit('update', texture.baseTexture); + baseTexture.emit('update', baseTexture); this.dirty = false; }; @@ -20974,163 +22702,17 @@ var Text = function (_Sprite) { }; /** - * Calculates the ascent, descent and fontSize of a given fontStyle - * - * @private - * @param {string} fontStyle - String representing the style of the font - * @return {Object} Font properties object - */ - - - Text.prototype.determineFontProperties = function determineFontProperties(fontStyle) { - var properties = Text.fontPropertiesCache[fontStyle]; - - if (!properties) { - properties = {}; - - var canvas = Text.fontPropertiesCanvas; - var context = Text.fontPropertiesContext; - - context.font = fontStyle; - - var width = Math.ceil(context.measureText('|MÉq').width); - var baseline = Math.ceil(context.measureText('M').width); - var height = 2 * baseline; - - baseline = baseline * 1.4 | 0; - - canvas.width = width; - canvas.height = height; - - context.fillStyle = '#f00'; - context.fillRect(0, 0, width, height); - - context.font = fontStyle; - - context.textBaseline = 'alphabetic'; - context.fillStyle = '#000'; - context.fillText('|MÉq', 0, baseline); - - var imagedata = context.getImageData(0, 0, width, height).data; - var pixels = imagedata.length; - var line = width * 4; - - var i = 0; - var idx = 0; - var stop = false; - - // ascent. scan from top to bottom until we find a non red pixel - for (i = 0; i < baseline; ++i) { - for (var j = 0; j < line; j += 4) { - if (imagedata[idx + j] !== 255) { - stop = true; - break; - } - } - if (!stop) { - idx += line; - } else { - break; - } - } - - properties.ascent = baseline - i; - - idx = pixels - line; - stop = false; - - // descent. scan from bottom to top until we find a non red pixel - for (i = height; i > baseline; --i) { - for (var _j = 0; _j < line; _j += 4) { - if (imagedata[idx + _j] !== 255) { - stop = true; - break; - } - } - - if (!stop) { - idx -= line; - } else { - break; - } - } - - properties.descent = i - baseline; - properties.fontSize = properties.ascent + properties.descent; - - Text.fontPropertiesCache[fontStyle] = properties; - } - - return properties; - }; - - /** - * Applies newlines to a string to have it optimally fit into the horizontal - * bounds set by the Text object's wordWrapWidth property. + * Gets the local bounds of the text object. * - * @private - * @param {string} text - String to apply word wrapping to - * @return {string} New string with new lines applied where required + * @param {Rectangle} rect - The output rectangle. + * @return {Rectangle} The bounds. */ - Text.prototype.wordWrap = function wordWrap(text) { - // Greedy wrapping algorithm that will wrap words as the line grows longer - // than its horizontal bounds. - var result = ''; - var lines = text.split('\n'); - var wordWrapWidth = this._style.wordWrapWidth; - - for (var i = 0; i < lines.length; i++) { - var spaceLeft = wordWrapWidth; - var words = lines[i].split(' '); - - for (var j = 0; j < words.length; j++) { - var wordWidth = this.context.measureText(words[j]).width; - - if (this._style.breakWords && wordWidth > wordWrapWidth) { - // Word should be split in the middle - var characters = words[j].split(''); - - for (var c = 0; c < characters.length; c++) { - var characterWidth = this.context.measureText(characters[c]).width; - - if (characterWidth > spaceLeft) { - result += '\n' + characters[c]; - spaceLeft = wordWrapWidth - characterWidth; - } else { - if (c === 0) { - result += ' '; - } - - result += characters[c]; - spaceLeft -= characterWidth; - } - } - } else { - var wordWidthWithSpace = wordWidth + this.context.measureText(' ').width; - - if (j === 0 || wordWidthWithSpace > spaceLeft) { - // Skip printing the newline if it's the first word of the line that is - // greater than the word wrap width. - if (j > 0) { - result += '\n'; - } - result += words[j]; - spaceLeft = wordWrapWidth - wordWidth; - } else { - spaceLeft -= wordWidthWithSpace; - result += ' ' + words[j]; - } - } - } - - if (i < lines.length - 1) { - result += '\n'; - } - } + Text.prototype.getLocalBounds = function getLocalBounds(rect) { + this.updateText(true); - return result; + return _Sprite.prototype.getLocalBounds.call(this, rect); }; /** @@ -21160,7 +22742,7 @@ var Text = function (_Sprite) { * * @private * @param {object} style - The style. - * @param {string} lines - The lines of text. + * @param {string[]} lines - The lines of text. * @return {string|number|CanvasGradient} The fill style */ @@ -21185,19 +22767,44 @@ var Text = function (_Sprite) { var width = this.canvas.width / this.resolution; var height = this.canvas.height / this.resolution; + // make a copy of the style settings, so we can manipulate them later + var fill = style.fill.slice(); + var fillGradientStops = style.fillGradientStops.slice(); + + // wanting to evenly distribute the fills. So an array of 4 colours should give fills of 0.25, 0.5 and 0.75 + if (!fillGradientStops.length) { + var lengthPlus1 = fill.length + 1; + + for (var i = 1; i < lengthPlus1; ++i) { + fillGradientStops.push(i / lengthPlus1); + } + } + + // stop the bleeding of the last gradient on the line above to the top gradient of the this line + // by hard defining the first gradient colour at point 0, and last gradient colour at point 1 + fill.unshift(style.fill[0]); + fillGradientStops.unshift(0); + + fill.push(style.fill[style.fill.length - 1]); + fillGradientStops.push(1); + if (style.fillGradientType === _const.TEXT_GRADIENT.LINEAR_VERTICAL) { // start the gradient at the top center of the canvas, and end at the bottom middle of the canvas gradient = this.context.createLinearGradient(width / 2, 0, width / 2, height); - // we need to repeat the gradient so that each invididual line of text has the same vertical gradient effect + // we need to repeat the gradient so that each individual line of text has the same vertical gradient effect // ['#FF0000', '#00FF00', '#0000FF'] over 2 lines would create stops at 0.125, 0.25, 0.375, 0.625, 0.75, 0.875 - totalIterations = (style.fill.length + 1) * lines.length; + totalIterations = (fill.length + 1) * lines.length; currentIteration = 0; - for (var i = 0; i < lines.length; i++) { + for (var _i2 = 0; _i2 < lines.length; _i2++) { currentIteration += 1; - for (var j = 0; j < style.fill.length; j++) { - stop = currentIteration / totalIterations; - gradient.addColorStop(stop, style.fill[j]); + for (var j = 0; j < fill.length; j++) { + if (typeof fillGradientStops[j] === 'number') { + stop = fillGradientStops[j] / lines.length + _i2 / lines.length; + } else { + stop = currentIteration / totalIterations; + } + gradient.addColorStop(stop, fill[j]); currentIteration++; } } @@ -21207,12 +22814,16 @@ var Text = function (_Sprite) { // can just evenly space out the gradients in this case, as multiple lines makes no difference // to an even left to right gradient - totalIterations = style.fill.length + 1; + totalIterations = fill.length + 1; currentIteration = 1; - for (var _i3 = 0; _i3 < style.fill.length; _i3++) { - stop = currentIteration / totalIterations; - gradient.addColorStop(stop, style.fill[_i3]); + for (var _i3 = 0; _i3 < fill.length; _i3++) { + if (typeof fillGradientStops[_i3] === 'number') { + stop = fillGradientStops[_i3]; + } else { + stop = currentIteration / totalIterations; + } + gradient.addColorStop(stop, fill[_i3]); currentIteration++; } } @@ -21223,7 +22834,7 @@ var Text = function (_Sprite) { /** * Destroys this text object. * Note* Unlike a Sprite, a Text object will automatically destroy its baseTexture and texture as - * the majorety of the time the texture will not be shared with any other Sprites. + * the majority of the time the texture will not be shared with any other Sprites. * * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options * have been set to that value @@ -21254,7 +22865,6 @@ var Text = function (_Sprite) { * The width of the Text, setting this will actually modify the scale to achieve the value set * * @member {number} - * @memberof PIXI.Text# */ @@ -21263,21 +22873,15 @@ var Text = function (_Sprite) { get: function get() { this.updateText(true); - return Math.abs(this.scale.x) * this.texture.orig.width; - } - - /** - * Sets the width of the text. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + return Math.abs(this.scale.x) * this._texture.orig.width; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.updateText(true); var s = (0, _utils.sign)(this.scale.x) || 1; - this.scale.x = s * value / this.texture.orig.width; + this.scale.x = s * value / this._texture.orig.width; this._width = value; } @@ -21285,7 +22889,6 @@ var Text = function (_Sprite) { * The height of the Text, setting this will actually modify the scale to achieve the value set * * @member {number} - * @memberof PIXI.Text# */ }, { @@ -21294,20 +22897,14 @@ var Text = function (_Sprite) { this.updateText(true); return Math.abs(this.scale.y) * this._texture.orig.height; - } - - /** - * Sets the height of the text. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.updateText(true); var s = (0, _utils.sign)(this.scale.y) || 1; - this.scale.y = s * value / this.texture.orig.height; + this.scale.y = s * value / this._texture.orig.height; this._height = value; } @@ -21316,22 +22913,15 @@ var Text = function (_Sprite) { * object and mark the text as dirty. * * @member {object|PIXI.TextStyle} - * @memberof PIXI.Text# */ }, { key: 'style', get: function get() { return this._style; - } - - /** - * Sets the style of the text. - * - * @param {object} style - The value to set to. - */ - , - set: function set(style) { + }, + set: function set(style) // eslint-disable-line require-jsdoc + { style = style || {}; if (style instanceof _TextStyle2.default) { @@ -21348,24 +22938,16 @@ var Text = function (_Sprite) { * Set the copy for the text object. To split a line you can use '\n'. * * @member {string} - * @memberof PIXI.Text# */ }, { key: 'text', get: function get() { return this._text; - } - - /** - * Sets the text. - * - * @param {string} text - The value to set to. - */ - , - set: function set(text) { - text = text || ' '; - text = text.toString(); + }, + set: function set(text) // eslint-disable-line require-jsdoc + { + text = String(text === '' || text === null || text === undefined ? ' ' : text); if (this._text === text) { return; @@ -21380,12 +22962,309 @@ var Text = function (_Sprite) { exports.default = Text; +},{"../const":46,"../math":70,"../settings":101,"../sprites/Sprite":102,"../textures/Texture":115,"../utils":124,"../utils/trimCanvas":129,"./TextMetrics":109,"./TextStyle":110}],109:[function(require,module,exports){ +'use strict'; + +exports.__esModule = true; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * The TextMetrics object represents the measurement of a block of text with a specified style. + * + * @class + * @memberOf PIXI + */ +var TextMetrics = function () { + /** + * @param {string} text - the text that was measured + * @param {PIXI.TextStyle} style - the style that was measured + * @param {number} width - the measured width of the text + * @param {number} height - the measured height of the text + * @param {array} lines - an array of the lines of text broken by new lines and wrapping if specified in style + * @param {array} lineWidths - an array of the line widths for each line matched to `lines` + * @param {number} lineHeight - the measured line height for this style + * @param {number} maxLineWidth - the maximum line width for all measured lines + * @param {Object} fontProperties - the font properties object from TextMetrics.measureFont + */ + function TextMetrics(text, style, width, height, lines, lineWidths, lineHeight, maxLineWidth, fontProperties) { + _classCallCheck(this, TextMetrics); + + this.text = text; + this.style = style; + this.width = width; + this.height = height; + this.lines = lines; + this.lineWidths = lineWidths; + this.lineHeight = lineHeight; + this.maxLineWidth = maxLineWidth; + this.fontProperties = fontProperties; + } + + /** + * Measures the supplied string of text and returns a Rectangle. + * + * @param {string} text - the text to measure. + * @param {PIXI.TextStyle} style - the text style to use for measuring + * @param {boolean} [wordWrap] - optional override for if word-wrap should be applied to the text. + * @param {HTMLCanvasElement} [canvas] - optional specification of the canvas to use for measuring. + * @return {PIXI.TextMetrics} measured width and height of the text. + */ + + + TextMetrics.measureText = function measureText(text, style, wordWrap) { + var canvas = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : TextMetrics._canvas; -Text.fontPropertiesCache = {}; -Text.fontPropertiesCanvas = document.createElement('canvas'); -Text.fontPropertiesContext = Text.fontPropertiesCanvas.getContext('2d'); + wordWrap = wordWrap || style.wordWrap; + var font = style.toFontString(); + var fontProperties = TextMetrics.measureFont(font); + var context = canvas.getContext('2d'); + + context.font = font; + + var outputText = wordWrap ? TextMetrics.wordWrap(text, style, canvas) : text; + var lines = outputText.split(/(?:\r\n|\r|\n)/); + var lineWidths = new Array(lines.length); + var maxLineWidth = 0; + + for (var i = 0; i < lines.length; i++) { + var lineWidth = context.measureText(lines[i]).width + (lines[i].length - 1) * style.letterSpacing; + + lineWidths[i] = lineWidth; + maxLineWidth = Math.max(maxLineWidth, lineWidth); + } + var width = maxLineWidth + style.strokeThickness; + + if (style.dropShadow) { + width += style.dropShadowDistance; + } + + var lineHeight = style.lineHeight || fontProperties.fontSize + style.strokeThickness; + var height = Math.max(lineHeight, fontProperties.fontSize + style.strokeThickness) + (lines.length - 1) * (lineHeight + style.leading); + + if (style.dropShadow) { + height += style.dropShadowDistance; + } + + return new TextMetrics(text, style, width, height, lines, lineWidths, lineHeight + style.leading, maxLineWidth, fontProperties); + }; + + /** + * Applies newlines to a string to have it optimally fit into the horizontal + * bounds set by the Text object's wordWrapWidth property. + * + * @private + * @param {string} text - String to apply word wrapping to + * @param {PIXI.TextStyle} style - the style to use when wrapping + * @param {HTMLCanvasElement} [canvas] - optional specification of the canvas to use for measuring. + * @return {string} New string with new lines applied where required + */ + + + TextMetrics.wordWrap = function wordWrap(text, style) { + var canvas = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : TextMetrics._canvas; + + var context = canvas.getContext('2d'); + + // Greedy wrapping algorithm that will wrap words as the line grows longer + // than its horizontal bounds. + var result = ''; + var lines = text.split('\n'); + var wordWrapWidth = style.wordWrapWidth; + var characterCache = {}; + + for (var i = 0; i < lines.length; i++) { + var spaceLeft = wordWrapWidth; + var words = lines[i].split(' '); + + for (var j = 0; j < words.length; j++) { + var wordWidth = context.measureText(words[j]).width; + + if (style.breakWords && wordWidth > wordWrapWidth) { + // Word should be split in the middle + var characters = words[j].split(''); + + for (var c = 0; c < characters.length; c++) { + var character = characters[c]; + var characterWidth = characterCache[character]; + + if (characterWidth === undefined) { + characterWidth = context.measureText(character).width; + characterCache[character] = characterWidth; + } + + if (characterWidth > spaceLeft) { + result += '\n' + character; + spaceLeft = wordWrapWidth - characterWidth; + } else { + if (c === 0) { + result += ' '; + } + + result += character; + spaceLeft -= characterWidth; + } + } + } else { + var wordWidthWithSpace = wordWidth + context.measureText(' ').width; + + if (j === 0 || wordWidthWithSpace > spaceLeft) { + // Skip printing the newline if it's the first word of the line that is + // greater than the word wrap width. + if (j > 0) { + result += '\n'; + } + result += words[j]; + spaceLeft = wordWrapWidth - wordWidth; + } else { + spaceLeft -= wordWidthWithSpace; + result += ' ' + words[j]; + } + } + } + + if (i < lines.length - 1) { + result += '\n'; + } + } + + return result; + }; + + /** + * Calculates the ascent, descent and fontSize of a given font-style + * + * @static + * @param {string} font - String representing the style of the font + * @return {PIXI.TextMetrics~FontMetrics} Font properties object + */ + + + TextMetrics.measureFont = function measureFont(font) { + // as this method is used for preparing assets, don't recalculate things if we don't need to + if (TextMetrics._fonts[font]) { + return TextMetrics._fonts[font]; + } + + var properties = {}; + + var canvas = TextMetrics._canvas; + var context = TextMetrics._context; + + context.font = font; + + var width = Math.ceil(context.measureText('|MÉq').width); + var baseline = Math.ceil(context.measureText('M').width); + var height = 2 * baseline; + + baseline = baseline * 1.4 | 0; + + canvas.width = width; + canvas.height = height; + + context.fillStyle = '#f00'; + context.fillRect(0, 0, width, height); + + context.font = font; + + context.textBaseline = 'alphabetic'; + context.fillStyle = '#000'; + context.fillText('|MÉq', 0, baseline); + + var imagedata = context.getImageData(0, 0, width, height).data; + var pixels = imagedata.length; + var line = width * 4; + + var i = 0; + var idx = 0; + var stop = false; + + // ascent. scan from top to bottom until we find a non red pixel + for (i = 0; i < baseline; ++i) { + for (var j = 0; j < line; j += 4) { + if (imagedata[idx + j] !== 255) { + stop = true; + break; + } + } + if (!stop) { + idx += line; + } else { + break; + } + } + + properties.ascent = baseline - i; + + idx = pixels - line; + stop = false; + + // descent. scan from bottom to top until we find a non red pixel + for (i = height; i > baseline; --i) { + for (var _j = 0; _j < line; _j += 4) { + if (imagedata[idx + _j] !== 255) { + stop = true; + break; + } + } + + if (!stop) { + idx -= line; + } else { + break; + } + } + + properties.descent = i - baseline; + properties.fontSize = properties.ascent + properties.descent; + + TextMetrics._fonts[font] = properties; + + return properties; + }; + + return TextMetrics; +}(); + +/** + * Internal return object for {@link PIXI.TextMetrics.measureFont `TextMetrics.measureFont`}. + * @class FontMetrics + * @memberof PIXI.TextMetrics~ + * @property {number} ascent - The ascent distance + * @property {number} descent - The descent distance + * @property {number} fontSize - Font size from ascent to descent + */ + +exports.default = TextMetrics; +var canvas = document.createElement('canvas'); + +canvas.width = canvas.height = 10; + +/** + * Cached canvas element for measuring text + * @memberof PIXI.TextMetrics + * @type {HTMLCanvasElement} + * @private + */ +TextMetrics._canvas = canvas; + +/** + * Cache for context to use. + * @memberof PIXI.TextMetrics + * @type {CanvasRenderingContext2D} + * @private + */ +TextMetrics._context = canvas.getContext('2d'); + +/** + * Cache of PIXI.TextMetrics~FontMetrics objects. + * @memberof PIXI.TextMetrics + * @type {Object} + * @private + */ +TextMetrics._fonts = {}; -},{"../const":42,"../math":66,"../sprites/Sprite":97,"../textures/Texture":108,"../utils":115,"./TextStyle":104}],104:[function(require,module,exports){ +},{}],110:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -21403,12 +23282,14 @@ var defaultStyle = { align: 'left', breakWords: false, dropShadow: false, + dropShadowAlpha: 1, dropShadowAngle: Math.PI / 6, dropShadowBlur: 0, - dropShadowColor: '#000000', + dropShadowColor: 'black', dropShadowDistance: 5, fill: 'black', fillGradientType: _const.TEXT_GRADIENT.LINEAR_VERTICAL, + fillGradientStops: [], fontFamily: 'Arial', fontSize: 26, fontStyle: 'normal', @@ -21422,8 +23303,10 @@ var defaultStyle = { stroke: 'black', strokeThickness: 0, textBaseline: 'alphabetic', + trim: false, wordWrap: false, - wordWrapWidth: 100 + wordWrapWidth: 100, + leading: 0 }; /** @@ -21442,23 +23325,27 @@ var TextStyle = function () { * @param {boolean} [style.breakWords=false] - Indicates if lines can be wrapped within words, it * needs wordWrap to be set to true * @param {boolean} [style.dropShadow=false] - Set a drop shadow for the text + * @param {number} [style.dropShadowAlpha=1] - Set alpha for the drop shadow * @param {number} [style.dropShadowAngle=Math.PI/6] - Set a angle of the drop shadow * @param {number} [style.dropShadowBlur=0] - Set a shadow blur radius - * @param {string} [style.dropShadowColor='#000000'] - A fill style to be used on the dropshadow e.g 'red', '#00FF00' + * @param {string|number} [style.dropShadowColor='black'] - A fill style to be used on the dropshadow e.g 'red', '#00FF00' * @param {number} [style.dropShadowDistance=5] - Set a distance of the drop shadow * @param {string|string[]|number|number[]|CanvasGradient|CanvasPattern} [style.fill='black'] - A canvas * fillstyle that will be used on the text e.g 'red', '#00FF00'. Can be an array to create a gradient * eg ['#000000','#FFFFFF'] * {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle|MDN} - * @param {number} [style.fillGradientType=PIXI.TEXT_GRADIENT.LINEAR_VERTICAL] - If fills styles are - * supplied, this can change the type/direction of the gradient. See {@link PIXI.TEXT_GRADIENT} for possible values - * @param {string} [style.fontFamily='Arial'] - The font family + * @param {number} [style.fillGradientType=PIXI.TEXT_GRADIENT.LINEAR_VERTICAL] - If fill is an array of colours + * to create a gradient, this can change the type/direction of the gradient. See {@link PIXI.TEXT_GRADIENT} + * @param {number[]} [style.fillGradientStops] - If fill is an array of colours to create a gradient, this array can set + * the stop points (numbers between 0 and 1) for the color, overriding the default behaviour of evenly spacing them. + * @param {string|string[]} [style.fontFamily='Arial'] - The font family * @param {number|string} [style.fontSize=26] - The font size (as a number it converts to px, but as a string, * equivalents are '26px','20pt','160%' or '1.6em') * @param {string} [style.fontStyle='normal'] - The font style ('normal', 'italic' or 'oblique') * @param {string} [style.fontVariant='normal'] - The font variant ('normal' or 'small-caps') * @param {string} [style.fontWeight='normal'] - The font weight ('normal', 'bold', 'bolder', 'lighter' and '100', * '200', '300', '400', '500', '600', '700', 800' or '900') + * @param {number} [style.leading=0] - The space between lines * @param {number} [style.letterSpacing=0] - The amount of spacing between letters, default is 0 * @param {number} [style.lineHeight] - The line height, a number that represents the vertical space that a letter uses * @param {string} [style.lineJoin='miter'] - The lineJoin property sets the type of corner created, it can resolve @@ -21471,6 +23358,7 @@ var TextStyle = function () { * e.g 'blue', '#FCFF00' * @param {number} [style.strokeThickness=0] - A number that represents the thickness of the stroke. * Default is 0 (no stroke) + * @param {boolean} [style.trim=false] - Trim transparent borders * @param {string} [style.textBaseline='alphabetic'] - The baseline of the text that is rendered. * @param {boolean} [style.wordWrap=false] - Indicates if word wrap should be used * @param {number} [style.wordWrapWidth=100] - The width at which text will wrap, it needs wordWrap to be set to true @@ -21494,7 +23382,7 @@ var TextStyle = function () { TextStyle.prototype.clone = function clone() { var clonedProperties = {}; - for (var key in this._defaults) { + for (var key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -21507,7 +23395,45 @@ var TextStyle = function () { TextStyle.prototype.reset = function reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); + }; + + /** + * Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text + * + * @member {string} + */ + + + /** + * Generates a font style string to use for `TextMetrics.measureFont()`. + * + * @return {string} Font style string, for passing to `TextMetrics.measureFont()` + */ + TextStyle.prototype.toFontString = function toFontString() { + // build canvas api font setting from individual components. Convert a numeric this.fontSize to px + var fontSizeString = typeof this.fontSize === 'number' ? this.fontSize + 'px' : this.fontSize; + + // Clean-up fontFamily property by quoting each font name + // this will support font names with spaces + var fontFamilies = this.fontFamily; + + if (!Array.isArray(this.fontFamily)) { + fontFamilies = this.fontFamily.split(','); + } + + for (var i = fontFamilies.length - 1; i >= 0; i--) { + // Trim any extra white-space + var fontFamily = fontFamilies[i].trim(); + + // Check if font already contains strings + if (!/([\"\'])[^\'\"]+\1/.test(fontFamily)) { + fontFamily = '"' + fontFamily + '"'; + } + fontFamilies[i] = fontFamily; + } + + return this.fontStyle + ' ' + this.fontVariant + ' ' + this.fontWeight + ' ' + fontSizeString + ' ' + fontFamilies.join(','); }; _createClass(TextStyle, [{ @@ -21515,263 +23441,537 @@ var TextStyle = function () { get: function get() { return this._align; }, - set: function set(align) { + set: function set(align) // eslint-disable-line require-jsdoc + { if (this._align !== align) { this._align = align; this.styleID++; } } + + /** + * Indicates if lines can be wrapped within words, it needs wordWrap to be set to true + * + * @member {boolean} + */ + }, { key: 'breakWords', get: function get() { return this._breakWords; }, - set: function set(breakWords) { + set: function set(breakWords) // eslint-disable-line require-jsdoc + { if (this._breakWords !== breakWords) { this._breakWords = breakWords; this.styleID++; } } + + /** + * Set a drop shadow for the text + * + * @member {boolean} + */ + }, { key: 'dropShadow', get: function get() { return this._dropShadow; }, - set: function set(dropShadow) { + set: function set(dropShadow) // eslint-disable-line require-jsdoc + { if (this._dropShadow !== dropShadow) { this._dropShadow = dropShadow; this.styleID++; } } + + /** + * Set alpha for the drop shadow + * + * @member {number} + */ + + }, { + key: 'dropShadowAlpha', + get: function get() { + return this._dropShadowAlpha; + }, + set: function set(dropShadowAlpha) // eslint-disable-line require-jsdoc + { + if (this._dropShadowAlpha !== dropShadowAlpha) { + this._dropShadowAlpha = dropShadowAlpha; + this.styleID++; + } + } + + /** + * Set a angle of the drop shadow + * + * @member {number} + */ + }, { key: 'dropShadowAngle', get: function get() { return this._dropShadowAngle; }, - set: function set(dropShadowAngle) { + set: function set(dropShadowAngle) // eslint-disable-line require-jsdoc + { if (this._dropShadowAngle !== dropShadowAngle) { this._dropShadowAngle = dropShadowAngle; this.styleID++; } } + + /** + * Set a shadow blur radius + * + * @member {number} + */ + }, { key: 'dropShadowBlur', get: function get() { return this._dropShadowBlur; }, - set: function set(dropShadowBlur) { + set: function set(dropShadowBlur) // eslint-disable-line require-jsdoc + { if (this._dropShadowBlur !== dropShadowBlur) { this._dropShadowBlur = dropShadowBlur; this.styleID++; } } + + /** + * A fill style to be used on the dropshadow e.g 'red', '#00FF00' + * + * @member {string|number} + */ + }, { key: 'dropShadowColor', get: function get() { return this._dropShadowColor; }, - set: function set(dropShadowColor) { + set: function set(dropShadowColor) // eslint-disable-line require-jsdoc + { var outputColor = getColor(dropShadowColor); if (this._dropShadowColor !== outputColor) { this._dropShadowColor = outputColor; this.styleID++; } } + + /** + * Set a distance of the drop shadow + * + * @member {number} + */ + }, { key: 'dropShadowDistance', get: function get() { return this._dropShadowDistance; }, - set: function set(dropShadowDistance) { + set: function set(dropShadowDistance) // eslint-disable-line require-jsdoc + { if (this._dropShadowDistance !== dropShadowDistance) { this._dropShadowDistance = dropShadowDistance; this.styleID++; } } + + /** + * A canvas fillstyle that will be used on the text e.g 'red', '#00FF00'. + * Can be an array to create a gradient eg ['#000000','#FFFFFF'] + * {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle|MDN} + * + * @member {string|string[]|number|number[]|CanvasGradient|CanvasPattern} + */ + }, { key: 'fill', get: function get() { return this._fill; }, - set: function set(fill) { + set: function set(fill) // eslint-disable-line require-jsdoc + { var outputColor = getColor(fill); if (this._fill !== outputColor) { this._fill = outputColor; this.styleID++; } } + + /** + * If fill is an array of colours to create a gradient, this can change the type/direction of the gradient. + * See {@link PIXI.TEXT_GRADIENT} + * + * @member {number} + */ + }, { key: 'fillGradientType', get: function get() { return this._fillGradientType; }, - set: function set(fillGradientType) { + set: function set(fillGradientType) // eslint-disable-line require-jsdoc + { if (this._fillGradientType !== fillGradientType) { this._fillGradientType = fillGradientType; this.styleID++; } } + + /** + * If fill is an array of colours to create a gradient, this array can set the stop points + * (numbers between 0 and 1) for the color, overriding the default behaviour of evenly spacing them. + * + * @member {number[]} + */ + + }, { + key: 'fillGradientStops', + get: function get() { + return this._fillGradientStops; + }, + set: function set(fillGradientStops) // eslint-disable-line require-jsdoc + { + if (!areArraysEqual(this._fillGradientStops, fillGradientStops)) { + this._fillGradientStops = fillGradientStops; + this.styleID++; + } + } + + /** + * The font family + * + * @member {string|string[]} + */ + }, { key: 'fontFamily', get: function get() { return this._fontFamily; }, - set: function set(fontFamily) { + set: function set(fontFamily) // eslint-disable-line require-jsdoc + { if (this.fontFamily !== fontFamily) { this._fontFamily = fontFamily; this.styleID++; } } + + /** + * The font size + * (as a number it converts to px, but as a string, equivalents are '26px','20pt','160%' or '1.6em') + * + * @member {number|string} + */ + }, { key: 'fontSize', get: function get() { return this._fontSize; }, - set: function set(fontSize) { + set: function set(fontSize) // eslint-disable-line require-jsdoc + { if (this._fontSize !== fontSize) { this._fontSize = fontSize; this.styleID++; } } + + /** + * The font style + * ('normal', 'italic' or 'oblique') + * + * @member {string} + */ + }, { key: 'fontStyle', get: function get() { return this._fontStyle; }, - set: function set(fontStyle) { + set: function set(fontStyle) // eslint-disable-line require-jsdoc + { if (this._fontStyle !== fontStyle) { this._fontStyle = fontStyle; this.styleID++; } } + + /** + * The font variant + * ('normal' or 'small-caps') + * + * @member {string} + */ + }, { key: 'fontVariant', get: function get() { return this._fontVariant; }, - set: function set(fontVariant) { + set: function set(fontVariant) // eslint-disable-line require-jsdoc + { if (this._fontVariant !== fontVariant) { this._fontVariant = fontVariant; this.styleID++; } } + + /** + * The font weight + * ('normal', 'bold', 'bolder', 'lighter' and '100', '200', '300', '400', '500', '600', '700', 800' or '900') + * + * @member {string} + */ + }, { key: 'fontWeight', get: function get() { return this._fontWeight; }, - set: function set(fontWeight) { + set: function set(fontWeight) // eslint-disable-line require-jsdoc + { if (this._fontWeight !== fontWeight) { this._fontWeight = fontWeight; this.styleID++; } } + + /** + * The amount of spacing between letters, default is 0 + * + * @member {number} + */ + }, { key: 'letterSpacing', get: function get() { return this._letterSpacing; }, - set: function set(letterSpacing) { + set: function set(letterSpacing) // eslint-disable-line require-jsdoc + { if (this._letterSpacing !== letterSpacing) { this._letterSpacing = letterSpacing; this.styleID++; } } + + /** + * The line height, a number that represents the vertical space that a letter uses + * + * @member {number} + */ + }, { key: 'lineHeight', get: function get() { return this._lineHeight; }, - set: function set(lineHeight) { + set: function set(lineHeight) // eslint-disable-line require-jsdoc + { if (this._lineHeight !== lineHeight) { this._lineHeight = lineHeight; this.styleID++; } } + + /** + * The space between lines + * + * @member {number} + */ + + }, { + key: 'leading', + get: function get() { + return this._leading; + }, + set: function set(leading) // eslint-disable-line require-jsdoc + { + if (this._leading !== leading) { + this._leading = leading; + this.styleID++; + } + } + + /** + * The lineJoin property sets the type of corner created, it can resolve spiked text issues. + * Default is 'miter' (creates a sharp corner). + * + * @member {string} + */ + }, { key: 'lineJoin', get: function get() { return this._lineJoin; }, - set: function set(lineJoin) { + set: function set(lineJoin) // eslint-disable-line require-jsdoc + { if (this._lineJoin !== lineJoin) { this._lineJoin = lineJoin; this.styleID++; } } + + /** + * The miter limit to use when using the 'miter' lineJoin mode + * This can reduce or increase the spikiness of rendered text. + * + * @member {number} + */ + }, { key: 'miterLimit', get: function get() { return this._miterLimit; }, - set: function set(miterLimit) { + set: function set(miterLimit) // eslint-disable-line require-jsdoc + { if (this._miterLimit !== miterLimit) { this._miterLimit = miterLimit; this.styleID++; } } + + /** + * Occasionally some fonts are cropped. Adding some padding will prevent this from happening + * by adding padding to all sides of the text. + * + * @member {number} + */ + }, { key: 'padding', get: function get() { return this._padding; }, - set: function set(padding) { + set: function set(padding) // eslint-disable-line require-jsdoc + { if (this._padding !== padding) { this._padding = padding; this.styleID++; } } + + /** + * A canvas fillstyle that will be used on the text stroke + * e.g 'blue', '#FCFF00' + * + * @member {string|number} + */ + }, { key: 'stroke', get: function get() { return this._stroke; }, - set: function set(stroke) { + set: function set(stroke) // eslint-disable-line require-jsdoc + { var outputColor = getColor(stroke); if (this._stroke !== outputColor) { this._stroke = outputColor; this.styleID++; } } + + /** + * A number that represents the thickness of the stroke. + * Default is 0 (no stroke) + * + * @member {number} + */ + }, { key: 'strokeThickness', get: function get() { return this._strokeThickness; }, - set: function set(strokeThickness) { + set: function set(strokeThickness) // eslint-disable-line require-jsdoc + { if (this._strokeThickness !== strokeThickness) { this._strokeThickness = strokeThickness; this.styleID++; } } + + /** + * The baseline of the text that is rendered. + * + * @member {string} + */ + }, { key: 'textBaseline', get: function get() { return this._textBaseline; }, - set: function set(textBaseline) { + set: function set(textBaseline) // eslint-disable-line require-jsdoc + { if (this._textBaseline !== textBaseline) { this._textBaseline = textBaseline; this.styleID++; } } + + /** + * Trim transparent borders + * + * @member {boolean} + */ + + }, { + key: 'trim', + get: function get() { + return this._trim; + }, + set: function set(trim) // eslint-disable-line require-jsdoc + { + if (this._trim !== trim) { + this._trim = trim; + this.styleID++; + } + } + + /** + * Indicates if word wrap should be used + * + * @member {boolean} + */ + }, { key: 'wordWrap', get: function get() { return this._wordWrap; }, - set: function set(wordWrap) { + set: function set(wordWrap) // eslint-disable-line require-jsdoc + { if (this._wordWrap !== wordWrap) { this._wordWrap = wordWrap; this.styleID++; } } + + /** + * The width at which text will wrap, it needs wordWrap to be set to true + * + * @member {number} + */ + }, { key: 'wordWrapWidth', get: function get() { return this._wordWrapWidth; }, - set: function set(wordWrapWidth) { + set: function set(wordWrapWidth) // eslint-disable-line require-jsdoc + { if (this._wordWrapWidth !== wordWrapWidth) { this._wordWrapWidth = wordWrapWidth; this.styleID++; @@ -21791,21 +23991,64 @@ var TextStyle = function () { exports.default = TextStyle; -function getColor(color) { +function getSingleColor(color) { if (typeof color === 'number') { return (0, _utils.hex2string)(color); - } else if (Array.isArray(color)) { - for (var i = 0; i < color.length; ++i) { - if (typeof color[i] === 'number') { - color[i] = (0, _utils.hex2string)(color[i]); - } + } else if (typeof color === 'string') { + if (color.indexOf('0x') === 0) { + color = color.replace('0x', '#'); } } return color; } -},{"../const":42,"../utils":115}],105:[function(require,module,exports){ +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) { + if (!Array.isArray(color)) { + return getSingleColor(color); + } else { + for (var i = 0; i < color.length; ++i) { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {Array} array1 First array to compare + * @param {Array} array2 Second array to compare + * @return {boolean} Do the arrays contain the same values in the same order + */ +function areArraysEqual(array1, array2) { + if (!Array.isArray(array1) || !Array.isArray(array2)) { + return false; + } + + if (array1.length !== array2.length) { + return false; + } + + for (var i = 0; i < array1.length; ++i) { + if (array1[i] !== array2[i]) { + return false; + } + } + + return true; +} + +},{"../const":46,"../utils":124}],111:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -21814,7 +24057,9 @@ var _BaseTexture2 = require('./BaseTexture'); var _BaseTexture3 = _interopRequireDefault(_BaseTexture2); -var _const = require('../const'); +var _settings = require('../settings'); + +var _settings2 = _interopRequireDefault(_settings); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -21825,7 +24070,7 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** - * A BaseRenderTexture is a special texture that allows any Pixi display object to be rendered to it. + * A BaseRenderTexture is a special texture that allows any PixiJS display object to be rendered to it. * * __Hint__: All DisplayObjects (i.e. Sprites) that render to a BaseRenderTexture should be preloaded * otherwise black rectangles will be drawn instead. @@ -21846,18 +24091,17 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" * baseRenderTexture.render(sprite); * ``` * - * The Sprite in this case will be rendered to a position of 0,0. To render this sprite at its actual - * position a Container should be used: + * The Sprite in this case will be rendered using its local transform. To render this sprite at 0,0 + * you can clear the transform * * ```js - * let doc = new PIXI.Container(); * - * doc.addChild(sprite); + * sprite.setTransform() * * let baseRenderTexture = new PIXI.BaseRenderTexture(100, 100); * let renderTexture = new PIXI.RenderTexture(baseRenderTexture); * - * renderer.render(doc, renderTexture); // Renders to center of RenderTexture + * renderer.render(sprite, renderTexture); // Renders to center of RenderTexture * ``` * * @class @@ -21870,7 +24114,7 @@ var BaseRenderTexture = function (_BaseTexture) { /** * @param {number} [width=100] - The width of the base render texture * @param {number} [height=100] - The height of the base render texture - * @param {number} [scaleMode=PIXI.SCALE_MODES.DEFAULT] - See {@link PIXI.SCALE_MODES} for possible values + * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES} for possible values * @param {number} [resolution=1] - The resolution / device pixel ratio of the texture being generated */ function BaseRenderTexture() { @@ -21883,7 +24127,7 @@ var BaseRenderTexture = function (_BaseTexture) { var _this = _possibleConstructorReturn(this, _BaseTexture.call(this, null, scaleMode)); - _this.resolution = resolution || _const.RESOLUTION; + _this.resolution = resolution || _settings2.default.RESOLUTION; _this.width = width; _this.height = height; @@ -21891,22 +24135,22 @@ var BaseRenderTexture = function (_BaseTexture) { _this.realWidth = _this.width * _this.resolution; _this.realHeight = _this.height * _this.resolution; - _this.scaleMode = scaleMode || _const.SCALE_MODES.DEFAULT; + _this.scaleMode = scaleMode !== undefined ? scaleMode : _settings2.default.SCALE_MODE; _this.hasLoaded = true; /** * A map of renderer IDs to webgl renderTargets * - * @member {object} * @private + * @member {object} */ - _this._glRenderTargets = []; + _this._glRenderTargets = {}; /** - * A reference to the canvas render target (we only need one as this can be shared accross renderers) + * A reference to the canvas render target (we only need one as this can be shared across renderers) * - * @member {object} * @private + * @member {object} */ _this._canvasRenderTarget = null; @@ -21963,7 +24207,7 @@ var BaseRenderTexture = function (_BaseTexture) { exports.default = BaseRenderTexture; -},{"../const":42,"./BaseTexture":106}],106:[function(require,module,exports){ +},{"../settings":101,"./BaseTexture":112}],112:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -21972,7 +24216,9 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol var _utils = require('../utils'); -var _const = require('../const'); +var _settings = require('../settings'); + +var _settings2 = _interopRequireDefault(_settings); var _eventemitter = require('eventemitter3'); @@ -22006,7 +24252,7 @@ var BaseTexture = function (_EventEmitter) { /** * @param {HTMLImageElement|HTMLCanvasElement} [source] - the source object of the texture. - * @param {number} [scaleMode=PIXI.SCALE_MODES.DEFAULT] - See {@link PIXI.SCALE_MODES} for possible values + * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES} for possible values * @param {number} [resolution=1] - The resolution / device pixel ratio of the texture */ function BaseTexture(source, scaleMode, resolution) { @@ -22024,7 +24270,7 @@ var BaseTexture = function (_EventEmitter) { * @member {number} * @default 1 */ - _this.resolution = resolution || _const.RESOLUTION; + _this.resolution = resolution || _settings2.default.RESOLUTION; /** * The width of the base texture set when the image has loaded @@ -22063,10 +24309,10 @@ var BaseTexture = function (_EventEmitter) { * The scale mode to apply when scaling this texture * * @member {number} - * @default PIXI.SCALE_MODES.DEFAULT + * @default PIXI.settings.SCALE_MODE * @see PIXI.SCALE_MODES */ - _this.scaleMode = scaleMode || _const.SCALE_MODES.DEFAULT; + _this.scaleMode = scaleMode !== undefined ? scaleMode : _settings2.default.SCALE_MODE; /** * Set to true once the base texture has successfully loaded. @@ -22144,7 +24390,7 @@ var BaseTexture = function (_EventEmitter) { _this.imageUrl = null; /** - * Wether or not the texture is a power of two, try to use power of two textures as much + * Whether or not the texture is a power of two, try to use power of two textures as much * as you can * * @private @@ -22163,7 +24409,7 @@ var BaseTexture = function (_EventEmitter) { * @member {boolean} * @see PIXI.MIPMAP_TEXTURES */ - _this.mipmap = _const.MIPMAP_TEXTURES; + _this.mipmap = _settings2.default.MIPMAP_TEXTURES; /** * @@ -22172,7 +24418,7 @@ var BaseTexture = function (_EventEmitter) { * @member {number} * @see PIXI.WRAP_MODES */ - _this.wrapMode = _const.WRAP_MODES.DEFAULT; + _this.wrapMode = _settings2.default.WRAP_MODE; /** * A map of renderer IDs to webgl textures @@ -22180,9 +24426,28 @@ var BaseTexture = function (_EventEmitter) { * @private * @member {object} */ - _this._glTextures = []; + _this._glTextures = {}; + _this._enabled = 0; - _this._id = 0; + _this._virtalBoundId = -1; + + /** + * If the object has been destroyed via destroy(). If true, it should not be used. + * + * @member {boolean} + * @private + * @readonly + */ + _this._destroyed = false; + + /** + * The ids under which this BaseTexture has been added to the base texture cache. This is + * automatically set as long as BaseTexture.addToCache is used, but may not be set if a + * BaseTexture is added directly to the BaseTextureCache array. + * + * @member {string[]} + */ + _this.textureCacheIds = []; // if no source passed don't try to load if (source) { @@ -22193,16 +24458,32 @@ var BaseTexture = function (_EventEmitter) { * Fired when a not-immediately-available source finishes loading. * * @protected - * @event loaded - * @memberof PIXI.BaseTexture# + * @event PIXI.BaseTexture#loaded + * @param {PIXI.BaseTexture} baseTexture - Resource loaded. */ /** * Fired when a not-immediately-available source fails to load. * * @protected - * @event error - * @memberof PIXI.BaseTexture# + * @event PIXI.BaseTexture#error + * @param {PIXI.BaseTexture} baseTexture - Resource errored. + */ + + /** + * Fired when BaseTexture is updated. + * + * @protected + * @event PIXI.BaseTexture#update + * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated. + */ + + /** + * Fired when BaseTexture is destroyed. + * + * @protected + * @event PIXI.BaseTexture#dispose + * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed. */ return _this; } @@ -22210,7 +24491,7 @@ var BaseTexture = function (_EventEmitter) { /** * Updates the texture on all the webgl renderers, this also assumes the src has changed. * - * @fires update + * @fires PIXI.BaseTexture#update */ @@ -22220,15 +24501,24 @@ var BaseTexture = function (_EventEmitter) { this.realWidth = this.source.naturalWidth || this.source.videoWidth || this.source.width; this.realHeight = this.source.naturalHeight || this.source.videoHeight || this.source.height; - this.width = this.realWidth / this.resolution; - this.height = this.realHeight / this.resolution; - - this.isPowerOfTwo = _bitTwiddle2.default.isPow2(this.realWidth) && _bitTwiddle2.default.isPow2(this.realHeight); + this._updateDimensions(); } this.emit('update', this); }; + /** + * Update dimensions from real values + */ + + + BaseTexture.prototype._updateDimensions = function _updateDimensions() { + this.width = this.realWidth / this.resolution; + this.height = this.realHeight / this.resolution; + + this.isPowerOfTwo = _bitTwiddle2.default.isPow2(this.realWidth) && _bitTwiddle2.default.isPow2(this.realHeight); + }; + /** * Load a source. * @@ -22387,7 +24677,7 @@ var BaseTexture = function (_EventEmitter) { imageType = (0, _utils.getUrlFileExtension)(this.imageUrl); if (!imageType) { - throw new Error('Invalid image type in URL.'); + imageType = 'png'; } } @@ -22478,7 +24768,7 @@ var BaseTexture = function (_EventEmitter) { * * @param {string} svgString SVG source as string * - * @fires loaded + * @fires PIXI.BaseTexture#loaded */ @@ -22496,11 +24786,7 @@ var BaseTexture = function (_EventEmitter) { this.realWidth = Math.round(svgWidth * this.sourceScale); this.realHeight = Math.round(svgHeight * this.sourceScale); - this.width = this.realWidth / this.resolution; - this.height = this.realHeight / this.resolution; - - // Check pow2 after scale - this.isPowerOfTwo = _bitTwiddle2.default.isPow2(this.realWidth) && _bitTwiddle2.default.isPow2(this.realHeight); + this._updateDimensions(); // Create a canvas element var canvas = document.createElement('canvas'); @@ -22517,7 +24803,7 @@ var BaseTexture = function (_EventEmitter) { this.source = canvas; // Add also the canvas in cache (destroy clears by `imageUrl` and `source._pixiId`) - _utils.BaseTextureCache[canvas._pixiId] = this; + BaseTexture.addToCache(this, canvas._pixiId); this.isLoading = false; this._sourceLoaded(); @@ -22545,7 +24831,6 @@ var BaseTexture = function (_EventEmitter) { BaseTexture.prototype.destroy = function destroy() { if (this.imageUrl) { - delete _utils.BaseTextureCache[this.imageUrl]; delete _utils.TextureCache[this.imageUrl]; this.imageUrl = null; @@ -22554,14 +24839,15 @@ var BaseTexture = function (_EventEmitter) { this.source.src = ''; } } - // An svg source has both `imageUrl` and `__pixiId`, so no `else if` here - if (this.source && this.source._pixiId) { - delete _utils.BaseTextureCache[this.source._pixiId]; - } this.source = null; this.dispose(); + + BaseTexture.removeFromCache(this); + this.textureCacheIds = null; + + this._destroyed = true; }; /** @@ -22569,14 +24855,12 @@ var BaseTexture = function (_EventEmitter) { * This means you can still use the texture later which will upload it to GPU * memory again. * + * @fires PIXI.BaseTexture#dispose */ BaseTexture.prototype.dispose = function dispose() { this.emit('dispose', this); - - // this should no longer be needed, the renderers should cleanup all the gl textures. - // this._glTextures = {}; }; /** @@ -22600,7 +24884,7 @@ var BaseTexture = function (_EventEmitter) { * @static * @param {string} imageUrl - The image url of the texture * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI. - * @param {number} [scaleMode=PIXI.SCALE_MODES.DEFAULT] - See {@link PIXI.SCALE_MODES} for possible values + * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES} for possible values * @param {number} [sourceScale=(auto)] - Scale for the original image, used with Svg images. * @return {PIXI.BaseTexture} The new base texture. */ @@ -22616,6 +24900,8 @@ var BaseTexture = function (_EventEmitter) { if (crossorigin === undefined && imageUrl.indexOf('data:') !== 0) { image.crossOrigin = (0, _determineCrossOrigin2.default)(imageUrl); + } else if (crossorigin) { + image.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous'; } baseTexture = new BaseTexture(image, scaleMode); @@ -22630,7 +24916,7 @@ var BaseTexture = function (_EventEmitter) { image.src = imageUrl; // Setting this triggers load - _utils.BaseTextureCache[imageUrl] = baseTexture; + BaseTexture.addToCache(baseTexture, imageUrl); } return baseTexture; @@ -22642,31 +24928,138 @@ var BaseTexture = function (_EventEmitter) { * @static * @param {HTMLCanvasElement} canvas - The canvas element source of the texture * @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values + * @param {string} [origin='canvas'] - A string origin of who created the base texture * @return {PIXI.BaseTexture} The new base texture. */ BaseTexture.fromCanvas = function fromCanvas(canvas, scaleMode) { + var origin = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'canvas'; + if (!canvas._pixiId) { - canvas._pixiId = 'canvas_' + (0, _utils.uid)(); + canvas._pixiId = origin + '_' + (0, _utils.uid)(); } var baseTexture = _utils.BaseTextureCache[canvas._pixiId]; if (!baseTexture) { baseTexture = new BaseTexture(canvas, scaleMode); - _utils.BaseTextureCache[canvas._pixiId] = baseTexture; + BaseTexture.addToCache(baseTexture, canvas._pixiId); } return baseTexture; }; + /** + * Helper function that creates a base texture based on the source you provide. + * The source can be - image url, image element, canvas element. + * + * @static + * @param {string|HTMLImageElement|HTMLCanvasElement} source - The source to create base texture from. + * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES} for possible values + * @param {number} [sourceScale=(auto)] - Scale for the original image, used with Svg images. + * @return {PIXI.BaseTexture} The new base texture. + */ + + + BaseTexture.from = function from(source, scaleMode, sourceScale) { + if (typeof source === 'string') { + return BaseTexture.fromImage(source, undefined, scaleMode, sourceScale); + } else if (source instanceof HTMLImageElement) { + var imageUrl = source.src; + var baseTexture = _utils.BaseTextureCache[imageUrl]; + + if (!baseTexture) { + baseTexture = new BaseTexture(source, scaleMode); + baseTexture.imageUrl = imageUrl; + + if (sourceScale) { + baseTexture.sourceScale = sourceScale; + } + + // if there is an @2x at the end of the url we are going to assume its a highres image + baseTexture.resolution = (0, _utils.getResolutionOfUrl)(imageUrl); + + BaseTexture.addToCache(baseTexture, imageUrl); + } + + return baseTexture; + } else if (source instanceof HTMLCanvasElement) { + return BaseTexture.fromCanvas(source, scaleMode); + } + + // lets assume its a base texture! + return source; + }; + + /** + * Adds a BaseTexture to the global BaseTextureCache. This cache is shared across the whole PIXI object. + * + * @static + * @param {PIXI.BaseTexture} baseTexture - The BaseTexture to add to the cache. + * @param {string} id - The id that the BaseTexture will be stored against. + */ + + + BaseTexture.addToCache = function addToCache(baseTexture, id) { + if (id) { + if (baseTexture.textureCacheIds.indexOf(id) === -1) { + baseTexture.textureCacheIds.push(id); + } + + /* eslint-disable no-console */ + if (_utils.BaseTextureCache[id]) { + console.warn('BaseTexture added to the cache with an id [' + id + '] that already had an entry'); + } + /* eslint-enable no-console */ + + _utils.BaseTextureCache[id] = baseTexture; + } + }; + + /** + * Remove a BaseTexture from the global BaseTextureCache. + * + * @static + * @param {string|PIXI.BaseTexture} baseTexture - id of a BaseTexture to be removed, or a BaseTexture instance itself. + * @return {PIXI.BaseTexture|null} The BaseTexture that was removed. + */ + + + BaseTexture.removeFromCache = function removeFromCache(baseTexture) { + if (typeof baseTexture === 'string') { + var baseTextureFromCache = _utils.BaseTextureCache[baseTexture]; + + if (baseTextureFromCache) { + var index = baseTextureFromCache.textureCacheIds.indexOf(baseTexture); + + if (index > -1) { + baseTextureFromCache.textureCacheIds.splice(index, 1); + } + + delete _utils.BaseTextureCache[baseTexture]; + + return baseTextureFromCache; + } + } else if (baseTexture && baseTexture.textureCacheIds) { + for (var i = 0; i < baseTexture.textureCacheIds.length; ++i) { + delete _utils.BaseTextureCache[baseTexture.textureCacheIds[i]]; + } + + baseTexture.textureCacheIds.length = 0; + + return baseTexture; + } + + return null; + }; + return BaseTexture; }(_eventemitter2.default); exports.default = BaseTexture; -},{"../const":42,"../utils":115,"../utils/determineCrossOrigin":114,"bit-twiddle":17,"eventemitter3":19}],107:[function(require,module,exports){ +},{"../settings":101,"../utils":124,"../utils/determineCrossOrigin":123,"bit-twiddle":18,"eventemitter3":20}],113:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -22688,13 +25081,12 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** - * A RenderTexture is a special texture that allows any Pixi display object to be rendered to it. + * A RenderTexture is a special texture that allows any PixiJS display object to be rendered to it. * * __Hint__: All DisplayObjects (i.e. Sprites) that render to a RenderTexture should be preloaded * otherwise black rectangles will be drawn instead. * - * A RenderTexture takes a snapshot of any Display Object given to its render method. The position - * and rotation of the given Display Objects is ignored. For example: + * A RenderTexture takes a snapshot of any Display Object given to its render method. For example: * * ```js * let renderer = PIXI.autoDetectRenderer(1024, 1024, { view: canvas, ratio: 1 }); @@ -22709,15 +25101,16 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" * renderer.render(sprite, renderTexture); * ``` * - * The Sprite in this case will be rendered to a position of 0,0. To render this sprite at its actual - * position a Container should be used: + * The Sprite in this case will be rendered using its local transform. To render this sprite at 0,0 + * you can clear the transform * * ```js - * let doc = new PIXI.Container(); * - * doc.addChild(sprite); + * sprite.setTransform() + * + * let renderTexture = new PIXI.RenderTexture.create(100, 100); * - * renderer.render(doc, renderTexture); // Renders to center of renderTexture + * renderer.render(sprite, renderTexture); // Renders to center of RenderTexture * ``` * * @class @@ -22734,15 +25127,15 @@ var RenderTexture = function (_Texture) { function RenderTexture(baseRenderTexture, frame) { _classCallCheck(this, RenderTexture); - // suport for legacy.. + // support for legacy.. var _legacyRenderer = null; if (!(baseRenderTexture instanceof _BaseRenderTexture2.default)) { /* eslint-disable prefer-rest-params, no-console */ var width = arguments[1]; var height = arguments[2]; - var scaleMode = arguments[3] || 0; - var resolution = arguments[4] || 1; + var scaleMode = arguments[3]; + var resolution = arguments[4]; // we have an old render texture.. console.warn('Please use RenderTexture.create(' + width + ', ' + height + ') instead of the ctor directly.'); @@ -22802,7 +25195,7 @@ var RenderTexture = function (_Texture) { * * @param {number} [width=100] - The width of the render texture * @param {number} [height=100] - The height of the render texture - * @param {number} [scaleMode=PIXI.SCALE_MODES.DEFAULT] - See {@link PIXI.SCALE_MODES} for possible values + * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES} for possible values * @param {number} [resolution=1] - The resolution / device pixel ratio of the texture being generated * @return {PIXI.RenderTexture} The new render texture */ @@ -22817,7 +25210,268 @@ var RenderTexture = function (_Texture) { exports.default = RenderTexture; -},{"./BaseRenderTexture":105,"./Texture":108}],108:[function(require,module,exports){ +},{"./BaseRenderTexture":111,"./Texture":115}],114:[function(require,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _ = require('../'); + +var _utils = require('../utils'); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Utility class for maintaining reference to a collection + * of Textures on a single Spritesheet. + * + * @class + * @memberof PIXI + */ +var Spritesheet = function () { + _createClass(Spritesheet, null, [{ + key: 'BATCH_SIZE', + + /** + * The maximum number of Textures to build per process. + * + * @type {number} + * @default 1000 + */ + get: function get() { + return 1000; + } + + /** + * @param {PIXI.BaseTexture} baseTexture Reference to the source BaseTexture object. + * @param {Object} data - Spritesheet image data. + * @param {string} [resolutionFilename] - The filename to consider when determining + * the resolution of the spritesheet. If not provided, the imageUrl will + * be used on the BaseTexture. + */ + + }]); + + function Spritesheet(baseTexture, data) { + var resolutionFilename = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + + _classCallCheck(this, Spritesheet); + + /** + * Reference to ths source texture + * @type {PIXI.BaseTexture} + */ + this.baseTexture = baseTexture; + + /** + * Map of spritesheet textures. + * @type {Object} + */ + this.textures = {}; + + /** + * Reference to the original JSON data. + * @type {Object} + */ + this.data = data; + + /** + * The resolution of the spritesheet. + * @type {number} + */ + this.resolution = this._updateResolution(resolutionFilename || this.baseTexture.imageUrl); + + /** + * Map of spritesheet frames. + * @type {Object} + * @private + */ + this._frames = this.data.frames; + + /** + * Collection of frame names. + * @type {string[]} + * @private + */ + this._frameKeys = Object.keys(this._frames); + + /** + * Current batch index being processed. + * @type {number} + * @private + */ + this._batchIndex = 0; + + /** + * Callback when parse is completed. + * @type {Function} + * @private + */ + this._callback = null; + } + + /** + * Generate the resolution from the filename or fallback + * to the meta.scale field of the JSON data. + * + * @private + * @param {string} resolutionFilename - The filename to use for resolving + * the default resolution. + * @return {number} Resolution to use for spritesheet. + */ + + + Spritesheet.prototype._updateResolution = function _updateResolution(resolutionFilename) { + var scale = this.data.meta.scale; + + // Use a defaultValue of `null` to check if a url-based resolution is set + var resolution = (0, _utils.getResolutionOfUrl)(resolutionFilename, null); + + // No resolution found via URL + if (resolution === null) { + // Use the scale value or default to 1 + resolution = scale !== undefined ? parseFloat(scale) : 1; + } + + // For non-1 resolutions, update baseTexture + if (resolution !== 1) { + this.baseTexture.resolution = resolution; + this.baseTexture.update(); + } + + return resolution; + }; + + /** + * Parser spritesheet from loaded data. This is done asynchronously + * to prevent creating too many Texture within a single process. + * + * @param {Function} callback - Callback when complete returns + * a map of the Textures for this spritesheet. + */ + + + Spritesheet.prototype.parse = function parse(callback) { + this._batchIndex = 0; + this._callback = callback; + + if (this._frameKeys.length <= Spritesheet.BATCH_SIZE) { + this._processFrames(0); + this._parseComplete(); + } else { + this._nextBatch(); + } + }; + + /** + * Process a batch of frames + * + * @private + * @param {number} initialFrameIndex - The index of frame to start. + */ + + + Spritesheet.prototype._processFrames = function _processFrames(initialFrameIndex) { + var frameIndex = initialFrameIndex; + var maxFrames = Spritesheet.BATCH_SIZE; + + while (frameIndex - initialFrameIndex < maxFrames && frameIndex < this._frameKeys.length) { + var i = this._frameKeys[frameIndex]; + var rect = this._frames[i].frame; + + if (rect) { + var frame = null; + var trim = null; + var orig = new _.Rectangle(0, 0, this._frames[i].sourceSize.w / this.resolution, this._frames[i].sourceSize.h / this.resolution); + + if (this._frames[i].rotated) { + frame = new _.Rectangle(rect.x / this.resolution, rect.y / this.resolution, rect.h / this.resolution, rect.w / this.resolution); + } else { + frame = new _.Rectangle(rect.x / this.resolution, rect.y / this.resolution, rect.w / this.resolution, rect.h / this.resolution); + } + + // Check to see if the sprite is trimmed + if (this._frames[i].trimmed) { + trim = new _.Rectangle(this._frames[i].spriteSourceSize.x / this.resolution, this._frames[i].spriteSourceSize.y / this.resolution, rect.w / this.resolution, rect.h / this.resolution); + } + + this.textures[i] = new _.Texture(this.baseTexture, frame, orig, trim, this._frames[i].rotated ? 2 : 0); + + // lets also add the frame to pixi's global cache for fromFrame and fromImage functions + _.Texture.addToCache(this.textures[i], i); + } + + frameIndex++; + } + }; + + /** + * The parse has completed. + * + * @private + */ + + + Spritesheet.prototype._parseComplete = function _parseComplete() { + var callback = this._callback; + + this._callback = null; + this._batchIndex = 0; + callback.call(this, this.textures); + }; + + /** + * Begin the next batch of textures. + * + * @private + */ + + + Spritesheet.prototype._nextBatch = function _nextBatch() { + var _this = this; + + this._processFrames(this._batchIndex * Spritesheet.BATCH_SIZE); + this._batchIndex++; + setTimeout(function () { + if (_this._batchIndex * Spritesheet.BATCH_SIZE < _this._frameKeys.length) { + _this._nextBatch(); + } else { + _this._parseComplete(); + } + }, 0); + }; + + /** + * Destroy Spritesheet and don't use after this. + * + * @param {boolean} [destroyBase=false] Whether to destroy the base texture as well + */ + + + Spritesheet.prototype.destroy = function destroy() { + var destroyBase = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + for (var i in this.textures) { + this.textures[i].destroy(); + } + this._frames = null; + this._frameKeys = null; + this.data = null; + this.textures = null; + if (destroyBase) { + this.baseTexture.destroy(); + } + this.baseTexture = null; + }; + + return Spritesheet; +}(); + +exports.default = Spritesheet; + +},{"../":65,"../utils":124}],115:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -22844,6 +25498,10 @@ var _math = require('../math'); var _utils = require('../utils'); +var _settings = require('../settings'); + +var _settings2 = _interopRequireDefault(_settings); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -22865,7 +25523,8 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" * let sprite2 = new PIXI.Sprite(texture); * ``` * - * Textures made from SVGs, loaded or not, cannot be used before the file finishes processing. You can check for this by checking the sprite's _textureID property. + * Textures made from SVGs, loaded or not, cannot be used before the file finishes processing. + * You can check for this by checking the sprite's _textureID property. * ```js * var texture = PIXI.Texture.fromImage('assets/image.svg'); * var sprite1 = new PIXI.Sprite(texture); @@ -22983,9 +25642,9 @@ var Texture = function (_EventEmitter) { /** * Fired when the texture is updated. This happens if the frame or the baseTexture is updated. * - * @event update - * @memberof PIXI.Texture# + * @event PIXI.Texture#update * @protected + * @param {PIXI.Texture} texture - Instance of texture being updated. */ _this._updateID = 0; @@ -22995,6 +25654,15 @@ var Texture = function (_EventEmitter) { * @type {Object} */ _this.transform = null; + + /** + * The ids under which this Texture has been added to the texture cache. This is + * automatically set as long as Texture.addToCache is used, but may not be set if a + * Texture is added directly to the TextureCache array. + * + * @member {string[]} + */ + _this.textureCacheIds = []; return _this; } @@ -23019,7 +25687,7 @@ var Texture = function (_EventEmitter) { Texture.prototype.onBaseTextureLoaded = function onBaseTextureLoaded(baseTexture) { this._updateID++; - // TODO this code looks confusing.. boo to abusing getters and setterss! + // TODO this code looks confusing.. boo to abusing getters and setters! if (this.noFrame) { this.frame = new _math.Rectangle(0, 0, baseTexture.width, baseTexture.height); } else { @@ -23058,9 +25726,9 @@ var Texture = function (_EventEmitter) { if (this.baseTexture) { if (destroyBase) { // delete the texture if it exists in the texture cache.. - // this only needs to be removed if the base texture is actually destoryed too.. + // this only needs to be removed if the base texture is actually destroyed too.. if (_utils.TextureCache[this.baseTexture.imageUrl]) { - delete _utils.TextureCache[this.baseTexture.imageUrl]; + Texture.removeFromCache(this.baseTexture.imageUrl); } this.baseTexture.destroy(); @@ -23079,8 +25747,8 @@ var Texture = function (_EventEmitter) { this.valid = false; - this.off('dispose', this.dispose, this); - this.off('update', this.update, this); + Texture.removeFromCache(this); + this.textureCacheIds = null; }; /** @@ -23118,7 +25786,7 @@ var Texture = function (_EventEmitter) { * @static * @param {string} imageUrl - The image url of the texture * @param {boolean} [crossorigin] - Whether requests should be treated as crossorigin - * @param {number} [scaleMode=PIXI.SCALE_MODES.DEFAULT] - See {@link PIXI.SCALE_MODES} for possible values + * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES} for possible values * @param {number} [sourceScale=(auto)] - Scale for the original image, used with SVG images. * @return {PIXI.Texture} The newly created texture */ @@ -23129,7 +25797,7 @@ var Texture = function (_EventEmitter) { if (!texture) { texture = new Texture(_BaseTexture2.default.fromImage(imageUrl, crossorigin, scaleMode, sourceScale)); - _utils.TextureCache[imageUrl] = texture; + Texture.addToCache(texture, imageUrl); } return texture; @@ -23160,13 +25828,16 @@ var Texture = function (_EventEmitter) { * * @static * @param {HTMLCanvasElement} canvas - The canvas element source of the texture - * @param {number} [scaleMode=PIXI.SCALE_MODES.DEFAULT] - See {@link PIXI.SCALE_MODES} for possible values + * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES} for possible values + * @param {string} [origin='canvas'] - A string origin of who created the base texture * @return {PIXI.Texture} The newly created texture */ Texture.fromCanvas = function fromCanvas(canvas, scaleMode) { - return new Texture(_BaseTexture2.default.fromCanvas(canvas, scaleMode)); + var origin = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'canvas'; + + return new Texture(_BaseTexture2.default.fromCanvas(canvas, scaleMode, origin)); }; /** @@ -23174,7 +25845,7 @@ var Texture = function (_EventEmitter) { * * @static * @param {HTMLVideoElement|string} video - The URL or actual element of the video - * @param {number} [scaleMode=PIXI.SCALE_MODES.DEFAULT] - See {@link PIXI.SCALE_MODES} for possible values + * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES} for possible values * @return {PIXI.Texture} The newly created texture */ @@ -23192,7 +25863,7 @@ var Texture = function (_EventEmitter) { * * @static * @param {string} videoUrl - URL of the video - * @param {number} [scaleMode=PIXI.SCALE_MODES.DEFAULT] - See {@link PIXI.SCALE_MODES} for possible values + * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES} for possible values * @return {PIXI.Texture} The newly created texture */ @@ -23203,10 +25874,11 @@ var Texture = function (_EventEmitter) { /** * Helper function that creates a new Texture based on the source you provide. - * The soucre can be - frame id, image url, video url, canvae element, video element, base texture + * The source can be - frame id, image url, video url, canvas element, video element, base texture * * @static - * @param {number|string|PIXI.BaseTexture|HTMLCanvasElement|HTMLVideoElement} source - Source to create texture from + * @param {number|string|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement|PIXI.BaseTexture} + * source - Source to create texture from * @return {PIXI.Texture} The newly created texture */ @@ -23229,12 +25901,14 @@ var Texture = function (_EventEmitter) { } return texture; + } else if (source instanceof HTMLImageElement) { + return new Texture(_BaseTexture2.default.from(source)); } else if (source instanceof HTMLCanvasElement) { - return Texture.fromCanvas(source); + return Texture.fromCanvas(source, _settings2.default.SCALE_MODE, 'HTMLCanvasElement'); } else if (source instanceof HTMLVideoElement) { return Texture.fromVideo(source); } else if (source instanceof _BaseTexture2.default) { - return new Texture(_BaseTexture2.default); + return new Texture(source); } // lets assume its a texture! @@ -23242,41 +25916,110 @@ var Texture = function (_EventEmitter) { }; /** - * Adds a texture to the global TextureCache. This cache is shared across the whole PIXI object. + * Create a texture from a source and add to the cache. + * + * @static + * @param {HTMLImageElement|HTMLCanvasElement} source - The input source. + * @param {String} imageUrl - File name of texture, for cache and resolving resolution. + * @param {String} [name] - Human readible name for the texture cache. If no name is + * specified, only `imageUrl` will be used as the cache ID. + * @return {PIXI.Texture} Output texture + */ + + + Texture.fromLoader = function fromLoader(source, imageUrl, name) { + var baseTexture = new _BaseTexture2.default(source, undefined, (0, _utils.getResolutionOfUrl)(imageUrl)); + var texture = new Texture(baseTexture); + + baseTexture.imageUrl = imageUrl; + + // No name, use imageUrl instead + if (!name) { + name = imageUrl; + } + + // lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions + _BaseTexture2.default.addToCache(texture.baseTexture, name); + Texture.addToCache(texture, name); + + // also add references by url if they are different. + if (name !== imageUrl) { + _BaseTexture2.default.addToCache(texture.baseTexture, imageUrl); + Texture.addToCache(texture, imageUrl); + } + + return texture; + }; + + /** + * Adds a Texture to the global TextureCache. This cache is shared across the whole PIXI object. * * @static * @param {PIXI.Texture} texture - The Texture to add to the cache. - * @param {string} id - The id that the texture will be stored against. + * @param {string} id - The id that the Texture will be stored against. */ - Texture.addTextureToCache = function addTextureToCache(texture, id) { - _utils.TextureCache[id] = texture; + Texture.addToCache = function addToCache(texture, id) { + if (id) { + if (texture.textureCacheIds.indexOf(id) === -1) { + texture.textureCacheIds.push(id); + } + + /* eslint-disable no-console */ + if (_utils.TextureCache[id]) { + console.warn('Texture added to the cache with an id [' + id + '] that already had an entry'); + } + /* eslint-enable no-console */ + + _utils.TextureCache[id] = texture; + } }; /** - * Remove a texture from the global TextureCache. + * Remove a Texture from the global TextureCache. * * @static - * @param {string} id - The id of the texture to be removed - * @return {PIXI.Texture} The texture that was removed + * @param {string|PIXI.Texture} texture - id of a Texture to be removed, or a Texture instance itself + * @return {PIXI.Texture|null} The Texture that was removed */ - Texture.removeTextureFromCache = function removeTextureFromCache(id) { - var texture = _utils.TextureCache[id]; + Texture.removeFromCache = function removeFromCache(texture) { + if (typeof texture === 'string') { + var textureFromCache = _utils.TextureCache[texture]; - delete _utils.TextureCache[id]; - delete _utils.BaseTextureCache[id]; + if (textureFromCache) { + var index = textureFromCache.textureCacheIds.indexOf(texture); - return texture; + if (index > -1) { + textureFromCache.textureCacheIds.splice(index, 1); + } + + delete _utils.TextureCache[texture]; + + return textureFromCache; + } + } else if (texture && texture.textureCacheIds) { + for (var i = 0; i < texture.textureCacheIds.length; ++i) { + // Check that texture matches the one being passed in before deleting it from the cache. + if (_utils.TextureCache[texture.textureCacheIds[i]] === texture) { + delete _utils.TextureCache[texture.textureCacheIds[i]]; + } + } + + texture.textureCacheIds.length = 0; + + return texture; + } + + return null; }; /** * The frame specifies the region of the base texture that this texture uses. * * @member {PIXI.Rectangle} - * @memberof PIXI.Texture# */ @@ -23284,21 +26027,15 @@ var Texture = function (_EventEmitter) { key: 'frame', get: function get() { return this._frame; - } - - /** - * Set the frame. - * - * @param {Rectangle} frame - The new frame to set. - */ - , - set: function set(frame) { + }, + set: function set(frame) // eslint-disable-line require-jsdoc + { this._frame = frame; this.noFrame = false; if (frame.x + frame.width > this.baseTexture.width || frame.y + frame.height > this.baseTexture.height) { - throw new Error('Texture Error: frame does not fit inside the base Texture dimensions ' + this); + throw new Error('Texture Error: frame does not fit inside the base Texture dimensions: ' + ('X: ' + frame.x + ' + ' + frame.width + ' = ' + (frame.x + frame.width) + ' > ' + this.baseTexture.width + ' ') + ('Y: ' + frame.y + ' + ' + frame.height + ' = ' + (frame.y + frame.height) + ' > ' + this.baseTexture.height)); } // this.valid = frame && frame.width && frame.height && this.baseTexture.source && this.baseTexture.hasLoaded; @@ -23327,15 +26064,9 @@ var Texture = function (_EventEmitter) { key: 'rotate', get: function get() { return this._rotate; - } - - /** - * Set the rotation - * - * @param {number} rotate - The new rotation to set. - */ - , - set: function set(rotate) { + }, + set: function set(rotate) // eslint-disable-line require-jsdoc + { this._rotate = rotate; if (this.valid) { this._updateUvs(); @@ -23351,7 +26082,7 @@ var Texture = function (_EventEmitter) { }, { key: 'width', get: function get() { - return this.orig ? this.orig.width : 0; + return this.orig.width; } /** @@ -23363,13 +26094,37 @@ var Texture = function (_EventEmitter) { }, { key: 'height', get: function get() { - return this.orig ? this.orig.height : 0; + return this.orig.height; } }]); return Texture; }(_eventemitter2.default); +exports.default = Texture; + + +function createWhiteTexture() { + var canvas = document.createElement('canvas'); + + canvas.width = 10; + canvas.height = 10; + + var context = canvas.getContext('2d'); + + context.fillStyle = 'white'; + context.fillRect(0, 0, 10, 10); + + return new Texture(new _BaseTexture2.default(canvas)); +} + +function removeAllHandlers(tex) { + tex.destroy = function _emptyDestroy() {/* empty */}; + tex.on = function _emptyOn() {/* empty */}; + tex.once = function _emptyOnce() {/* empty */}; + tex.emit = function _emptyEmit() {/* empty */}; +} + /** * An empty texture, used often to not have to create multiple empty textures. * Can not be destroyed. @@ -23377,16 +26132,22 @@ var Texture = function (_EventEmitter) { * @static * @constant */ - - -exports.default = Texture; Texture.EMPTY = new Texture(new _BaseTexture2.default()); -Texture.EMPTY.destroy = function _emptyDestroy() {/* empty */}; -Texture.EMPTY.on = function _emptyOn() {/* empty */}; -Texture.EMPTY.once = function _emptyOnce() {/* empty */}; -Texture.EMPTY.emit = function _emptyEmit() {/* empty */}; +removeAllHandlers(Texture.EMPTY); +removeAllHandlers(Texture.EMPTY.baseTexture); + +/** + * A white texture of 10x10 size, used for graphics and other things + * Can not be destroyed. + * + * @static + * @constant + */ +Texture.WHITE = createWhiteTexture(); +removeAllHandlers(Texture.WHITE); +removeAllHandlers(Texture.WHITE.baseTexture); -},{"../math":66,"../utils":115,"./BaseTexture":106,"./TextureUvs":109,"./VideoBaseTexture":110,"eventemitter3":19}],109:[function(require,module,exports){ +},{"../math":70,"../settings":101,"../utils":124,"./BaseTexture":112,"./TextureUvs":116,"./VideoBaseTexture":117,"eventemitter3":20}],116:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -23491,7 +26252,7 @@ var TextureUvs = function () { exports.default = TextureUvs; -},{"../math/GroupD8":62}],110:[function(require,module,exports){ +},{"../math/GroupD8":66}],117:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -23506,9 +26267,7 @@ var _utils = require('../utils'); var _ticker = require('../ticker'); -var ticker = _interopRequireWildcard(_ticker); - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } +var _const = require('../const'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -23521,7 +26280,7 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" /** * A texture of a [playing] Video. * - * Video base textures mimic Pixi BaseTexture.from.... method in their creation process. + * Video base textures mimic PixiJS BaseTexture.from.... method in their creation process. * * This can be used in several ways, such as: * @@ -23549,7 +26308,7 @@ var VideoBaseTexture = function (_BaseTexture) { /** * @param {HTMLVideoElement} source - Video source - * @param {number} [scaleMode=PIXI.SCALE_MODES.DEFAULT] - See {@link PIXI.SCALE_MODES} for possible values + * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES} for possible values */ function VideoBaseTexture(source, scaleMode) { _classCallCheck(this, VideoBaseTexture); @@ -23633,13 +26392,13 @@ var VideoBaseTexture = function (_BaseTexture) { VideoBaseTexture.prototype._onPlayStart = function _onPlayStart() { - // Just in case the video has not recieved its can play even yet.. + // Just in case the video has not received its can play even yet.. if (!this.hasLoaded) { this._onCanPlay(); } if (!this._isAutoUpdating && this.autoUpdate) { - ticker.shared.add(this.update, this); + _ticker.shared.add(this.update, this, _const.UPDATE_PRIORITY.HIGH); this._isAutoUpdating = true; } }; @@ -23653,7 +26412,7 @@ var VideoBaseTexture = function (_BaseTexture) { VideoBaseTexture.prototype._onPlayStop = function _onPlayStop() { if (this._isAutoUpdating) { - ticker.shared.remove(this.update, this); + _ticker.shared.remove(this.update, this); this._isAutoUpdating = false; } }; @@ -23697,11 +26456,11 @@ var VideoBaseTexture = function (_BaseTexture) { VideoBaseTexture.prototype.destroy = function destroy() { if (this._isAutoUpdating) { - ticker.shared.remove(this.update, this); + _ticker.shared.remove(this.update, this); } if (this.source && this.source._pixiId) { - delete _utils.BaseTextureCache[this.source._pixiId]; + _BaseTexture3.default.removeFromCache(this.source._pixiId); delete this.source._pixiId; } @@ -23709,11 +26468,11 @@ var VideoBaseTexture = function (_BaseTexture) { }; /** - * Mimic Pixi BaseTexture.from.... method. + * Mimic PixiJS BaseTexture.from.... method. * * @static * @param {HTMLVideoElement} video - Video to create texture from - * @param {number} [scaleMode=PIXI.SCALE_MODES.DEFAULT] - See {@link PIXI.SCALE_MODES} for possible values + * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES} for possible values * @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture */ @@ -23727,7 +26486,7 @@ var VideoBaseTexture = function (_BaseTexture) { if (!baseTexture) { baseTexture = new VideoBaseTexture(video, scaleMode); - _utils.BaseTextureCache[video._pixiId] = baseTexture; + _BaseTexture3.default.addToCache(baseTexture, video._pixiId); } return baseTexture; @@ -23773,7 +26532,6 @@ var VideoBaseTexture = function (_BaseTexture) { * Should the base texture automatically update itself, set to true by default * * @member {boolean} - * @memberof PIXI.VideoBaseTexture# */ @@ -23781,23 +26539,17 @@ var VideoBaseTexture = function (_BaseTexture) { key: 'autoUpdate', get: function get() { return this._autoUpdate; - } - - /** - * Sets autoUpdate property. - * - * @param {number} value - enable auto update or not - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { if (value !== this._autoUpdate) { this._autoUpdate = value; if (!this._autoUpdate && this._isAutoUpdating) { - ticker.shared.remove(this.update, this); + _ticker.shared.remove(this.update, this); this._isAutoUpdating = false; } else if (this._autoUpdate && !this._isAutoUpdating) { - ticker.shared.add(this.update, this); + _ticker.shared.add(this.update, this, _const.UPDATE_PRIORITY.HIGH); this._isAutoUpdating = true; } } @@ -23825,29 +26577,30 @@ function createSource(path, type) { return source; } -},{"../ticker":112,"../utils":115,"./BaseTexture":106}],111:[function(require,module,exports){ +},{"../const":46,"../ticker":120,"../utils":124,"./BaseTexture":112}],118:[function(require,module,exports){ 'use strict'; exports.__esModule = true; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); +var _settings = require('../settings'); + +var _settings2 = _interopRequireDefault(_settings); + var _const = require('../const'); -var _eventemitter = require('eventemitter3'); +var _TickerListener = require('./TickerListener'); -var _eventemitter2 = _interopRequireDefault(_eventemitter); +var _TickerListener2 = _interopRequireDefault(_TickerListener); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -// Internal event used by composed emitter -var TICK = 'tick'; - /** * A Ticker class that runs an update loop that other objects listen to. - * This class is composed around an EventEmitter object to add listeners + * This class is composed around listeners * meant for execution on the next requested animation frame. * Animation frames are requested only when necessary, * e.g. When the ticker is started and the emitter has listeners. @@ -23855,7 +26608,6 @@ var TICK = 'tick'; * @class * @memberof PIXI.ticker */ - var Ticker = function () { /** * @@ -23866,10 +26618,11 @@ var Ticker = function () { _classCallCheck(this, Ticker); /** - * Internal emitter used to fire 'tick' event + * The first listener. All new listeners added are chained on this. * @private + * @type {TickerListener} */ - this._emitter = new _eventemitter2.default(); + this._head = new _TickerListener2.default(null, null, Infinity); /** * Internal current frame request ID @@ -23911,11 +26664,12 @@ var Ticker = function () { * is based, this value is neither capped nor scaled. * If the platform supports DOMHighResTimeStamp, * this value will have a precision of 1 µs. + * Defaults to target frame time * * @member {number} - * @default 1 / TARGET_FPMS + * @default 16.66 */ - this.elapsedMS = 1 / _const.TARGET_FPMS; // default to target frame time + this.elapsedMS = 1 / _settings2.default.TARGET_FPMS; /** * The last time {@link PIXI.ticker.Ticker#update} was invoked. @@ -23925,9 +26679,9 @@ var Ticker = function () { * this value will have a precision of 1 µs. * * @member {number} - * @default 0 + * @default -1 */ - this.lastTime = 0; + this.lastTime = -1; /** * Factor of current {@link PIXI.ticker.Ticker#deltaTime}. @@ -23972,7 +26726,7 @@ var Ticker = function () { // Invoke listeners now _this.update(time); // Listener side effects may have modified ticker state. - if (_this.started && _this._requestId === null && _this._emitter.listeners(TICK, true)) { + if (_this.started && _this._requestId === null && _this._head.next) { _this._requestId = requestAnimationFrame(_this._tick); } } @@ -23989,7 +26743,7 @@ var Ticker = function () { Ticker.prototype._requestIfNeeded = function _requestIfNeeded() { - if (this._requestId === null && this._emitter.listeners(TICK, true)) { + if (this._requestId === null && this._head.next) { // ensure callbacks get correct delta this.lastTime = performance.now(); this._requestId = requestAnimationFrame(this._tick); @@ -24031,37 +26785,73 @@ var Ticker = function () { }; /** - * Calls {@link module:eventemitter3.EventEmitter#on} internally for the - * internal 'tick' event. It checks if the emitter has listeners, - * and if so it requests a new animation frame at this point. + * Register a handler for tick events. Calls continuously unless + * it is removed or the ticker is stopped. * * @param {Function} fn - The listener function to be added for updates * @param {Function} [context] - The listener context + * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting * @returns {PIXI.ticker.Ticker} This instance of a ticker */ Ticker.prototype.add = function add(fn, context) { - this._emitter.on(TICK, fn, context); + var priority = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _const.UPDATE_PRIORITY.NORMAL; - this._startIfPossible(); - - return this; + return this._addListener(new _TickerListener2.default(fn, context, priority)); }; /** - * Calls {@link module:eventemitter3.EventEmitter#once} internally for the - * internal 'tick' event. It checks if the emitter has listeners, - * and if so it requests a new animation frame at this point. + * Add a handler for the tick event which is only execute once. * * @param {Function} fn - The listener function to be added for one update * @param {Function} [context] - The listener context + * @param {number} [priority=PIXI.UPDATE_PRIORITY.NORMAL] - The priority for emitting * @returns {PIXI.ticker.Ticker} This instance of a ticker */ Ticker.prototype.addOnce = function addOnce(fn, context) { - this._emitter.once(TICK, fn, context); + var priority = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _const.UPDATE_PRIORITY.NORMAL; + + return this._addListener(new _TickerListener2.default(fn, context, priority, true)); + }; + + /** + * Internally adds the event handler so that it can be sorted by priority. + * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run + * before the rendering. + * + * @private + * @param {TickerListener} listener - Current listener being added. + * @returns {PIXI.ticker.Ticker} This instance of a ticker + */ + + + Ticker.prototype._addListener = function _addListener(listener) { + // For attaching to head + var current = this._head.next; + var previous = this._head; + + // Add the first item + if (!current) { + listener.connect(previous); + } else { + // Go from highest to lowest priority + while (current) { + if (listener.priority > current.priority) { + listener.connect(previous); + break; + } + previous = current; + current = current.next; + } + + // Not yet connected + if (!listener.previous) { + listener.connect(previous); + } + } this._startIfPossible(); @@ -24069,20 +26859,30 @@ var Ticker = function () { }; /** - * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event. - * It checks if the emitter has listeners for 'tick' event. - * If it does, then it cancels the animation frame. + * Removes any handlers matching the function and context parameters. + * If no handlers are left after removing, then it cancels the animation frame. * - * @param {Function} [fn] - The listener function to be removed + * @param {Function} fn - The listener function to be removed * @param {Function} [context] - The listener context to be removed * @returns {PIXI.ticker.Ticker} This instance of a ticker */ Ticker.prototype.remove = function remove(fn, context) { - this._emitter.off(TICK, fn, context); + var listener = this._head.next; + + while (listener) { + // We found a match, lets remove it + // no break to delete all possible matches + // incase a listener was added 2+ times + if (listener.match(fn, context)) { + listener = listener.destroy(); + } else { + listener = listener.next; + } + } - if (!this._emitter.listeners(TICK, true)) { + if (!this._head.next) { this._cancelIfNeeded(); } @@ -24115,6 +26915,25 @@ var Ticker = function () { } }; + /** + * Destroy the ticker and don't use after this. Calling + * this method removes all references to internal events. + */ + + + Ticker.prototype.destroy = function destroy() { + this.stop(); + + var listener = this._head.next; + + while (listener) { + listener = listener.destroy(true); + } + + this._head.destroy(); + this._head = null; + }; + /** * Triggers an update. An update entails setting the * current {@link PIXI.ticker.Ticker#elapsedMS}, @@ -24159,10 +26978,22 @@ var Ticker = function () { elapsedMS = this._maxElapsedMS; } - this.deltaTime = elapsedMS * _const.TARGET_FPMS * this.speed; + this.deltaTime = elapsedMS * _settings2.default.TARGET_FPMS * this.speed; + + // Cache a local reference, in-case ticker is destroyed + // during the emit, we can still check for head.next + var head = this._head; // Invoke listeners added to internal emitter - this._emitter.emit(TICK, this.deltaTime); + var listener = head.next; + + while (listener) { + listener = listener.emit(this.deltaTime); + } + + if (!head.next) { + this._cancelIfNeeded(); + } } else { this.deltaTime = this.elapsedMS = 0; } @@ -24177,7 +27008,7 @@ var Ticker = function () { * {@link PIXI.ticker.Ticker#speed}, which is specific * to scaling {@link PIXI.ticker.Ticker#deltaTime}. * - * @memberof PIXI.ticker.Ticker# + * @member {number} * @readonly */ @@ -24194,9 +27025,9 @@ var Ticker = function () { * This value is used to cap {@link PIXI.ticker.Ticker#deltaTime}, * but does not effect the measured value of {@link PIXI.ticker.Ticker#FPS}. * When setting this property it is clamped to a value between - * `0` and `PIXI.TARGET_FPMS * 1000`. + * `0` and `PIXI.settings.TARGET_FPMS * 1000`. * - * @memberof PIXI.ticker.Ticker# + * @member {number} * @default 10 */ @@ -24204,17 +27035,11 @@ var Ticker = function () { key: 'minFPS', get: function get() { return 1000 / this._maxElapsedMS; - } - - /** - * Sets the min fps. - * - * @param {number} fps - value to set. - */ - , - set: function set(fps) { + }, + set: function set(fps) // eslint-disable-line require-jsdoc + { // Clamp: 0 to TARGET_FPMS - var minFPMS = Math.min(Math.max(0, fps) / 1000, _const.TARGET_FPMS); + var minFPMS = Math.min(Math.max(0, fps) / 1000, _settings2.default.TARGET_FPMS); this._maxElapsedMS = 1 / minFPMS; } @@ -24225,7 +27050,181 @@ var Ticker = function () { exports.default = Ticker; -},{"../const":42,"eventemitter3":19}],112:[function(require,module,exports){ +},{"../const":46,"../settings":101,"./TickerListener":119}],119:[function(require,module,exports){ +"use strict"; + +exports.__esModule = true; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Internal class for handling the priority sorting of ticker handlers. + * + * @private + * @class + * @memberof PIXI.ticker + */ +var TickerListener = function () { + /** + * Constructor + * + * @param {Function} fn - The listener function to be added for one update + * @param {Function} [context=null] - The listener context + * @param {number} [priority=0] - The priority for emitting + * @param {boolean} [once=false] - If the handler should fire once + */ + function TickerListener(fn) { + var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + var priority = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; + var once = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + + _classCallCheck(this, TickerListener); + + /** + * The handler function to execute. + * @member {Function} + */ + this.fn = fn; + + /** + * The calling to execute. + * @member {Function} + */ + this.context = context; + + /** + * The current priority. + * @member {number} + */ + this.priority = priority; + + /** + * If this should only execute once. + * @member {boolean} + */ + this.once = once; + + /** + * The next item in chain. + * @member {TickerListener} + */ + this.next = null; + + /** + * The previous item in chain. + * @member {TickerListener} + */ + this.previous = null; + + /** + * `true` if this listener has been destroyed already. + * @member {boolean} + * @private + */ + this._destroyed = false; + } + + /** + * Simple compare function to figure out if a function and context match. + * + * @param {Function} fn - The listener function to be added for one update + * @param {Function} context - The listener context + * @return {boolean} `true` if the listener match the arguments + */ + + + TickerListener.prototype.match = function match(fn, context) { + context = context || null; + + return this.fn === fn && this.context === context; + }; + + /** + * Emit by calling the current function. + * @param {number} deltaTime - time since the last emit. + * @return {TickerListener} Next ticker + */ + + + TickerListener.prototype.emit = function emit(deltaTime) { + if (this.fn) { + if (this.context) { + this.fn.call(this.context, deltaTime); + } else { + this.fn(deltaTime); + } + } + + var redirect = this.next; + + if (this.once) { + this.destroy(true); + } + + // Soft-destroying should remove + // the next reference + if (this._destroyed) { + this.next = null; + } + + return redirect; + }; + + /** + * Connect to the list. + * @param {TickerListener} previous - Input node, previous listener + */ + + + TickerListener.prototype.connect = function connect(previous) { + this.previous = previous; + if (previous.next) { + previous.next.previous = this; + } + this.next = previous.next; + previous.next = this; + }; + + /** + * Destroy and don't use after this. + * @param {boolean} [hard = false] `true` to remove the `next` reference, this + * is considered a hard destroy. Soft destroy maintains the next reference. + * @return {TickerListener} The listener to redirect while emitting or removing. + */ + + + TickerListener.prototype.destroy = function destroy() { + var hard = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + this._destroyed = true; + this.fn = null; + this.context = null; + + // Disconnect, hook up next and previous + if (this.previous) { + this.previous.next = this.next; + } + + if (this.next) { + this.next.previous = this.previous; + } + + // Redirect to the next item + var redirect = this.previous; + + // Remove references + this.next = hard ? null : redirect; + this.previous = null; + + return redirect; + }; + + return TickerListener; +}(); + +exports.default = TickerListener; + +},{}],120:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -24238,7 +27237,7 @@ var _Ticker2 = _interopRequireDefault(_Ticker); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** - * The shared ticker instance used by {@link PIXI.extras.MovieClip}. + * The shared ticker instance used by {@link PIXI.extras.AnimatedSprite}. * and by {@link PIXI.interaction.InteractionManager}. * The property {@link PIXI.ticker.Ticker#autoStart} is set to `true` * for this instance. Please follow the examples for usage, including @@ -24282,14 +27281,44 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de var shared = new _Ticker2.default(); shared.autoStart = true; +shared.destroy = function () { + // protect destroying shared ticker + // this is used by other internal systems + // like AnimatedSprite and InteractionManager +}; /** + * This namespace contains an API for interacting with PIXI's internal global update loop. + * + * This ticker is used for rendering, {@link PIXI.extras.AnimatedSprite AnimatedSprite}, + * {@link PIXI.interaction.InteractionManager InteractionManager} and many other time-based PIXI systems. + * @example + * const ticker = new PIXI.ticker.Ticker(); + * ticker.stop(); + * ticker.add((deltaTime) => { + * // do something every frame + * }); + * ticker.start(); * @namespace PIXI.ticker */ exports.shared = shared; exports.Ticker = _Ticker2.default; -},{"./Ticker":111}],113:[function(require,module,exports){ +},{"./Ticker":118}],121:[function(require,module,exports){ +"use strict"; + +exports.__esModule = true; +exports.default = canUploadSameBuffer; +function canUploadSameBuffer() { + // Uploading the same buffer multiple times in a single frame can cause perf issues. + // Apparent on IOS so only check for that at the moment + // this check may become more complex if this issue pops up elsewhere. + var ios = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform); + + return !ios; +} + +},{}],122:[function(require,module,exports){ "use strict"; exports.__esModule = true; @@ -24297,8 +27326,9 @@ exports.default = createIndicesForQuads; /** * Generic Mask Stack data structure * - * @class * @memberof PIXI + * @function createIndicesForQuads + * @private * @param {number} size - Number of quads * @return {Uint16Array} indices */ @@ -24322,7 +27352,7 @@ function createIndicesForQuads(size) { return indices; } -},{}],114:[function(require,module,exports){ +},{}],123:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -24378,11 +27408,11 @@ function determineCrossOrigin(url) { return ''; } -},{"url":29}],115:[function(require,module,exports){ +},{"url":38}],124:[function(require,module,exports){ 'use strict'; exports.__esModule = true; -exports.BaseTextureCache = exports.TextureCache = exports.pluginTarget = exports.EventEmitter = undefined; +exports.premultiplyBlendMode = exports.BaseTextureCache = exports.TextureCache = exports.mixins = exports.pluginTarget = exports.EventEmitter = exports.removeItems = exports.isMobile = undefined; exports.uid = uid; exports.hex2rgb = hex2rgb; exports.hex2string = hex2string; @@ -24395,10 +27425,19 @@ exports.skipHello = skipHello; exports.sayHello = sayHello; exports.isWebGLSupported = isWebGLSupported; exports.sign = sign; -exports.removeItems = removeItems; +exports.destroyTextureCache = destroyTextureCache; +exports.clearTextureCache = clearTextureCache; +exports.correctBlendMode = correctBlendMode; +exports.premultiplyTint = premultiplyTint; +exports.premultiplyRgba = premultiplyRgba; +exports.premultiplyTintToRgba = premultiplyTintToRgba; var _const = require('../const'); +var _settings = require('../settings'); + +var _settings2 = _interopRequireDefault(_settings); + var _eventemitter = require('eventemitter3'); var _eventemitter2 = _interopRequireDefault(_eventemitter); @@ -24407,21 +27446,58 @@ var _pluginTarget = require('./pluginTarget'); var _pluginTarget2 = _interopRequireDefault(_pluginTarget); +var _mixin = require('./mixin'); + +var mixins = _interopRequireWildcard(_mixin); + +var _ismobilejs = require('ismobilejs'); + +var isMobile = _interopRequireWildcard(_ismobilejs); + +var _removeArrayItems = require('remove-array-items'); + +var _removeArrayItems2 = _interopRequireDefault(_removeArrayItems); + +var _mapPremultipliedBlendModes = require('./mapPremultipliedBlendModes'); + +var _mapPremultipliedBlendModes2 = _interopRequireDefault(_mapPremultipliedBlendModes); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var nextUid = 0; var saidHello = false; /** + * Generalized convenience utilities for PIXI. + * @example + * // Extend PIXI's internal Event Emitter. + * class MyEmitter extends PIXI.utils.EventEmitter { + * constructor() { + * super(); + * console.log("Emitter created!"); + * } + * } + * + * // Get info on current device + * console.log(PIXI.utils.isMobile); + * + * // Convert hex color to string + * console.log(PIXI.utils.hex2string(0xff00ff)); // returns: "#ff00ff" * @namespace PIXI.utils */ +exports.isMobile = isMobile; +exports.removeItems = _removeArrayItems2.default; exports.EventEmitter = _eventemitter2.default; exports.pluginTarget = _pluginTarget2.default; +exports.mixins = mixins; /** * Gets the next unique identifier * * @memberof PIXI.utils + * @function uid * @return {number} The next unique identifier to use. */ @@ -24433,6 +27509,7 @@ function uid() { * Converts a hex color number to an [R, G, B] array * * @memberof PIXI.utils + * @function hex2rgb * @param {number} hex - The number to convert * @param {number[]} [out=[]] If supplied, this array will be used rather than returning a new one * @return {number[]} An array representing the [R, G, B] of the color. @@ -24451,6 +27528,7 @@ function hex2rgb(hex, out) { * Converts a hex color number to a string. * * @memberof PIXI.utils + * @function hex2string * @param {number} hex - Number in hex * @return {string} The string color. */ @@ -24465,11 +27543,12 @@ function hex2string(hex) { * Converts a color as an [R, G, B] array to a hex number * * @memberof PIXI.utils + * @function rgb2hex * @param {number[]} rgb - rgb array * @return {number} The color number */ function rgb2hex(rgb) { - return (rgb[0] * 255 << 16) + (rgb[1] * 255 << 8) + rgb[2] * 255; + return (rgb[0] * 255 << 16) + (rgb[1] * 255 << 8) + (rgb[2] * 255 | 0); } /** @@ -24477,17 +27556,19 @@ function rgb2hex(rgb) { * used by spritesheets and image urls * * @memberof PIXI.utils + * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -function getResolutionOfUrl(url) { - var resolution = _const.RETINA_PREFIX.exec(url); +function getResolutionOfUrl(url, defaultValue) { + var resolution = _settings2.default.RETINA_PREFIX.exec(url); if (resolution) { return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** @@ -24505,6 +27586,7 @@ function getResolutionOfUrl(url) { * parameter `dataUri` is not a valid data URI. * * @memberof PIXI.utils + * @function decomposeDataUri * @param {string} dataUri - the data URI to check * @return {DecomposedDataUri|undefined} The decomposed data uri or undefined */ @@ -24527,6 +27609,7 @@ function decomposeDataUri(dataUri) { * Get type of the image by regexp for extension. Returns undefined for unknown extensions. * * @memberof PIXI.utils + * @function getUrlFileExtension * @param {string} url - the image path * @return {string|undefined} image extension */ @@ -24552,6 +27635,7 @@ function getUrlFileExtension(url) { * Get size from an svg string using regexp. * * @memberof PIXI.utils + * @function getSvgSize * @param {string} svgString - a serialized svg element * @return {Size|undefined} image extension */ @@ -24560,8 +27644,8 @@ function getSvgSize(svgString) { var size = {}; if (sizeMatch) { - size[sizeMatch[1]] = Math.round(parseFloat(sizeMatch[2])); - size[sizeMatch[3]] = Math.round(parseFloat(sizeMatch[4])); + size[sizeMatch[1]] = Math.round(parseFloat(sizeMatch[3])); + size[sizeMatch[5]] = Math.round(parseFloat(sizeMatch[7])); } return size; @@ -24570,6 +27654,8 @@ function getSvgSize(svgString) { /** * Skips the hello message of renderers that are created after this is run. * + * @function skipHello + * @memberof PIXI.utils */ function skipHello() { saidHello = true; @@ -24581,6 +27667,7 @@ function skipHello() { * creating your renderer. Keep in mind that doing that will forever makes you a jerk face. * * @static + * @function sayHello * @memberof PIXI.utils * @param {string} type - The string renderer type to log. */ @@ -24590,11 +27677,11 @@ function sayHello(type) { } if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) { - var args = ['\n %c %c %c Pixi.js ' + _const.VERSION + ' - \u2730 ' + type + ' \u2730 %c %c http://www.pixijs.com/ %c %c \u2665%c\u2665%c\u2665 \n\n', 'background: #ff66a5; padding:5px 0;', 'background: #ff66a5; padding:5px 0;', 'color: #ff66a5; background: #030307; padding:5px 0;', 'background: #ff66a5; padding:5px 0;', 'background: #ffc3dc; padding:5px 0;', 'background: #ff66a5; padding:5px 0;', 'color: #ff2424; background: #fff; padding:5px 0;', 'color: #ff2424; background: #fff; padding:5px 0;', 'color: #ff2424; background: #fff; padding:5px 0;']; + var args = ['\n %c %c %c PixiJS ' + _const.VERSION + ' - \u2730 ' + type + ' \u2730 %c %c http://www.pixijs.com/ %c %c \u2665%c\u2665%c\u2665 \n\n', 'background: #ff66a5; padding:5px 0;', 'background: #ff66a5; padding:5px 0;', 'color: #ff66a5; background: #030307; padding:5px 0;', 'background: #ff66a5; padding:5px 0;', 'background: #ffc3dc; padding:5px 0;', 'background: #ff66a5; padding:5px 0;', 'color: #ff2424; background: #fff; padding:5px 0;', 'color: #ff2424; background: #fff; padding:5px 0;', 'color: #ff2424; background: #fff; padding:5px 0;']; window.console.log.apply(console, args); } else if (window.console) { - window.console.log('Pixi.js ' + _const.VERSION + ' - ' + type + ' - http://www.pixijs.com/'); + window.console.log('PixiJS ' + _const.VERSION + ' - ' + type + ' - http://www.pixijs.com/'); } saidHello = true; @@ -24604,6 +27691,7 @@ function sayHello(type) { * Helper for checking for webgl support * * @memberof PIXI.utils + * @function isWebGLSupported * @return {boolean} is webgl supported */ function isWebGLSupported() { @@ -24639,6 +27727,7 @@ function isWebGLSupported() { * Returns sign of number * * @memberof PIXI.utils + * @function sign * @param {number} n - the number to check the sign of * @returns {number} 0 if `n` is 0, -1 if `n` is negative, 1 if `n` is positive */ @@ -24649,70 +27738,278 @@ function sign(n) { } /** - * Remove a range of items from an array + * @todo Describe property usage * * @memberof PIXI.utils - * @param {Array<*>} arr The target array - * @param {number} startIdx The index to begin removing from (inclusive) - * @param {number} removeCount How many items to remove + * @private */ -function removeItems(arr, startIdx, removeCount) { - var length = arr.length; +var TextureCache = exports.TextureCache = Object.create(null); - if (startIdx >= length || removeCount === 0) { - return; +/** + * @todo Describe property usage + * + * @memberof PIXI.utils + * @private + */ +var BaseTextureCache = exports.BaseTextureCache = Object.create(null); + +/** + * Destroys all texture in the cache + * + * @memberof PIXI.utils + * @function destroyTextureCache + */ +function destroyTextureCache() { + var key = void 0; + + for (key in TextureCache) { + TextureCache[key].destroy(); + } + for (key in BaseTextureCache) { + BaseTextureCache[key].destroy(); } +} + +/** + * Removes all textures from cache, but does not destroy them + * + * @memberof PIXI.utils + * @function clearTextureCache + */ +function clearTextureCache() { + var key = void 0; + + for (key in TextureCache) { + delete TextureCache[key]; + } + for (key in BaseTextureCache) { + delete BaseTextureCache[key]; + } +} - removeCount = startIdx + removeCount > length ? length - startIdx : removeCount; +/** + * maps premultiply flag and blendMode to adjusted blendMode + * @memberof PIXI.utils + * @const premultiplyBlendMode + * @type {Array} + */ +var premultiplyBlendMode = exports.premultiplyBlendMode = (0, _mapPremultipliedBlendModes2.default)(); - var len = length - removeCount; +/** + * changes blendMode according to texture format + * + * @memberof PIXI.utils + * @function correctBlendMode + * @param {number} blendMode supposed blend mode + * @param {boolean} premultiplied whether source is premultiplied + * @returns {number} true blend mode for this texture + */ +function correctBlendMode(blendMode, premultiplied) { + return premultiplyBlendMode[premultiplied ? 1 : 0][blendMode]; +} - for (var i = startIdx; i < len; ++i) { - arr[i] = arr[i + removeCount]; +/** + * premultiplies tint + * + * @param {number} tint integet RGB + * @param {number} alpha floating point alpha (0.0-1.0) + * @returns {number} tint multiplied by alpha + */ +function premultiplyTint(tint, alpha) { + if (alpha === 1.0) { + return (alpha * 255 << 24) + tint; + } + if (alpha === 0.0) { + return 0; } + var R = tint >> 16 & 0xFF; + var G = tint >> 8 & 0xFF; + var B = tint & 0xFF; - arr.length = len; + R = R * alpha + 0.5 | 0; + G = G * alpha + 0.5 | 0; + B = B * alpha + 0.5 | 0; + + return (alpha * 255 << 24) + (R << 16) + (G << 8) + B; } /** - * @todo Describe property usage + * combines rgb and alpha to out array + * + * @param {Float32Array|number[]} rgb input rgb + * @param {number} alpha alpha param + * @param {Float32Array} [out] output + * @param {boolean} [premultiply=true] do premultiply it + * @returns {Float32Array} vec4 rgba + */ +function premultiplyRgba(rgb, alpha, out, premultiply) { + out = out || new Float32Array(4); + if (premultiply || premultiply === undefined) { + out[0] = rgb[0] * alpha; + out[1] = rgb[1] * alpha; + out[2] = rgb[2] * alpha; + } else { + out[0] = rgb[0]; + out[1] = rgb[1]; + out[2] = rgb[2]; + } + out[3] = alpha; + + return out; +} + +/** + * converts integer tint and float alpha to vec4 form, premultiplies by default + * + * @param {number} tint input tint + * @param {number} alpha alpha param + * @param {Float32Array} [out] output + * @param {boolean} [premultiply=true] do premultiply it + * @returns {Float32Array} vec4 rgba + */ +function premultiplyTintToRgba(tint, alpha, out, premultiply) { + out = out || new Float32Array(4); + out[0] = (tint >> 16 & 0xFF) / 255.0; + out[1] = (tint >> 8 & 0xFF) / 255.0; + out[2] = (tint & 0xFF) / 255.0; + if (premultiply || premultiply === undefined) { + out[0] *= alpha; + out[1] *= alpha; + out[2] *= alpha; + } + out[3] = alpha; + + return out; +} + +},{"../const":46,"../settings":101,"./mapPremultipliedBlendModes":125,"./mixin":127,"./pluginTarget":128,"eventemitter3":20,"ismobilejs":21,"remove-array-items":31}],125:[function(require,module,exports){ +'use strict'; + +exports.__esModule = true; +exports.default = mapPremultipliedBlendModes; + +var _const = require('../const'); + +/** + * Corrects PixiJS blend, takes premultiplied alpha into account + * + * @memberof PIXI + * @function mapPremultipliedBlendModes + * @private + * @param {Array} [array] - The array to output into. + * @return {Array} Mapped modes. + */ + +function mapPremultipliedBlendModes() { + var pm = []; + var npm = []; + + for (var i = 0; i < 32; i++) { + pm[i] = i; + npm[i] = i; + } + + pm[_const.BLEND_MODES.NORMAL_NPM] = _const.BLEND_MODES.NORMAL; + pm[_const.BLEND_MODES.ADD_NPM] = _const.BLEND_MODES.ADD; + pm[_const.BLEND_MODES.SCREEN_NPM] = _const.BLEND_MODES.SCREEN; + + npm[_const.BLEND_MODES.NORMAL] = _const.BLEND_MODES.NORMAL_NPM; + npm[_const.BLEND_MODES.ADD] = _const.BLEND_MODES.ADD_NPM; + npm[_const.BLEND_MODES.SCREEN] = _const.BLEND_MODES.SCREEN_NPM; + + var array = []; + + array.push(npm); + array.push(pm); + + return array; +} + +},{"../const":46}],126:[function(require,module,exports){ +'use strict'; + +exports.__esModule = true; +exports.default = maxRecommendedTextures; + +var _ismobilejs = require('ismobilejs'); + +var _ismobilejs2 = _interopRequireDefault(_ismobilejs); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function maxRecommendedTextures(max) { + if (_ismobilejs2.default.tablet || _ismobilejs2.default.phone) { + // check if the res is iphone 6 or higher.. + return 4; + } + + // desktop should be ok + return max; +} + +},{"ismobilejs":21}],127:[function(require,module,exports){ +"use strict"; + +exports.__esModule = true; +exports.mixin = mixin; +exports.delayMixin = delayMixin; +exports.performMixins = performMixins; +/** + * Mixes all enumerable properties and methods from a source object to a target object. + * + * @memberof PIXI.utils.mixins + * @function mixin + * @param {object} target The prototype or instance that properties and methods should be added to. + * @param {object} source The source of properties and methods to mix in. + */ +function mixin(target, source) { + if (!target || !source) return; + // in ES8/ES2017, this would be really easy: + // Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); + + // get all the enumerable property keys + var keys = Object.keys(source); + + // loop through properties + for (var i = 0; i < keys.length; ++i) { + var propertyName = keys[i]; + + // Set the property using the property descriptor - this works for accessors and normal value properties + Object.defineProperty(target, propertyName, Object.getOwnPropertyDescriptor(source, propertyName)); + } +} + +var mixins = []; + +/** + * Queues a mixin to be handled towards the end of the initialization of PIXI, so that deprecation + * can take effect. * - * @memberof PIXI.utils + * @memberof PIXI.utils.mixins + * @function delayMixin * @private + * @param {object} target The prototype or instance that properties and methods should be added to. + * @param {object} source The source of properties and methods to mix in. */ -var TextureCache = exports.TextureCache = {}; +function delayMixin(target, source) { + mixins.push(target, source); +} /** - * @todo Describe property usage + * Handles all mixins queued via delayMixin(). * - * @memberof PIXI.utils + * @memberof PIXI.utils.mixins + * @function performMixins * @private */ -var BaseTextureCache = exports.BaseTextureCache = {}; - -},{"../const":42,"./pluginTarget":117,"eventemitter3":19}],116:[function(require,module,exports){ -'use strict'; - -exports.__esModule = true; -exports.default = maxRecommendedTextures; - -var _ismobilejs = require('ismobilejs'); - -var _ismobilejs2 = _interopRequireDefault(_ismobilejs); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function maxRecommendedTextures(max) { - if (_ismobilejs2.default.tablet || _ismobilejs2.default.phone) { - // check if the res is iphone 6 or higher.. - return 2; +function performMixins() { + for (var i = 0; i < mixins.length; i += 2) { + mixin(mixins[i], mixins[i + 1]); } - - // desktop should be ok - return max; + mixins.length = 0; } -},{"ismobilejs":20}],117:[function(require,module,exports){ +},{}],128:[function(require,module,exports){ "use strict"; exports.__esModule = true; @@ -24778,31 +28075,87 @@ exports.default = { } }; -},{}],118:[function(require,module,exports){ +},{}],129:[function(require,module,exports){ 'use strict'; -var _core = require('./core'); +exports.__esModule = true; +exports.default = trimCanvas; +/** + * Trim transparent borders from a canvas + * + * @memberof PIXI + * @function trimCanvas + * @private + * @param {HTMLCanvasElement} canvas - the canvas to trim + * @returns {object} Trim data + */ +function trimCanvas(canvas) { + // https://gist.github.com/remy/784508 -var core = _interopRequireWildcard(_core); + var width = canvas.width; + var height = canvas.height; -var _mesh = require('./mesh'); + var context = canvas.getContext('2d'); + var imageData = context.getImageData(0, 0, width, height); + var pixels = imageData.data; + var len = pixels.length; -var mesh = _interopRequireWildcard(_mesh); + var bound = { + top: null, + left: null, + right: null, + bottom: null + }; + var i = void 0; + var x = void 0; + var y = void 0; -var _particles = require('./particles'); + for (i = 0; i < len; i += 4) { + if (pixels[i + 3] !== 0) { + x = i / 4 % width; + y = ~~(i / 4 / width); -var particles = _interopRequireWildcard(_particles); + if (bound.top === null) { + bound.top = y; + } -var _extras = require('./extras'); + if (bound.left === null) { + bound.left = x; + } else if (x < bound.left) { + bound.left = x; + } -var extras = _interopRequireWildcard(_extras); + if (bound.right === null) { + bound.right = x + 1; + } else if (bound.right < x) { + bound.right = x + 1; + } -var _filters = require('./filters'); + if (bound.bottom === null) { + bound.bottom = y; + } else if (bound.bottom < y) { + bound.bottom = y; + } + } + } -var filters = _interopRequireWildcard(_filters); + width = bound.right - bound.left; + height = bound.bottom - bound.top + 1; -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + var data = context.getImageData(bound.left, bound.top, width, height); + + return { + height: height, + width: width, + data: data + }; +} + +},{}],130:[function(require,module,exports){ +'use strict'; +exports.__esModule = true; +exports.default = deprecation; // provide method to give a stack track for warnings // useful for tracking-down where deprecated methods/properties/classes // are being used within the code @@ -24829,523 +28182,1072 @@ function warn(msg) { /* eslint-enable no-console */ } -/** - * @class - * @private - * @name SpriteBatch - * @memberof PIXI - * @see PIXI.ParticleContainer - * @throws {ReferenceError} SpriteBatch does not exist any more, please use the new ParticleContainer instead. - * @deprecated since version 3.0.0 - */ -core.SpriteBatch = function () { - throw new ReferenceError('SpriteBatch does not exist any more, please use the new ParticleContainer instead.'); -}; +function deprecation(core) { + var mesh = core.mesh; + var particles = core.particles; + var extras = core.extras; + var filters = core.filters; + var prepare = core.prepare; + var loaders = core.loaders; + var interaction = core.interaction; -/** - * @class - * @private - * @name AssetLoader - * @memberof PIXI - * @see PIXI.loaders.Loader - * @throws {ReferenceError} The loader system was overhauled in pixi v3, please see the new PIXI.loaders.Loader class. - * @deprecated since version 3.0.0 - */ -core.AssetLoader = function () { - throw new ReferenceError('The loader system was overhauled in pixi v3, please see the new PIXI.loaders.Loader class.'); -}; -Object.defineProperties(core, { + Object.defineProperties(core, { - /** - * @class - * @private - * @name Stage - * @memberof PIXI - * @see PIXI.Container - * @deprecated since version 3.0.0 - */ - Stage: { - enumerable: true, - get: function get() { - warn('You do not need to use a PIXI Stage any more, you can simply render any container.'); + /** + * @class + * @private + * @name SpriteBatch + * @memberof PIXI + * @see PIXI.ParticleContainer + * @throws {ReferenceError} SpriteBatch does not exist any more, please use the new ParticleContainer instead. + * @deprecated since version 3.0.0 + */ + SpriteBatch: { + get: function get() { + throw new ReferenceError('SpriteBatch does not exist any more, ' + 'please use the new ParticleContainer instead.'); + } + }, - return core.Container; - } - }, + /** + * @class + * @private + * @name AssetLoader + * @memberof PIXI + * @see PIXI.loaders.Loader + * @throws {ReferenceError} The loader system was overhauled in PixiJS v3, + * please see the new PIXI.loaders.Loader class. + * @deprecated since version 3.0.0 + */ + AssetLoader: { + get: function get() { + throw new ReferenceError('The loader system was overhauled in PixiJS v3, ' + 'please see the new PIXI.loaders.Loader class.'); + } + }, - /** - * @class - * @private - * @name DisplayObjectContainer - * @memberof PIXI - * @see PIXI.Container - * @deprecated since version 3.0.0 - */ - DisplayObjectContainer: { - enumerable: true, - get: function get() { - warn('DisplayObjectContainer has been shortened to Container, please use Container from now on.'); + /** + * @class + * @private + * @name Stage + * @memberof PIXI + * @see PIXI.Container + * @deprecated since version 3.0.0 + */ + Stage: { + get: function get() { + warn('You do not need to use a PIXI Stage any more, you can simply render any container.'); - return core.Container; - } - }, + return core.Container; + } + }, - /** - * @class - * @private - * @name Strip - * @memberof PIXI - * @see PIXI.mesh.Mesh - * @deprecated since version 3.0.0 - */ - Strip: { - enumerable: true, - get: function get() { - warn('The Strip class has been renamed to Mesh and moved to mesh.Mesh, please use mesh.Mesh from now on.'); + /** + * @class + * @private + * @name DisplayObjectContainer + * @memberof PIXI + * @see PIXI.Container + * @deprecated since version 3.0.0 + */ + DisplayObjectContainer: { + get: function get() { + warn('DisplayObjectContainer has been shortened to Container, please use Container from now on.'); - return mesh.Mesh; - } - }, + return core.Container; + } + }, - /** - * @class - * @private - * @name Rope - * @memberof PIXI - * @see PIXI.mesh.Rope - * @deprecated since version 3.0.0 - */ - Rope: { - enumerable: true, - get: function get() { - warn('The Rope class has been moved to mesh.Rope, please use mesh.Rope from now on.'); + /** + * @class + * @private + * @name Strip + * @memberof PIXI + * @see PIXI.mesh.Mesh + * @deprecated since version 3.0.0 + */ + Strip: { + get: function get() { + warn('The Strip class has been renamed to Mesh and moved to mesh.Mesh, please use mesh.Mesh from now on.'); - return mesh.Rope; - } - }, + return mesh.Mesh; + } + }, - /** - * @class - * @private - * @name ParticleContainer - * @memberof PIXI - * @see PIXI.particles.ParticleContainer - * @deprecated since version 4.0.0 - */ - ParticleContainer: { - enumerable: true, - get: function get() { - warn('The ParticleContainer class has been moved to particles.ParticleContainer, ' + 'please use particles.ParticleContainer from now on.'); + /** + * @class + * @private + * @name Rope + * @memberof PIXI + * @see PIXI.mesh.Rope + * @deprecated since version 3.0.0 + */ + Rope: { + get: function get() { + warn('The Rope class has been moved to mesh.Rope, please use mesh.Rope from now on.'); - return particles.ParticleContainer; - } - }, + return mesh.Rope; + } + }, - /** - * @class - * @private - * @name MovieClip - * @memberof PIXI - * @see PIXI.extras.MovieClip - * @deprecated since version 3.0.0 - */ - MovieClip: { - enumerable: true, - get: function get() { - warn('The MovieClip class has been moved to extras.MovieClip, please use extras.MovieClip from now on.'); + /** + * @class + * @private + * @name ParticleContainer + * @memberof PIXI + * @see PIXI.particles.ParticleContainer + * @deprecated since version 4.0.0 + */ + ParticleContainer: { + get: function get() { + warn('The ParticleContainer class has been moved to particles.ParticleContainer, ' + 'please use particles.ParticleContainer from now on.'); - return extras.MovieClip; - } - }, + return particles.ParticleContainer; + } + }, - /** - * @class - * @private - * @name TilingSprite - * @memberof PIXI - * @see PIXI.extras.TilingSprite - * @deprecated since version 3.0.0 - */ - TilingSprite: { - enumerable: true, - get: function get() { - warn('The TilingSprite class has been moved to extras.TilingSprite, ' + 'please use extras.TilingSprite from now on.'); + /** + * @class + * @private + * @name MovieClip + * @memberof PIXI + * @see PIXI.extras.MovieClip + * @deprecated since version 3.0.0 + */ + MovieClip: { + get: function get() { + warn('The MovieClip class has been moved to extras.AnimatedSprite, please use extras.AnimatedSprite.'); + + return extras.AnimatedSprite; + } + }, + + /** + * @class + * @private + * @name TilingSprite + * @memberof PIXI + * @see PIXI.extras.TilingSprite + * @deprecated since version 3.0.0 + */ + TilingSprite: { + get: function get() { + warn('The TilingSprite class has been moved to extras.TilingSprite, ' + 'please use extras.TilingSprite from now on.'); + + return extras.TilingSprite; + } + }, + + /** + * @class + * @private + * @name BitmapText + * @memberof PIXI + * @see PIXI.extras.BitmapText + * @deprecated since version 3.0.0 + */ + BitmapText: { + get: function get() { + warn('The BitmapText class has been moved to extras.BitmapText, ' + 'please use extras.BitmapText from now on.'); + + return extras.BitmapText; + } + }, + + /** + * @class + * @private + * @name blendModes + * @memberof PIXI + * @see PIXI.BLEND_MODES + * @deprecated since version 3.0.0 + */ + blendModes: { + get: function get() { + warn('The blendModes has been moved to BLEND_MODES, please use BLEND_MODES from now on.'); + + return core.BLEND_MODES; + } + }, + + /** + * @class + * @private + * @name scaleModes + * @memberof PIXI + * @see PIXI.SCALE_MODES + * @deprecated since version 3.0.0 + */ + scaleModes: { + get: function get() { + warn('The scaleModes has been moved to SCALE_MODES, please use SCALE_MODES from now on.'); + + return core.SCALE_MODES; + } + }, + + /** + * @class + * @private + * @name BaseTextureCache + * @memberof PIXI + * @see PIXI.utils.BaseTextureCache + * @deprecated since version 3.0.0 + */ + BaseTextureCache: { + get: function get() { + warn('The BaseTextureCache class has been moved to utils.BaseTextureCache, ' + 'please use utils.BaseTextureCache from now on.'); + + return core.utils.BaseTextureCache; + } + }, + + /** + * @class + * @private + * @name TextureCache + * @memberof PIXI + * @see PIXI.utils.TextureCache + * @deprecated since version 3.0.0 + */ + TextureCache: { + get: function get() { + warn('The TextureCache class has been moved to utils.TextureCache, ' + 'please use utils.TextureCache from now on.'); + + return core.utils.TextureCache; + } + }, + + /** + * @namespace + * @private + * @name math + * @memberof PIXI + * @see PIXI + * @deprecated since version 3.0.6 + */ + math: { + get: function get() { + warn('The math namespace is deprecated, please access members already accessible on PIXI.'); + + return core; + } + }, + + /** + * @class + * @private + * @name PIXI.AbstractFilter + * @see PIXI.Filter + * @deprecated since version 3.0.6 + */ + AbstractFilter: { + get: function get() { + warn('AstractFilter has been renamed to Filter, please use PIXI.Filter'); + + return core.Filter; + } + }, + + /** + * @class + * @private + * @name PIXI.TransformManual + * @see PIXI.TransformBase + * @deprecated since version 4.0.0 + */ + TransformManual: { + get: function get() { + warn('TransformManual has been renamed to TransformBase, please update your pixi-spine'); + + return core.TransformBase; + } + }, + + /** + * @static + * @constant + * @name PIXI.TARGET_FPMS + * @see PIXI.settings.TARGET_FPMS + * @deprecated since version 4.2.0 + */ + TARGET_FPMS: { + get: function get() { + warn('PIXI.TARGET_FPMS has been deprecated, please use PIXI.settings.TARGET_FPMS'); + + return core.settings.TARGET_FPMS; + }, + set: function set(value) { + warn('PIXI.TARGET_FPMS has been deprecated, please use PIXI.settings.TARGET_FPMS'); + + core.settings.TARGET_FPMS = value; + } + }, + + /** + * @static + * @constant + * @name PIXI.FILTER_RESOLUTION + * @see PIXI.settings.FILTER_RESOLUTION + * @deprecated since version 4.2.0 + */ + FILTER_RESOLUTION: { + get: function get() { + warn('PIXI.FILTER_RESOLUTION has been deprecated, please use PIXI.settings.FILTER_RESOLUTION'); + + return core.settings.FILTER_RESOLUTION; + }, + set: function set(value) { + warn('PIXI.FILTER_RESOLUTION has been deprecated, please use PIXI.settings.FILTER_RESOLUTION'); + + core.settings.FILTER_RESOLUTION = value; + } + }, + + /** + * @static + * @constant + * @name PIXI.RESOLUTION + * @see PIXI.settings.RESOLUTION + * @deprecated since version 4.2.0 + */ + RESOLUTION: { + get: function get() { + warn('PIXI.RESOLUTION has been deprecated, please use PIXI.settings.RESOLUTION'); + + return core.settings.RESOLUTION; + }, + set: function set(value) { + warn('PIXI.RESOLUTION has been deprecated, please use PIXI.settings.RESOLUTION'); + + core.settings.RESOLUTION = value; + } + }, + + /** + * @static + * @constant + * @name PIXI.MIPMAP_TEXTURES + * @see PIXI.settings.MIPMAP_TEXTURES + * @deprecated since version 4.2.0 + */ + MIPMAP_TEXTURES: { + get: function get() { + warn('PIXI.MIPMAP_TEXTURES has been deprecated, please use PIXI.settings.MIPMAP_TEXTURES'); - return extras.TilingSprite; + return core.settings.MIPMAP_TEXTURES; + }, + set: function set(value) { + warn('PIXI.MIPMAP_TEXTURES has been deprecated, please use PIXI.settings.MIPMAP_TEXTURES'); + + core.settings.MIPMAP_TEXTURES = value; + } + }, + + /** + * @static + * @constant + * @name PIXI.SPRITE_BATCH_SIZE + * @see PIXI.settings.SPRITE_BATCH_SIZE + * @deprecated since version 4.2.0 + */ + SPRITE_BATCH_SIZE: { + get: function get() { + warn('PIXI.SPRITE_BATCH_SIZE has been deprecated, please use PIXI.settings.SPRITE_BATCH_SIZE'); + + return core.settings.SPRITE_BATCH_SIZE; + }, + set: function set(value) { + warn('PIXI.SPRITE_BATCH_SIZE has been deprecated, please use PIXI.settings.SPRITE_BATCH_SIZE'); + + core.settings.SPRITE_BATCH_SIZE = value; + } + }, + + /** + * @static + * @constant + * @name PIXI.SPRITE_MAX_TEXTURES + * @see PIXI.settings.SPRITE_MAX_TEXTURES + * @deprecated since version 4.2.0 + */ + SPRITE_MAX_TEXTURES: { + get: function get() { + warn('PIXI.SPRITE_MAX_TEXTURES has been deprecated, please use PIXI.settings.SPRITE_MAX_TEXTURES'); + + return core.settings.SPRITE_MAX_TEXTURES; + }, + set: function set(value) { + warn('PIXI.SPRITE_MAX_TEXTURES has been deprecated, please use PIXI.settings.SPRITE_MAX_TEXTURES'); + + core.settings.SPRITE_MAX_TEXTURES = value; + } + }, + + /** + * @static + * @constant + * @name PIXI.RETINA_PREFIX + * @see PIXI.settings.RETINA_PREFIX + * @deprecated since version 4.2.0 + */ + RETINA_PREFIX: { + get: function get() { + warn('PIXI.RETINA_PREFIX has been deprecated, please use PIXI.settings.RETINA_PREFIX'); + + return core.settings.RETINA_PREFIX; + }, + set: function set(value) { + warn('PIXI.RETINA_PREFIX has been deprecated, please use PIXI.settings.RETINA_PREFIX'); + + core.settings.RETINA_PREFIX = value; + } + }, + + /** + * @static + * @constant + * @name PIXI.DEFAULT_RENDER_OPTIONS + * @see PIXI.settings.RENDER_OPTIONS + * @deprecated since version 4.2.0 + */ + DEFAULT_RENDER_OPTIONS: { + get: function get() { + warn('PIXI.DEFAULT_RENDER_OPTIONS has been deprecated, please use PIXI.settings.DEFAULT_RENDER_OPTIONS'); + + return core.settings.RENDER_OPTIONS; + } } - }, + }); - /** - * @class - * @private - * @name BitmapText - * @memberof PIXI - * @see PIXI.extras.BitmapText - * @deprecated since version 3.0.0 - */ - BitmapText: { - enumerable: true, - get: function get() { - warn('The BitmapText class has been moved to extras.BitmapText, ' + 'please use extras.BitmapText from now on.'); + // Move the default properties to settings + var defaults = [{ parent: 'TRANSFORM_MODE', target: 'TRANSFORM_MODE' }, { parent: 'GC_MODES', target: 'GC_MODE' }, { parent: 'WRAP_MODES', target: 'WRAP_MODE' }, { parent: 'SCALE_MODES', target: 'SCALE_MODE' }, { parent: 'PRECISION', target: 'PRECISION_FRAGMENT' }]; + + var _loop = function _loop(i) { + var deprecation = defaults[i]; + + Object.defineProperty(core[deprecation.parent], 'DEFAULT', { + get: function get() { + warn('PIXI.' + deprecation.parent + '.DEFAULT has been deprecated, ' + ('please use PIXI.settings.' + deprecation.target)); + + return core.settings[deprecation.target]; + }, + set: function set(value) { + warn('PIXI.' + deprecation.parent + '.DEFAULT has been deprecated, ' + ('please use PIXI.settings.' + deprecation.target)); - return extras.BitmapText; + core.settings[deprecation.target] = value; + } + }); + }; + + for (var i = 0; i < defaults.length; i++) { + _loop(i); + } + + Object.defineProperties(core.settings, { + + /** + * @static + * @name PRECISION + * @memberof PIXI.settings + * @see PIXI.PRECISION + * @deprecated since version 4.4.0 + */ + PRECISION: { + get: function get() { + warn('PIXI.settings.PRECISION has been deprecated, please use PIXI.settings.PRECISION_FRAGMENT'); + + return core.settings.PRECISION_FRAGMENT; + }, + set: function set(value) { + warn('PIXI.settings.PRECISION has been deprecated, please use PIXI.settings.PRECISION_FRAGMENT'); + + core.settings.PRECISION_FRAGMENT = value; + } } - }, + }); + + if (extras.AnimatedSprite) { + Object.defineProperties(extras, { + + /** + * @class + * @name MovieClip + * @memberof PIXI.extras + * @see PIXI.extras.AnimatedSprite + * @deprecated since version 4.2.0 + */ + MovieClip: { + get: function get() { + warn('The MovieClip class has been renamed to AnimatedSprite, please use AnimatedSprite from now on.'); + + return extras.AnimatedSprite; + } + } + }); + } + + core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution) { + warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)'); + + return renderer.generateTexture(this, scaleMode, resolution); + }; + + core.Graphics.prototype.generateTexture = function generateTexture(scaleMode, resolution) { + warn('graphics generate texture has moved to the renderer. ' + 'Or to render a graphics to a texture using canvas please use generateCanvasTexture'); + + return this.generateCanvasTexture(scaleMode, resolution); + }; + + core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform) { + this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform); + warn('RenderTexture.render is now deprecated, please use renderer.render(displayObject, renderTexture)'); + }; + + core.RenderTexture.prototype.getImage = function getImage(target) { + warn('RenderTexture.getImage is now deprecated, please use renderer.extract.image(target)'); + + return this.legacyRenderer.extract.image(target); + }; + + core.RenderTexture.prototype.getBase64 = function getBase64(target) { + warn('RenderTexture.getBase64 is now deprecated, please use renderer.extract.base64(target)'); + + return this.legacyRenderer.extract.base64(target); + }; + + core.RenderTexture.prototype.getCanvas = function getCanvas(target) { + warn('RenderTexture.getCanvas is now deprecated, please use renderer.extract.canvas(target)'); + + return this.legacyRenderer.extract.canvas(target); + }; + + core.RenderTexture.prototype.getPixels = function getPixels(target) { + warn('RenderTexture.getPixels is now deprecated, please use renderer.extract.pixels(target)'); + + return this.legacyRenderer.pixels(target); + }; /** - * @class + * @method * @private - * @name blendModes - * @memberof PIXI - * @see PIXI.BLEND_MODES + * @name PIXI.Sprite#setTexture + * @see PIXI.Sprite#texture * @deprecated since version 3.0.0 + * @param {PIXI.Texture} texture - The texture to set to. */ - blendModes: { - enumerable: true, - get: function get() { - warn('The blendModes has been moved to BLEND_MODES, please use BLEND_MODES from now on.'); + core.Sprite.prototype.setTexture = function setTexture(texture) { + this.texture = texture; + warn('setTexture is now deprecated, please use the texture property, e.g : sprite.texture = texture;'); + }; - return core.BLEND_MODES; - } - }, + if (extras.BitmapText) { + /** + * @method + * @name PIXI.extras.BitmapText#setText + * @see PIXI.extras.BitmapText#text + * @deprecated since version 3.0.0 + * @param {string} text - The text to set to. + */ + extras.BitmapText.prototype.setText = function setText(text) { + this.text = text; + warn('setText is now deprecated, please use the text property, e.g : myBitmapText.text = \'my text\';'); + }; + } /** - * @class - * @private - * @name scaleModes - * @memberof PIXI - * @see PIXI.SCALE_MODES + * @method + * @name PIXI.Text#setText + * @see PIXI.Text#text * @deprecated since version 3.0.0 + * @param {string} text - The text to set to. */ - scaleModes: { - enumerable: true, - get: function get() { - warn('The scaleModes has been moved to SCALE_MODES, please use SCALE_MODES from now on.'); - - return core.SCALE_MODES; - } - }, + core.Text.prototype.setText = function setText(text) { + this.text = text; + warn('setText is now deprecated, please use the text property, e.g : myText.text = \'my text\';'); + }; /** - * @class - * @private - * @name BaseTextureCache - * @memberof PIXI - * @see PIXI.utils.BaseTextureCache - * @deprecated since version 3.0.0 + * Calculates the ascent, descent and fontSize of a given fontStyle + * + * @name PIXI.Text.calculateFontProperties + * @see PIXI.TextMetrics.measureFont + * @deprecated since version 4.5.0 + * @param {string} font - String representing the style of the font + * @return {Object} Font properties object */ - BaseTextureCache: { - enumerable: true, - get: function get() { - warn('The BaseTextureCache class has been moved to utils.BaseTextureCache, ' + 'please use utils.BaseTextureCache from now on.'); + core.Text.calculateFontProperties = function calculateFontProperties(font) { + warn('Text.calculateFontProperties is now deprecated, please use the TextMetrics.measureFont'); + + return core.TextMetrics.measureFont(font); + }; + + Object.defineProperties(core.Text, { + fontPropertiesCache: { + get: function get() { + warn('Text.fontPropertiesCache is deprecated'); + + return core.TextMetrics._fonts; + } + }, + fontPropertiesCanvas: { + get: function get() { + warn('Text.fontPropertiesCanvas is deprecated'); + + return core.TextMetrics._canvas; + } + }, + fontPropertiesContext: { + get: function get() { + warn('Text.fontPropertiesContext is deprecated'); - return core.utils.BaseTextureCache; + return core.TextMetrics._context; + } } - }, + }); /** - * @class - * @private - * @name TextureCache - * @memberof PIXI - * @see PIXI.utils.TextureCache + * @method + * @name PIXI.Text#setStyle + * @see PIXI.Text#style * @deprecated since version 3.0.0 + * @param {*} style - The style to set to. */ - TextureCache: { - enumerable: true, - get: function get() { - warn('The TextureCache class has been moved to utils.TextureCache, ' + 'please use utils.TextureCache from now on.'); - - return core.utils.TextureCache; - } - }, + core.Text.prototype.setStyle = function setStyle(style) { + this.style = style; + warn('setStyle is now deprecated, please use the style property, e.g : myText.style = style;'); + }; /** - * @namespace + * @method + * @name PIXI.Text#determineFontProperties + * @see PIXI.Text#measureFontProperties + * @deprecated since version 4.2.0 * @private - * @name math - * @memberof PIXI - * @see PIXI - * @deprecated since version 3.0.6 + * @param {string} fontStyle - String representing the style of the font + * @return {Object} Font properties object */ - math: { - enumerable: true, - get: function get() { - warn('The math namespace is deprecated, please access members already accessible on PIXI.'); + core.Text.prototype.determineFontProperties = function determineFontProperties(fontStyle) { + warn('determineFontProperties is now deprecated, please use TextMetrics.measureFont method'); - return core; - } - }, + return core.TextMetrics.measureFont(fontStyle); + }; /** - * @class - * @private - * @name PIXI.AbstractFilter - * @see PIXI.Filter - * @deprecated since version 3.0.6 + * @method + * @name PIXI.Text.getFontStyle + * @see PIXI.TextMetrics.getFontStyle + * @deprecated since version 4.5.0 + * @param {PIXI.TextStyle} style - The style to use. + * @return {string} Font string */ - AbstractFilter: { - enumerable: true, - get: function get() { - warn('AstractFilter has been renamed to Filter, please use PIXI.Filter'); + core.Text.getFontStyle = function getFontStyle(style) { + warn('getFontStyle is now deprecated, please use TextStyle.toFontString() instead'); + + style = style || {}; - return core.Filter; + if (!(style instanceof core.TextStyle)) { + style = new core.TextStyle(style); } - }, - /** - * @class - * @private - * @name PIXI.TransformManual - * @see PIXI.TransformBase - * @deprecated since version 4.0.0 - */ - TransformManual: { - enumerable: true, - get: function get() { - warn('TransformManual has been renamed to TransformBase, please update your pixi-spine'); + return style.toFontString(); + }; - return core.TransformBase; - } - } -}); + Object.defineProperties(core.TextStyle.prototype, { + /** + * Set all properties of a font as a single string + * + * @name PIXI.TextStyle#font + * @deprecated since version 4.0.0 + */ + font: { + get: function get() { + warn('text style property \'font\' is now deprecated, please use the ' + '\'fontFamily\', \'fontSize\', \'fontStyle\', \'fontVariant\' and \'fontWeight\' properties from now on'); -core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution) { - warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)'); + var fontSizeString = typeof this._fontSize === 'number' ? this._fontSize + 'px' : this._fontSize; - return renderer.generateTexture(this, scaleMode, resolution); -}; + return this._fontStyle + ' ' + this._fontVariant + ' ' + this._fontWeight + ' ' + fontSizeString + ' ' + this._fontFamily; + }, + set: function set(font) { + warn('text style property \'font\' is now deprecated, please use the ' + '\'fontFamily\',\'fontSize\',fontStyle\',\'fontVariant\' and \'fontWeight\' properties from now on'); -core.Graphics.prototype.generateTexture = function generateTexture(scaleMode, resolution) { - warn('graphics generate texture has moved to the renderer. ' + 'Or to render a graphics to a texture using canvas please use generateCanvasTexture'); + // can work out fontStyle from search of whole string + if (font.indexOf('italic') > 1) { + this._fontStyle = 'italic'; + } else if (font.indexOf('oblique') > -1) { + this._fontStyle = 'oblique'; + } else { + this._fontStyle = 'normal'; + } - return this.generateCanvasTexture(scaleMode, resolution); -}; + // can work out fontVariant from search of whole string + if (font.indexOf('small-caps') > -1) { + this._fontVariant = 'small-caps'; + } else { + this._fontVariant = 'normal'; + } -core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform) { - this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform); - warn('RenderTexture.render is now deprecated, please use renderer.render(displayObject, renderTexture)'); -}; + // fontWeight and fontFamily are tricker to find, but it's easier to find the fontSize due to it's units + var splits = font.split(' '); + var fontSizeIndex = -1; -core.RenderTexture.prototype.getImage = function getImage(target) { - warn('RenderTexture.getImage is now deprecated, please use renderer.extract.image(target)'); + this._fontSize = 26; + for (var _i = 0; _i < splits.length; ++_i) { + if (splits[_i].match(/(px|pt|em|%)/)) { + fontSizeIndex = _i; + this._fontSize = splits[_i]; + break; + } + } - return this.legacyRenderer.extract.image(target); -}; + // we can now search for fontWeight as we know it must occur before the fontSize + this._fontWeight = 'normal'; + for (var _i2 = 0; _i2 < fontSizeIndex; ++_i2) { + if (splits[_i2].match(/(bold|bolder|lighter|100|200|300|400|500|600|700|800|900)/)) { + this._fontWeight = splits[_i2]; + break; + } + } -core.RenderTexture.prototype.getBase64 = function getBase64(target) { - warn('RenderTexture.getBase64 is now deprecated, please use renderer.extract.base64(target)'); + // and finally join everything together after the fontSize in case the font family has multiple words + if (fontSizeIndex > -1 && fontSizeIndex < splits.length - 1) { + this._fontFamily = ''; + for (var _i3 = fontSizeIndex + 1; _i3 < splits.length; ++_i3) { + this._fontFamily += splits[_i3] + ' '; + } - return this.legacyRenderer.extract.base64(target); -}; + this._fontFamily = this._fontFamily.slice(0, -1); + } else { + this._fontFamily = 'Arial'; + } -core.RenderTexture.prototype.getCanvas = function getCanvas(target) { - warn('RenderTexture.getCanvas is now deprecated, please use renderer.extract.canvas(target)'); + this.styleID++; + } + } + }); - return this.legacyRenderer.extract.canvas(target); -}; + /** + * @method + * @name PIXI.Texture#setFrame + * @see PIXI.Texture#setFrame + * @deprecated since version 3.0.0 + * @param {PIXI.Rectangle} frame - The frame to set. + */ + core.Texture.prototype.setFrame = function setFrame(frame) { + this.frame = frame; + warn('setFrame is now deprecated, please use the frame property, e.g: myTexture.frame = frame;'); + }; -core.RenderTexture.prototype.getPixels = function getPixels(target) { - warn('RenderTexture.getPixels is now deprecated, please use renderer.extract.pixels(target)'); + /** + * @static + * @function + * @name PIXI.Texture.addTextureToCache + * @see PIXI.Texture.addToCache + * @deprecated since 4.5.0 + * @param {PIXI.Texture} texture - The Texture to add to the cache. + * @param {string} id - The id that the texture will be stored against. + */ + core.Texture.addTextureToCache = function addTextureToCache(texture, id) { + core.Texture.addToCache(texture, id); + warn('Texture.addTextureToCache is deprecated, please use Texture.addToCache from now on.'); + }; - return this.legacyRenderer.pixels(target); -}; + /** + * @static + * @function + * @name PIXI.Texture.removeTextureFromCache + * @see PIXI.Texture.removeFromCache + * @deprecated since 4.5.0 + * @param {string} id - The id of the texture to be removed + * @return {PIXI.Texture|null} The texture that was removed + */ + core.Texture.removeTextureFromCache = function removeTextureFromCache(id) { + warn('Texture.removeTextureFromCache is deprecated, please use Texture.removeFromCache from now on. ' + 'Be aware that Texture.removeFromCache does not automatically its BaseTexture from the BaseTextureCache. ' + 'For that, use BaseTexture.removeFromCache'); -/** - * @method - * @private - * @name PIXI.Sprite#setTexture - * @see PIXI.Sprite#texture - * @deprecated since version 3.0.0 - * @param {PIXI.Texture} texture - The texture to set to. - */ -core.Sprite.prototype.setTexture = function setTexture(texture) { - this.texture = texture; - warn('setTexture is now deprecated, please use the texture property, e.g : sprite.texture = texture;'); -}; + core.BaseTexture.removeFromCache(id); -/** - * @method - * @name PIXI.extras.BitmapText#setText - * @see PIXI.extras.BitmapText#text - * @deprecated since version 3.0.0 - * @param {string} text - The text to set to. - */ -extras.BitmapText.prototype.setText = function setText(text) { - this.text = text; - warn('setText is now deprecated, please use the text property, e.g : myBitmapText.text = \'my text\';'); -}; + return core.Texture.removeFromCache(id); + }; -/** - * @method - * @name PIXI.Text#setText - * @see PIXI.Text#text - * @deprecated since version 3.0.0 - * @param {string} text - The text to set to. - */ -core.Text.prototype.setText = function setText(text) { - this.text = text; - warn('setText is now deprecated, please use the text property, e.g : myText.text = \'my text\';'); -}; + Object.defineProperties(filters, { -/** - * @method - * @name PIXI.Text#setStyle - * @see PIXI.Text#style - * @deprecated since version 3.0.0 - * @param {*} style - The style to set to. - */ -core.Text.prototype.setStyle = function setStyle(style) { - this.style = style; - warn('setStyle is now deprecated, please use the style property, e.g : myText.style = style;'); -}; + /** + * @class + * @private + * @name PIXI.filters.AbstractFilter + * @see PIXI.AbstractFilter + * @deprecated since version 3.0.6 + */ + AbstractFilter: { + get: function get() { + warn('AstractFilter has been renamed to Filter, please use PIXI.Filter'); + + return core.AbstractFilter; + } + }, + + /** + * @class + * @private + * @name PIXI.filters.SpriteMaskFilter + * @see PIXI.SpriteMaskFilter + * @deprecated since version 3.0.6 + */ + SpriteMaskFilter: { + get: function get() { + warn('filters.SpriteMaskFilter is an undocumented alias, please use SpriteMaskFilter from now on.'); + + return core.SpriteMaskFilter; + } + } + }); -Object.defineProperties(core.TextStyle.prototype, { /** - * Set all properties of a font as a single string - * - * @name PIXI.TextStyle#font - * @deprecated since version 4.0.0 + * @method + * @name PIXI.utils.uuid + * @see PIXI.utils.uid + * @deprecated since version 3.0.6 + * @return {number} The uid + */ + core.utils.uuid = function () { + warn('utils.uuid() is deprecated, please use utils.uid() from now on.'); + + return core.utils.uid(); + }; + + /** + * @method + * @name PIXI.utils.canUseNewCanvasBlendModes + * @see PIXI.CanvasTinter + * @deprecated + * @return {boolean} Can use blend modes. + */ + core.utils.canUseNewCanvasBlendModes = function () { + warn('utils.canUseNewCanvasBlendModes() is deprecated, please use CanvasTinter.canUseMultiply from now on'); + + return core.CanvasTinter.canUseMultiply; + }; + + var saidHello = true; + + /** + * @name PIXI.utils._saidHello + * @type {boolean} + * @see PIXI.utils.skipHello + * @deprecated since 4.1.0 */ - font: { + Object.defineProperty(core.utils, '_saidHello', { + set: function set(bool) { + if (bool) { + warn('PIXI.utils._saidHello is deprecated, please use PIXI.utils.skipHello()'); + this.skipHello(); + } + saidHello = bool; + }, get: function get() { - warn('text style property \'font\' is now deprecated, please use the ' + '\'fontFamily\', \'fontSize\', \'fontStyle\', \'fontVariant\' and \'fontWeight\' properties from now on'); + return saidHello; + } + }); - var fontSizeString = typeof this._fontSize === 'number' ? this._fontSize + 'px' : this._fontSize; + if (prepare.BasePrepare) { + /** + * @method + * @name PIXI.prepare.BasePrepare#register + * @see PIXI.prepare.BasePrepare#registerFindHook + * @deprecated since version 4.4.2 + * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array` + * function must return `true` if it was able to add item to the queue. + * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and + * function must return `true` if it was able to handle upload of item. + * @return {PIXI.BasePrepare} Instance of plugin for chaining. + */ + prepare.BasePrepare.prototype.register = function register(addHook, uploadHook) { + warn('renderer.plugins.prepare.register is now deprecated, ' + 'please use renderer.plugins.prepare.registerFindHook & renderer.plugins.prepare.registerUploadHook'); - return this._fontStyle + ' ' + this._fontVariant + ' ' + this._fontWeight + ' ' + fontSizeString + ' ' + this._fontFamily; - }, - set: function set(font) { - warn('text style property \'font\' is now deprecated, please use the ' + '\'fontFamily\',\'fontSize\',fontStyle\',\'fontVariant\' and \'fontWeight\' properties from now on'); - - // can work out fontStyle from search of whole string - if (font.indexOf('italic') > 1) { - this._fontStyle = 'italic'; - } else if (font.indexOf('oblique') > -1) { - this._fontStyle = 'oblique'; - } else { - this._fontStyle = 'normal'; + if (addHook) { + this.registerFindHook(addHook); } - // can work out fontVariant from search of whole string - if (font.indexOf('small-caps') > -1) { - this._fontVariant = 'small-caps'; - } else { - this._fontVariant = 'normal'; + if (uploadHook) { + this.registerUploadHook(uploadHook); } - // fontWeight and fontFamily are tricker to find, but it's easier to find the fontSize due to it's units - var splits = font.split(' '); - var fontSizeIndex = -1; + return this; + }; + } - this._fontSize = 26; - for (var i = 0; i < splits.length; ++i) { - if (splits[i].match(/(px|pt|em|%)/)) { - fontSizeIndex = i; - this._fontSize = splits[i]; - break; - } - } + if (prepare.canvas) { + /** + * The number of graphics or textures to upload to the GPU. + * + * @name PIXI.prepare.canvas.UPLOADS_PER_FRAME + * @static + * @type {number} + * @see PIXI.prepare.BasePrepare.limiter + * @deprecated since 4.2.0 + */ + Object.defineProperty(prepare.canvas, 'UPLOADS_PER_FRAME', { + set: function set() { + warn('PIXI.CanvasPrepare.UPLOADS_PER_FRAME has been removed. Please set ' + 'renderer.plugins.prepare.limiter.maxItemsPerFrame on your renderer'); + // because we don't have a reference to the renderer, we can't actually set + // the uploads per frame, so we'll have to stick with the warning. + }, + get: function get() { + warn('PIXI.CanvasPrepare.UPLOADS_PER_FRAME has been removed. Please use ' + 'renderer.plugins.prepare.limiter'); - // we can now search for fontWeight as we know it must occur before the fontSize - this._fontWeight = 'normal'; - for (var _i = 0; _i < fontSizeIndex; ++_i) { - if (splits[_i].match(/(bold|bolder|lighter|100|200|300|400|500|600|700|800|900)/)) { - this._fontWeight = splits[_i]; - break; - } + return NaN; } + }); + } - // and finally join everything together after the fontSize in case the font family has multiple words - if (fontSizeIndex > -1 && fontSizeIndex < splits.length - 1) { - this._fontFamily = ''; - for (var _i2 = fontSizeIndex + 1; _i2 < splits.length; ++_i2) { - this._fontFamily += splits[_i2] + ' '; - } + if (prepare.webgl) { + /** + * The number of graphics or textures to upload to the GPU. + * + * @name PIXI.prepare.webgl.UPLOADS_PER_FRAME + * @static + * @type {number} + * @see PIXI.prepare.BasePrepare.limiter + * @deprecated since 4.2.0 + */ + Object.defineProperty(prepare.webgl, 'UPLOADS_PER_FRAME', { + set: function set() { + warn('PIXI.WebGLPrepare.UPLOADS_PER_FRAME has been removed. Please set ' + 'renderer.plugins.prepare.limiter.maxItemsPerFrame on your renderer'); + // because we don't have a reference to the renderer, we can't actually set + // the uploads per frame, so we'll have to stick with the warning. + }, + get: function get() { + warn('PIXI.WebGLPrepare.UPLOADS_PER_FRAME has been removed. Please use ' + 'renderer.plugins.prepare.limiter'); - this._fontFamily = this._fontFamily.slice(0, -1); - } else { - this._fontFamily = 'Arial'; + return NaN; } - - this.styleID++; - } + }); } -}); -/** - * @method - * @name PIXI.Texture#setFrame - * @see PIXI.Texture#setFrame - * @deprecated since version 3.0.0 - * @param {PIXI.Rectangle} frame - The frame to set. - */ -core.Texture.prototype.setFrame = function setFrame(frame) { - this.frame = frame; - warn('setFrame is now deprecated, please use the frame property, e.g: myTexture.frame = frame;'); -}; + if (loaders.Loader) { + (function () { + var Resource = loaders.Resource; + var Loader = loaders.Loader; -Object.defineProperties(filters, { + Object.defineProperties(Resource.prototype, { + isJson: { + get: function get() { + warn('The isJson property is deprecated, please use `resource.type === Resource.TYPE.JSON`.'); - /** - * @class - * @private - * @name PIXI.filters.AbstractFilter - * @see PIXI.AbstractFilter - * @deprecated since version 3.0.6 - */ - AbstractFilter: { - get: function get() { - warn('AstractFilter has been renamed to Filter, please use PIXI.Filter'); + return this.type === Resource.TYPE.JSON; + } + }, + isXml: { + get: function get() { + warn('The isXml property is deprecated, please use `resource.type === Resource.TYPE.XML`.'); - return core.AbstractFilter; - } - }, + return this.type === Resource.TYPE.XML; + } + }, + isImage: { + get: function get() { + warn('The isImage property is deprecated, please use `resource.type === Resource.TYPE.IMAGE`.'); - /** - * @class - * @private - * @name PIXI.filters.SpriteMaskFilter - * @see PIXI.SpriteMaskFilter - * @deprecated since version 3.0.6 - */ - SpriteMaskFilter: { - get: function get() { - warn('filters.SpriteMaskFilter is an undocumented alias, please use SpriteMaskFilter from now on.'); + return this.type === Resource.TYPE.IMAGE; + } + }, + isAudio: { + get: function get() { + warn('The isAudio property is deprecated, please use `resource.type === Resource.TYPE.AUDIO`.'); - return core.SpriteMaskFilter; - } + return this.type === Resource.TYPE.AUDIO; + } + }, + isVideo: { + get: function get() { + warn('The isVideo property is deprecated, please use `resource.type === Resource.TYPE.VIDEO`.'); + + return this.type === Resource.TYPE.VIDEO; + } + } + }); + + Object.defineProperties(Loader.prototype, { + before: { + get: function get() { + warn('The before() method is deprecated, please use pre().'); + + return this.pre; + } + }, + after: { + get: function get() { + warn('The after() method is deprecated, please use use().'); + + return this.use; + } + } + }); + })(); } -}); -/** - * @method - * @name PIXI.utils.uuid - * @see PIXI.utils.uid - * @deprecated since version 3.0.6 - * @return {number} The uid - */ -core.utils.uuid = function () { - warn('utils.uuid() is deprecated, please use utils.uid() from now on.'); + if (interaction.interactiveTarget) { + /** + * @name PIXI.interaction.interactiveTarget#defaultCursor + * @static + * @type {number} + * @see PIXI.interaction.interactiveTarget#cursor + * @deprecated since 4.3.0 + */ + Object.defineProperty(interaction.interactiveTarget, 'defaultCursor', { + set: function set(value) { + warn('Property defaultCursor has been replaced with \'cursor\'. '); + this.cursor = value; + }, + get: function get() { + warn('Property defaultCursor has been replaced with \'cursor\'. '); - return core.utils.uid(); -}; + return this.cursor; + } + }); + } -/** - * @method - * @name PIXI.utils.canUseNewCanvasBlendModes - * @see PIXI.CanvasTinter - * @deprecated - * @return {boolean} Can use blend modes. - */ -core.utils.canUseNewCanvasBlendModes = function () { - warn('utils.canUseNewCanvasBlendModes() is deprecated, please use CanvasTinter.canUseMultiply from now on'); + if (interaction.InteractionManager) { + /** + * @name PIXI.interaction.InteractionManager#defaultCursorStyle + * @static + * @type {string} + * @see PIXI.interaction.InteractionManager#cursorStyles + * @deprecated since 4.3.0 + */ + Object.defineProperty(interaction.InteractionManager, 'defaultCursorStyle', { + set: function set(value) { + warn('Property defaultCursorStyle has been replaced with \'cursorStyles.default\'. '); + this.cursorStyles.default = value; + }, + get: function get() { + warn('Property defaultCursorStyle has been replaced with \'cursorStyles.default\'. '); - return core.CanvasTinter.canUseMultiply; -}; + return this.cursorStyles.default; + } + }); + + /** + * @name PIXI.interaction.InteractionManager#currentCursorStyle + * @static + * @type {string} + * @see PIXI.interaction.InteractionManager#cursorStyles + * @deprecated since 4.3.0 + */ + Object.defineProperty(interaction.InteractionManager, 'currentCursorStyle', { + set: function set(value) { + warn('Property currentCursorStyle has been removed.' + 'See the currentCursorMode property, which works differently.'); + this.currentCursorMode = value; + }, + get: function get() { + warn('Property currentCursorStyle has been removed.' + 'See the currentCursorMode property, which works differently.'); -},{"./core":61,"./extras":129,"./filters":140,"./mesh":158,"./particles":161}],119:[function(require,module,exports){ + return this.currentCursorMode; + } + }); + } +} + +},{}],131:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -25363,8 +29265,10 @@ var TEMP_RECT = new core.Rectangle(); /** * The extract manager provides functionality to export content from the renderers. * + * An instance of this class is automatically created by default, and can be found at renderer.plugins.extract + * * @class - * @memberof PIXI + * @memberof PIXI.extract */ var CanvasExtract = function () { @@ -25375,6 +29279,13 @@ var CanvasExtract = function () { _classCallCheck(this, CanvasExtract); this.renderer = renderer; + /** + * Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture + * + * @member {PIXI.extract.CanvasExtract} extract + * @memberof PIXI.CanvasRenderer# + * @see PIXI.extract.CanvasExtract + */ renderer.extract = this; } @@ -25516,7 +29427,7 @@ exports.default = CanvasExtract; core.CanvasRenderer.registerPlugin('extract', CanvasExtract); -},{"../../core":61}],120:[function(require,module,exports){ +},{"../../core":65}],132:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -25541,7 +29452,7 @@ Object.defineProperty(exports, 'canvas', { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -},{"./canvas/CanvasExtract":119,"./webgl/WebGLExtract":121}],121:[function(require,module,exports){ +},{"./canvas/CanvasExtract":131,"./webgl/WebGLExtract":133}],133:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -25560,8 +29471,10 @@ var BYTES_PER_PIXEL = 4; /** * The extract manager provides functionality to export content from the renderers. * + * An instance of this class is automatically created by default, and can be found at renderer.plugins.extract + * * @class - * @memberof PIXI + * @memberof PIXI.extract */ var WebGLExtract = function () { @@ -25572,6 +29485,13 @@ var WebGLExtract = function () { _classCallCheck(this, WebGLExtract); this.renderer = renderer; + /** + * Collection of methods for extracting data (image, pixels, etc.) from a display object or render texture + * + * @member {PIXI.extract.WebGLExtract} extract + * @memberof PIXI.WebGLRenderer# + * @see PIXI.extract.WebGLExtract + */ renderer.extract = this; } @@ -25755,7 +29675,415 @@ exports.default = WebGLExtract; core.WebGLRenderer.registerPlugin('extract', WebGLExtract); -},{"../../core":61}],122:[function(require,module,exports){ +},{"../../core":65}],134:[function(require,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _core = require('../core'); + +var core = _interopRequireWildcard(_core); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +/** + * @typedef FrameObject + * @type {object} + * @property {PIXI.Texture} texture - The {@link PIXI.Texture} of the frame + * @property {number} time - the duration of the frame in ms + */ + +/** + * An AnimatedSprite is a simple way to display an animation depicted by a list of textures. + * + * ```js + * let alienImages = ["image_sequence_01.png","image_sequence_02.png","image_sequence_03.png","image_sequence_04.png"]; + * let textureArray = []; + * + * for (let i=0; i < 4; i++) + * { + * let texture = PIXI.Texture.fromImage(alienImages[i]); + * textureArray.push(texture); + * }; + * + * let mc = new PIXI.AnimatedSprite(textureArray); + * ``` + * + * @class + * @extends PIXI.Sprite + * @memberof PIXI.extras + */ +var AnimatedSprite = function (_core$Sprite) { + _inherits(AnimatedSprite, _core$Sprite); + + /** + * @param {PIXI.Texture[]|FrameObject[]} textures - an array of {@link PIXI.Texture} or frame + * objects that make up the animation + * @param {boolean} [autoUpdate=true] - Whether to use PIXI.ticker.shared to auto update animation time. + */ + function AnimatedSprite(textures, autoUpdate) { + _classCallCheck(this, AnimatedSprite); + + /** + * @private + */ + var _this = _possibleConstructorReturn(this, _core$Sprite.call(this, textures[0] instanceof core.Texture ? textures[0] : textures[0].texture)); + + _this._textures = null; + + /** + * @private + */ + _this._durations = null; + + _this.textures = textures; + + /** + * `true` uses PIXI.ticker.shared to auto update animation time. + * @type {boolean} + * @default true + * @private + */ + _this._autoUpdate = autoUpdate !== false; + + /** + * The speed that the AnimatedSprite will play at. Higher is faster, lower is slower + * + * @member {number} + * @default 1 + */ + _this.animationSpeed = 1; + + /** + * Whether or not the animate sprite repeats after playing. + * + * @member {boolean} + * @default true + */ + _this.loop = true; + + /** + * Function to call when a AnimatedSprite finishes playing + * + * @member {Function} + */ + _this.onComplete = null; + + /** + * Function to call when a AnimatedSprite changes which texture is being rendered + * + * @member {Function} + */ + _this.onFrameChange = null; + + /** + * Function to call when 'loop' is true, and an AnimatedSprite is played and loops around to start again + * + * @member {Function} + */ + _this.onLoop = null; + + /** + * Elapsed time since animation has been started, used internally to display current texture + * + * @member {number} + * @private + */ + _this._currentTime = 0; + + /** + * Indicates if the AnimatedSprite is currently playing + * + * @member {boolean} + * @readonly + */ + _this.playing = false; + return _this; + } + + /** + * Stops the AnimatedSprite + * + */ + + + AnimatedSprite.prototype.stop = function stop() { + if (!this.playing) { + return; + } + + this.playing = false; + if (this._autoUpdate) { + core.ticker.shared.remove(this.update, this); + } + }; + + /** + * Plays the AnimatedSprite + * + */ + + + AnimatedSprite.prototype.play = function play() { + if (this.playing) { + return; + } + + this.playing = true; + if (this._autoUpdate) { + core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.HIGH); + } + }; + + /** + * Stops the AnimatedSprite and goes to a specific frame + * + * @param {number} frameNumber - frame index to stop at + */ + + + AnimatedSprite.prototype.gotoAndStop = function gotoAndStop(frameNumber) { + this.stop(); + + var previousFrame = this.currentFrame; + + this._currentTime = frameNumber; + + if (previousFrame !== this.currentFrame) { + this.updateTexture(); + } + }; + + /** + * Goes to a specific frame and begins playing the AnimatedSprite + * + * @param {number} frameNumber - frame index to start at + */ + + + AnimatedSprite.prototype.gotoAndPlay = function gotoAndPlay(frameNumber) { + var previousFrame = this.currentFrame; + + this._currentTime = frameNumber; + + if (previousFrame !== this.currentFrame) { + this.updateTexture(); + } + + this.play(); + }; + + /** + * Updates the object transform for rendering. + * + * @private + * @param {number} deltaTime - Time since last tick. + */ + + + AnimatedSprite.prototype.update = function update(deltaTime) { + var elapsed = this.animationSpeed * deltaTime; + var previousFrame = this.currentFrame; + + if (this._durations !== null) { + var lag = this._currentTime % 1 * this._durations[this.currentFrame]; + + lag += elapsed / 60 * 1000; + + while (lag < 0) { + this._currentTime--; + lag += this._durations[this.currentFrame]; + } + + var sign = Math.sign(this.animationSpeed * deltaTime); + + this._currentTime = Math.floor(this._currentTime); + + while (lag >= this._durations[this.currentFrame]) { + lag -= this._durations[this.currentFrame] * sign; + this._currentTime += sign; + } + + this._currentTime += lag / this._durations[this.currentFrame]; + } else { + this._currentTime += elapsed; + } + + if (this._currentTime < 0 && !this.loop) { + this.gotoAndStop(0); + + if (this.onComplete) { + this.onComplete(); + } + } else if (this._currentTime >= this._textures.length && !this.loop) { + this.gotoAndStop(this._textures.length - 1); + + if (this.onComplete) { + this.onComplete(); + } + } else if (previousFrame !== this.currentFrame) { + if (this.loop && this.onLoop) { + if (this.animationSpeed > 0 && this.currentFrame < previousFrame) { + this.onLoop(); + } else if (this.animationSpeed < 0 && this.currentFrame > previousFrame) { + this.onLoop(); + } + } + + this.updateTexture(); + } + }; + + /** + * Updates the displayed texture to match the current frame index + * + * @private + */ + + + AnimatedSprite.prototype.updateTexture = function updateTexture() { + this._texture = this._textures[this.currentFrame]; + this._textureID = -1; + + if (this.onFrameChange) { + this.onFrameChange(this.currentFrame); + } + }; + + /** + * Stops the AnimatedSprite and destroys it + * + * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options + * have been set to that value + * @param {boolean} [options.children=false] - if set to true, all the children will have their destroy + * method called as well. 'options' will be passed on to those calls. + * @param {boolean} [options.texture=false] - Should it destroy the current texture of the sprite as well + * @param {boolean} [options.baseTexture=false] - Should it destroy the base texture of the sprite as well + */ + + + AnimatedSprite.prototype.destroy = function destroy(options) { + this.stop(); + _core$Sprite.prototype.destroy.call(this, options); + }; + + /** + * A short hand way of creating a movieclip from an array of frame ids + * + * @static + * @param {string[]} frames - The array of frames ids the movieclip will use as its texture frames + * @return {AnimatedSprite} The new animated sprite with the specified frames. + */ + + + AnimatedSprite.fromFrames = function fromFrames(frames) { + var textures = []; + + for (var i = 0; i < frames.length; ++i) { + textures.push(core.Texture.fromFrame(frames[i])); + } + + return new AnimatedSprite(textures); + }; + + /** + * A short hand way of creating a movieclip from an array of image ids + * + * @static + * @param {string[]} images - the array of image urls the movieclip will use as its texture frames + * @return {AnimatedSprite} The new animate sprite with the specified images as frames. + */ + + + AnimatedSprite.fromImages = function fromImages(images) { + var textures = []; + + for (var i = 0; i < images.length; ++i) { + textures.push(core.Texture.fromImage(images[i])); + } + + return new AnimatedSprite(textures); + }; + + /** + * totalFrames is the total number of frames in the AnimatedSprite. This is the same as number of textures + * assigned to the AnimatedSprite. + * + * @readonly + * @member {number} + * @default 0 + */ + + + _createClass(AnimatedSprite, [{ + key: 'totalFrames', + get: function get() { + return this._textures.length; + } + + /** + * The array of textures used for this AnimatedSprite + * + * @member {PIXI.Texture[]} + */ + + }, { + key: 'textures', + get: function get() { + return this._textures; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { + if (value[0] instanceof core.Texture) { + this._textures = value; + this._durations = null; + } else { + this._textures = []; + this._durations = []; + + for (var i = 0; i < value.length; i++) { + this._textures.push(value[i].texture); + this._durations.push(value[i].time); + } + } + this.gotoAndStop(0); + this.updateTexture(); + } + + /** + * The AnimatedSprites current frame index + * + * @member {number} + * @readonly + */ + + }, { + key: 'currentFrame', + get: function get() { + var currentFrame = Math.floor(this._currentTime) % this._textures.length; + + if (currentFrame < 0) { + currentFrame += this._textures.length; + } + + return currentFrame; + } + }]); + + return AnimatedSprite; +}(core.Sprite); + +exports.default = AnimatedSprite; + +},{"../core":65}],135:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -25770,6 +30098,10 @@ var _ObservablePoint = require('../core/math/ObservablePoint'); var _ObservablePoint2 = _interopRequireDefault(_ObservablePoint); +var _settings = require('../core/settings'); + +var _settings2 = _interopRequireDefault(_settings); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } @@ -25818,24 +30150,22 @@ var BitmapText = function (_core$Container) { _classCallCheck(this, BitmapText); /** - * The width of the overall text, different from fontSize, - * which is defined in the style object + * Private tracker for the width of the overall text * * @member {number} - * @readonly + * @private */ var _this = _possibleConstructorReturn(this, _core$Container.call(this)); - _this.textWidth = 0; + _this._textWidth = 0; /** - * The height of the overall text, different from fontSize, - * which is defined in the style object + * Private tracker for the height of the overall text * * @member {number} - * @readonly + * @private */ - _this.textHeight = 0; + _this._textHeight = 0; /** * Private tracker for the letter sprite pool. @@ -25880,16 +30210,18 @@ var BitmapText = function (_core$Container) { * Disable by setting value to 0 * * @member {number} + * @private */ - _this.maxWidth = 0; + _this._maxWidth = 0; /** * The max line height. This is useful when trying to use the total height of the Text, * ie: when trying to vertically align. * * @member {number} + * @private */ - _this.maxLineHeight = 0; + _this._maxLineHeight = 0; /** * Text anchor. read-only @@ -25932,6 +30264,7 @@ var BitmapText = function (_core$Container) { var line = 0; var lastSpace = -1; var lastSpaceWidth = 0; + var spacesRemoved = 0; var maxLineHeight = 0; for (var i = 0; i < this.text.length; i++) { @@ -25953,10 +30286,11 @@ var BitmapText = function (_core$Container) { continue; } - if (lastSpace !== -1 && this.maxWidth > 0 && pos.x * scale > this.maxWidth) { - core.utils.removeItems(chars, lastSpace, i - lastSpace); + if (lastSpace !== -1 && this._maxWidth > 0 && pos.x * scale > this._maxWidth) { + core.utils.removeItems(chars, lastSpace - spacesRemoved, i - lastSpace); i = lastSpace; lastSpace = -1; + ++spacesRemoved; lineWidths.push(lastSpaceWidth); maxLineWidth = Math.max(maxLineWidth, lastSpaceWidth); @@ -26035,17 +30369,17 @@ var BitmapText = function (_core$Container) { this.removeChild(this._glyphs[_i3]); } - this.textWidth = maxLineWidth * scale; - this.textHeight = (pos.y + data.lineHeight) * scale; + this._textWidth = maxLineWidth * scale; + this._textHeight = (pos.y + data.lineHeight) * scale; // apply anchor if (this.anchor.x !== 0 || this.anchor.y !== 0) { for (var _i4 = 0; _i4 < lenChars; _i4++) { - this._glyphs[_i4].x -= this.textWidth * this.anchor.x; - this._glyphs[_i4].y -= this.textHeight * this.anchor.y; + this._glyphs[_i4].x -= this._textWidth * this.anchor.x; + this._glyphs[_i4].y -= this._textHeight * this.anchor.y; } } - this.maxLineHeight = maxLineHeight * scale; + this._maxLineHeight = maxLineHeight * scale; }; /** @@ -26091,23 +30425,75 @@ var BitmapText = function (_core$Container) { * The tint of the BitmapText object * * @member {number} - * @memberof PIXI.extras.BitmapText# */ + /** + * Register a bitmap font with data and a texture. + * + * @static + * @param {XMLDocument} xml - The XML document data. + * @param {PIXI.Texture} texture - Texture with all symbols. + * @return {Object} Result font object with font, size, lineHeight and char fields. + */ + BitmapText.registerFont = function registerFont(xml, texture) { + var data = {}; + var info = xml.getElementsByTagName('info')[0]; + var common = xml.getElementsByTagName('common')[0]; + var res = texture.baseTexture.resolution || _settings2.default.RESOLUTION; + + data.font = info.getAttribute('face'); + data.size = parseInt(info.getAttribute('size'), 10); + data.lineHeight = parseInt(common.getAttribute('lineHeight'), 10) / res; + data.chars = {}; + + // parse letters + var letters = xml.getElementsByTagName('char'); + + for (var i = 0; i < letters.length; i++) { + var letter = letters[i]; + var charCode = parseInt(letter.getAttribute('id'), 10); + + var textureRect = new core.Rectangle(parseInt(letter.getAttribute('x'), 10) / res + texture.frame.x / res, parseInt(letter.getAttribute('y'), 10) / res + texture.frame.y / res, parseInt(letter.getAttribute('width'), 10) / res, parseInt(letter.getAttribute('height'), 10) / res); + + data.chars[charCode] = { + xOffset: parseInt(letter.getAttribute('xoffset'), 10) / res, + yOffset: parseInt(letter.getAttribute('yoffset'), 10) / res, + xAdvance: parseInt(letter.getAttribute('xadvance'), 10) / res, + kerning: {}, + texture: new core.Texture(texture.baseTexture, textureRect) + + }; + } + + // parse kernings + var kernings = xml.getElementsByTagName('kerning'); + + for (var _i5 = 0; _i5 < kernings.length; _i5++) { + var kerning = kernings[_i5]; + var first = parseInt(kerning.getAttribute('first'), 10) / res; + var second = parseInt(kerning.getAttribute('second'), 10) / res; + var amount = parseInt(kerning.getAttribute('amount'), 10) / res; + + if (data.chars[second]) { + data.chars[second].kerning[first] = amount; + } + } + + // I'm leaving this as a temporary fix so we can test the bitmap fonts in v3 + // but it's very likely to change + BitmapText.fonts[data.font] = data; + + return data; + }; + _createClass(BitmapText, [{ key: 'tint', get: function get() { return this._font.tint; - } - - /** - * Sets the tint. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._font.tint = typeof value === 'number' && value >= 0 ? value : 0xFFFFFF; this.dirty = true; @@ -26118,22 +30504,15 @@ var BitmapText = function (_core$Container) { * * @member {string} * @default 'left' - * @memberof PIXI.extras.BitmapText# */ }, { key: 'align', get: function get() { return this._font.align; - } - - /** - * Sets the alignment - * - * @param {string} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._font.align = value || 'left'; this.dirty = true; @@ -26146,22 +30525,15 @@ var BitmapText = function (_core$Container) { * Setting the anchor to 1,1 would mean the text's origin point will be the bottom right corner * * @member {PIXI.Point | number} - * @memberof PIXI.extras.BitmapText# */ }, { key: 'anchor', get: function get() { return this._anchor; - } - - /** - * Sets the anchor. - * - * @param {PIXI.Point|number} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { if (typeof value === 'number') { this._anchor.set(value); } else { @@ -26173,22 +30545,15 @@ var BitmapText = function (_core$Container) { * The font descriptor of the BitmapText object * * @member {string|object} - * @memberof PIXI.extras.BitmapText# */ }, { key: 'font', get: function get() { return this._font; - } - - /** - * Sets the font. - * - * @param {string|object} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { if (!value) { return; } @@ -26210,22 +30575,15 @@ var BitmapText = function (_core$Container) { * The text of the BitmapText object * * @member {string} - * @memberof PIXI.extras.BitmapText# */ }, { key: 'text', get: function get() { return this._text; - } - - /** - * Sets the text. - * - * @param {string} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { value = value.toString() || ' '; if (this._text === value) { return; @@ -26233,388 +30591,87 @@ var BitmapText = function (_core$Container) { this._text = value; this.dirty = true; } - }]); - - return BitmapText; -}(core.Container); - -exports.default = BitmapText; - - -BitmapText.fonts = {}; - -},{"../core":61,"../core/math/ObservablePoint":64}],123:[function(require,module,exports){ -'use strict'; - -exports.__esModule = true; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _core = require('../core'); - -var core = _interopRequireWildcard(_core); - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -/** - * @typedef FrameObject - * @type {object} - * @property {PIXI.Texture} texture - The {@link PIXI.Texture} of the frame - * @property {number} time - the duration of the frame in ms - */ - -/** - * A MovieClip is a simple way to display an animation depicted by a list of textures. - * - * ```js - * let alienImages = ["image_sequence_01.png","image_sequence_02.png","image_sequence_03.png","image_sequence_04.png"]; - * let textureArray = []; - * - * for (let i=0; i < 4; i++) - * { - * let texture = PIXI.Texture.fromImage(alienImages[i]); - * textureArray.push(texture); - * }; - * - * let mc = new PIXI.MovieClip(textureArray); - * ``` - * - * @class - * @extends PIXI.Sprite - * @memberof PIXI.extras - */ -var MovieClip = function (_core$Sprite) { - _inherits(MovieClip, _core$Sprite); - - /** - * @param {PIXI.Texture[]|FrameObject[]} textures - an array of {@link PIXI.Texture} or frame - * objects that make up the animation - */ - function MovieClip(textures) { - _classCallCheck(this, MovieClip); - - /** - * @private - */ - var _this = _possibleConstructorReturn(this, _core$Sprite.call(this, textures[0] instanceof core.Texture ? textures[0] : textures[0].texture)); - - _this._textures = null; - - /** - * @private - */ - _this._durations = null; - - _this.textures = textures; /** - * The speed that the MovieClip will play at. Higher is faster, lower is slower + * The max width of this bitmap text in pixels. If the text provided is longer than the + * value provided, line breaks will be automatically inserted in the last whitespace. + * Disable by setting value to 0 * * @member {number} - * @default 1 - */ - _this.animationSpeed = 1; - - /** - * Whether or not the movie clip repeats after playing. - * - * @member {boolean} - * @default true */ - _this.loop = true; - /** - * Function to call when a MovieClip finishes playing - * - * @method - * @memberof PIXI.extras.MovieClip# - */ - _this.onComplete = null; - - /** - * Function to call when a MovieClip changes which texture is being rendered - * - * @method - * @memberof PIXI.extras.MovieClip# - */ - _this.onFrameChange = null; + }, { + key: 'maxWidth', + get: function get() { + return this._maxWidth; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { + if (this._maxWidth === value) { + return; + } + this._maxWidth = value; + this.dirty = true; + } /** - * Elapsed time since animation has been started, used internally to display current texture + * The max line height. This is useful when trying to use the total height of the Text, + * ie: when trying to vertically align. * * @member {number} - * @private - */ - _this._currentTime = 0; - - /** - * Indicates if the MovieClip is currently playing - * - * @member {boolean} * @readonly */ - _this.playing = false; - return _this; - } - - /** - * Stops the MovieClip - * - */ - - - MovieClip.prototype.stop = function stop() { - if (!this.playing) { - return; - } - - this.playing = false; - core.ticker.shared.remove(this.update, this); - }; - - /** - * Plays the MovieClip - * - */ - - - MovieClip.prototype.play = function play() { - if (this.playing) { - return; - } - - this.playing = true; - core.ticker.shared.add(this.update, this); - }; - - /** - * Stops the MovieClip and goes to a specific frame - * - * @param {number} frameNumber - frame index to stop at - */ - - - MovieClip.prototype.gotoAndStop = function gotoAndStop(frameNumber) { - this.stop(); - - var previousFrame = this.currentFrame; - - this._currentTime = frameNumber; - - if (previousFrame !== this.currentFrame) { - this._texture = this._textures[this.currentFrame]; - this._textureID = -1; - - if (this.onFrameChange) { - this.onFrameChange(this.currentFrame); - } - } - }; - - /** - * Goes to a specific frame and begins playing the MovieClip - * - * @param {number} frameNumber - frame index to start at - */ - - - MovieClip.prototype.gotoAndPlay = function gotoAndPlay(frameNumber) { - this._currentTime = frameNumber; - - this.play(); - }; - - /** - * Updates the object transform for rendering. - * - * @private - * @param {number} deltaTime - Time since last tick. - */ - - - MovieClip.prototype.update = function update(deltaTime) { - var elapsed = this.animationSpeed * deltaTime; - var previousFrame = this.currentFrame; - - if (this._durations !== null) { - var lag = this._currentTime % 1 * this._durations[this.currentFrame]; - - lag += elapsed / 60 * 1000; - - while (lag < 0) { - this._currentTime--; - lag += this._durations[this.currentFrame]; - } - - var sign = Math.sign(this.animationSpeed * deltaTime); - - this._currentTime = Math.floor(this._currentTime); - - while (lag >= this._durations[this.currentFrame]) { - lag -= this._durations[this.currentFrame] * sign; - this._currentTime += sign; - } - - this._currentTime += lag / this._durations[this.currentFrame]; - } else { - this._currentTime += elapsed; - } - - if (this._currentTime < 0 && !this.loop) { - this.gotoAndStop(0); - - if (this.onComplete) { - this.onComplete(); - } - } else if (this._currentTime >= this._textures.length && !this.loop) { - this.gotoAndStop(this._textures.length - 1); - - if (this.onComplete) { - this.onComplete(); - } - } else if (previousFrame !== this.currentFrame) { - this._texture = this._textures[this.currentFrame]; - this._textureID = -1; - - if (this.onFrameChange) { - this.onFrameChange(this.currentFrame); - } - } - }; - - /** - * Stops the MovieClip and destroys it - * - */ - - - MovieClip.prototype.destroy = function destroy() { - this.stop(); - _core$Sprite.prototype.destroy.call(this); - }; - - /** - * A short hand way of creating a movieclip from an array of frame ids - * - * @static - * @param {string[]} frames - The array of frames ids the movieclip will use as its texture frames - * @return {MovieClip} The new movie clip with the specified frames. - */ - - - MovieClip.fromFrames = function fromFrames(frames) { - var textures = []; - for (var i = 0; i < frames.length; ++i) { - textures.push(core.Texture.fromFrame(frames[i])); - } - - return new MovieClip(textures); - }; - - /** - * A short hand way of creating a movieclip from an array of image ids - * - * @static - * @param {string[]} images - the array of image urls the movieclip will use as its texture frames - * @return {MovieClip} The new movie clip with the specified images as frames. - */ - - - MovieClip.fromImages = function fromImages(images) { - var textures = []; - - for (var i = 0; i < images.length; ++i) { - textures.push(core.Texture.fromImage(images[i])); - } - - return new MovieClip(textures); - }; - - /** - * totalFrames is the total number of frames in the MovieClip. This is the same as number of textures - * assigned to the MovieClip. - * - * @readonly - * @member {number} - * @memberof PIXI.extras.MovieClip# - * @default 0 - */ - - - _createClass(MovieClip, [{ - key: 'totalFrames', + }, { + key: 'maxLineHeight', get: function get() { - return this._textures.length; + this.validate(); + + return this._maxLineHeight; } /** - * The array of textures used for this MovieClip + * The width of the overall text, different from fontSize, + * which is defined in the style object * - * @member {PIXI.Texture[]} - * @memberof PIXI.extras.MovieClip# + * @member {number} + * @readonly */ }, { - key: 'textures', + key: 'textWidth', get: function get() { - return this._textures; + this.validate(); + + return this._textWidth; } /** - * Sets the textures. + * The height of the overall text, different from fontSize, + * which is defined in the style object * - * @param {PIXI.Texture[]} value - The texture to set. + * @member {number} + * @readonly */ - , - set: function set(value) { - if (value[0] instanceof core.Texture) { - this._textures = value; - this._durations = null; - } else { - this._textures = []; - this._durations = []; - - for (var i = 0; i < value.length; i++) { - this._textures.push(value[i].texture); - this._durations.push(value[i].time); - } - } - } - - /** - * The MovieClips current frame index - * - * @member {number} - * @memberof PIXI.extras.MovieClip# - * @readonly - */ }, { - key: 'currentFrame', + key: 'textHeight', get: function get() { - var currentFrame = Math.floor(this._currentTime) % this._textures.length; - - if (currentFrame < 0) { - currentFrame += this._textures.length; - } + this.validate(); - return currentFrame; + return this._textHeight; } }]); - return MovieClip; -}(core.Sprite); + return BitmapText; +}(core.Container); + +exports.default = BitmapText; -exports.default = MovieClip; -},{"../core":61}],124:[function(require,module,exports){ +BitmapText.fonts = {}; + +},{"../core":65,"../core/math/ObservablePoint":68,"../core/settings":101}],136:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -26633,6 +30690,9 @@ var tempMat = new _Matrix2.default(); /** * class controls uv transform and frame clamp for texture + * + * @class + * @memberof PIXI.extras */ var TextureTransform = function () { @@ -26658,7 +30718,7 @@ var TextureTransform = function () { /** * Changes frame clamping * Works with TilingSprite and Mesh - * Change to 1.5 if you tex ture has repeated right and bottom lines, that leads to smoother borders + * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders * * @default 0 * @member {number} @@ -26679,28 +30739,54 @@ var TextureTransform = function () { /** * texture property * @member {PIXI.Texture} - * @memberof PIXI.TextureTransform */ + /** + * Multiplies uvs array to transform + * @param {Float32Array} uvs mesh uvs + * @param {Float32Array} [out=uvs] output + * @returns {Float32Array} output + */ + TextureTransform.prototype.multiplyUvs = function multiplyUvs(uvs, out) { + if (out === undefined) { + out = uvs; + } + + var mat = this.mapCoord; + + for (var i = 0; i < uvs.length; i += 2) { + var x = uvs[i]; + var y = uvs[i + 1]; + + out[i] = x * mat.a + y * mat.c + mat.tx; + out[i + 1] = x * mat.b + y * mat.d + mat.ty; + } + + return out; + }; + /** * updates matrices if texture was changed * @param {boolean} forceUpdate if true, matrices will be updated any case + * @returns {boolean} whether or not it was updated */ + + TextureTransform.prototype.update = function update(forceUpdate) { - var tex = this.texture; + var tex = this._texture; if (!tex || !tex.valid) { - return; + return false; } - if (!forceUpdate && this._lastTextureID === this.texture._updateID) { - return; + if (!forceUpdate && this._lastTextureID === tex._updateID) { + return false; } - this._lastTextureID = this.texture._updateID; + this._lastTextureID = tex._updateID; - var uvs = this.texture._uvs; + var uvs = tex._uvs; this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0); @@ -26723,20 +30809,17 @@ var TextureTransform = function () { frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height; this.uClampOffset[0] = offset / texBase.realWidth; this.uClampOffset[1] = offset / texBase.realHeight; + + return true; }; _createClass(TextureTransform, [{ key: 'texture', get: function get() { return this._texture; - } - - /** - * sets texture value - * @param {PIXI.Texture} value texture to be set - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._texture = value; this._lastTextureID = -1; } @@ -26747,7 +30830,7 @@ var TextureTransform = function () { exports.default = TextureTransform; -},{"../core/math/Matrix":63}],125:[function(require,module,exports){ +},{"../core/math/Matrix":67}],137:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -26841,6 +30924,23 @@ var TilingSprite = function (_core$Sprite) { * @member {PIXI.extras.TextureTransform} */ _this.uvTransform = texture.transform || new _TextureTransform2.default(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + _this.pluginName = 'tilingSprite'; + + /** + * Whether or not anchor affects uvs + * + * @member {boolean} + * @default false + */ + _this.uvRespectAnchor = false; return _this; } /** @@ -26849,7 +30949,6 @@ var TilingSprite = function (_core$Sprite) { * * @default 0.5 * @member {number} - * @memberof PIXI.TilingSprite */ @@ -26881,8 +30980,8 @@ var TilingSprite = function (_core$Sprite) { this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); }; /** @@ -26904,14 +31003,15 @@ var TilingSprite = function (_core$Sprite) { var transform = this.worldTransform; var resolution = renderer.resolution; var baseTexture = texture.baseTexture; - var modX = this.tilePosition.x / this.tileScale.x % texture._frame.width; - var modY = this.tilePosition.y / this.tileScale.y % texture._frame.height; + var baseTextureResolution = baseTexture.resolution; + var modX = this.tilePosition.x / this.tileScale.x % texture._frame.width * baseTextureResolution; + var modY = this.tilePosition.y / this.tileScale.y % texture._frame.height * baseTextureResolution; // create a nice shiny pattern! // TODO this needs to be refreshed if texture changes.. if (!this._canvasPattern) { // cut an object from a spritesheet.. - var tempCanvas = new core.CanvasRenderTarget(texture._frame.width, texture._frame.height); + var tempCanvas = new core.CanvasRenderTarget(texture._frame.width, texture._frame.height, baseTextureResolution); // Tint the tiling sprite if (this.tint !== 0xFFFFFF) { @@ -26922,7 +31022,7 @@ var TilingSprite = function (_core$Sprite) { } tempCanvas.context.drawImage(this.tintedTexture, 0, 0); } else { - tempCanvas.context.drawImage(baseTexture.source, -texture._frame.x, -texture._frame.y); + tempCanvas.context.drawImage(baseTexture.source, -texture._frame.x * baseTextureResolution, -texture._frame.y * baseTextureResolution); } this._canvasPattern = tempCanvas.context.createPattern(tempCanvas.canvas, 'repeat'); } @@ -26931,21 +31031,26 @@ var TilingSprite = function (_core$Sprite) { context.globalAlpha = this.worldAlpha; context.setTransform(transform.a * resolution, transform.b * resolution, transform.c * resolution, transform.d * resolution, transform.tx * resolution, transform.ty * resolution); + renderer.setBlendMode(this.blendMode); + + // fill the pattern! + context.fillStyle = this._canvasPattern; + // TODO - this should be rolled into the setTransform above.. - context.scale(this.tileScale.x, this.tileScale.y); + context.scale(this.tileScale.x / baseTextureResolution, this.tileScale.y / baseTextureResolution); - context.translate(modX + this.anchor.x * -this._width, modY + this.anchor.y * -this._height); + var anchorX = this.anchor.x * -this._width; + var anchorY = this.anchor.y * -this._height; - // check blend mode - var compositeOperation = renderer.blendModes[this.blendMode]; + if (this.uvRespectAnchor) { + context.translate(modX, modY); - if (compositeOperation !== renderer.context.globalCompositeOperation) { - context.globalCompositeOperation = compositeOperation; - } + context.fillRect(-modX + anchorX, -modY + anchorY, this._width / this.tileScale.x * baseTextureResolution, this._height / this.tileScale.y * baseTextureResolution); + } else { + context.translate(modX + anchorX, modY + anchorY); - // fill the pattern! - context.fillStyle = this._canvasPattern; - context.fillRect(-modX, -modY, this._width / this.tileScale.x, this._height / this.tileScale.y); + context.fillRect(-modX, -modY, this._width / this.tileScale.x * baseTextureResolution, this._height / this.tileScale.y * baseTextureResolution); + } }; /** @@ -26956,16 +31061,16 @@ var TilingSprite = function (_core$Sprite) { TilingSprite.prototype._calculateBounds = function _calculateBounds() { - var minX = -this._width * this.anchor._x; - var minY = -this._height * this.anchor._y; - var maxX = this._width; - var maxY = this._height; + var minX = this._width * -this._anchor._x; + var minY = this._height * -this._anchor._y; + var maxX = this._width * (1 - this._anchor._x); + var maxY = this._height * (1 - this._anchor._y); this._bounds.addFrame(this.transform, minX, minY, maxX, maxY); }; /** - * Gets the local bounds of the tiling sprite object. + * Gets the local bounds of the sprite object. * * @param {PIXI.Rectangle} rect - The output rectangle. * @return {PIXI.Rectangle} The bounds. @@ -26975,10 +31080,10 @@ var TilingSprite = function (_core$Sprite) { TilingSprite.prototype.getLocalBounds = function getLocalBounds(rect) { // we can do a fast local bounds if the sprite has no children! if (this.children.length === 0) { - this._bounds.minX = -this._width * this.anchor._x; - this._bounds.minY = -this._height * this.anchor._y; - this._bounds.maxX = this._width; - this._bounds.maxY = this._height; + this._bounds.minX = this._width * -this._anchor._x; + this._bounds.minY = this._height * -this._anchor._y; + this._bounds.maxX = this._width * (1 - this._anchor._x); + this._bounds.maxY = this._height * (1 - this._anchor._x); if (!rect) { if (!this._localBoundsRect) { @@ -27007,12 +31112,12 @@ var TilingSprite = function (_core$Sprite) { var width = this._width; var height = this._height; - var x1 = -width * this.anchor.x; + var x1 = -width * this.anchor._x; - if (tempPoint.x > x1 && tempPoint.x < x1 + width) { - var y1 = -height * this.anchor.y; + if (tempPoint.x >= x1 && tempPoint.x < x1 + width) { + var y1 = -height * this.anchor._y; - if (tempPoint.y > y1 && tempPoint.y < y1 + height) { + if (tempPoint.y >= y1 && tempPoint.y < y1 + height) { return true; } } @@ -27021,16 +31126,22 @@ var TilingSprite = function (_core$Sprite) { }; /** - * Destroys this tiling sprite + * Destroys this sprite and optionally its texture and children * + * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options + * have been set to that value + * @param {boolean} [options.children=false] - if set to true, all the children will have their destroy + * method called as well. 'options' will be passed on to those calls. + * @param {boolean} [options.texture=false] - Should it destroy the current texture of the sprite as well + * @param {boolean} [options.baseTexture=false] - Should it destroy the base texture of the sprite as well */ - TilingSprite.prototype.destroy = function destroy() { - _core$Sprite.prototype.destroy.call(this); + TilingSprite.prototype.destroy = function destroy(options) { + _core$Sprite.prototype.destroy.call(this, options); - this.tileScale = null; - this.tilePosition = null; + this.tileTransform = null; + this.uvTransform = null; }; /** @@ -27080,7 +31191,7 @@ var TilingSprite = function (_core$Sprite) { * @param {number} width - the width of the tiling sprite * @param {number} height - the height of the tiling sprite * @param {boolean} [crossorigin] - if you want to specify the cross-origin parameter - * @param {number} [scaleMode=PIXI.SCALE_MODES.DEFAULT] - if you want to specify the scale mode, + * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - if you want to specify the scale mode, * see {@link PIXI.SCALE_MODES} for possible values * @return {PIXI.extras.TilingSprite} A new TilingSprite using a texture from the texture cache matching the image id */ @@ -27094,7 +31205,6 @@ var TilingSprite = function (_core$Sprite) { * The width of the sprite, setting this will actually modify the scale to achieve the value set * * @member {number} - * @memberof PIXI.extras.TilingSprite# */ @@ -27102,15 +31212,9 @@ var TilingSprite = function (_core$Sprite) { key: 'clampMargin', get: function get() { return this.uvTransform.clampMargin; - } - - /** - * setter for clampMargin - * - * @param {number} value assigned value - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.uvTransform.clampMargin = value; this.uvTransform.update(true); } @@ -27119,22 +31223,15 @@ var TilingSprite = function (_core$Sprite) { * The scaling of the image that is being tiled * * @member {PIXI.ObservablePoint} - * @memberof PIXI.DisplayObject# */ }, { key: 'tileScale', get: function get() { return this.tileTransform.scale; - } - - /** - * Copies the point to the scale of the tiled image. - * - * @param {PIXI.Point|PIXI.ObservablePoint} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.tileTransform.scale.copy(value); } @@ -27142,37 +31239,24 @@ var TilingSprite = function (_core$Sprite) { * The offset of the image that is being tiled * * @member {PIXI.ObservablePoint} - * @memberof PIXI.TilingSprite# */ }, { key: 'tilePosition', get: function get() { return this.tileTransform.position; - } - - /** - * Copies the point to the position of the tiled image. - * - * @param {PIXI.Point|PIXI.ObservablePoint} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.tileTransform.position.copy(value); } }, { key: 'width', get: function get() { return this._width; - } - - /** - * Sets the width. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._width = value; } @@ -27180,22 +31264,15 @@ var TilingSprite = function (_core$Sprite) { * The height of the TilingSprite, setting this will actually modify the scale to achieve the value set * * @member {number} - * @memberof PIXI.extras.TilingSprite# */ }, { key: 'height', get: function get() { return this._height; - } - - /** - * Sets the width. - * - * @param {number} value - The value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._height = value; } }]); @@ -27205,13 +31282,25 @@ var TilingSprite = function (_core$Sprite) { exports.default = TilingSprite; -},{"../core":61,"../core/sprites/canvas/CanvasTinter":99,"./TextureTransform":124}],126:[function(require,module,exports){ +},{"../core":65,"../core/sprites/canvas/CanvasTinter":104,"./TextureTransform":136}],138:[function(require,module,exports){ 'use strict'; var _core = require('../core'); var core = _interopRequireWildcard(_core); +var _Texture = require('../core/textures/Texture'); + +var _Texture2 = _interopRequireDefault(_Texture); + +var _BaseTexture = require('../core/textures/BaseTexture'); + +var _BaseTexture2 = _interopRequireDefault(_BaseTexture); + +var _utils = require('../core/utils'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -27237,6 +31326,8 @@ var CacheData = function CacheData() { _classCallCheck(this, CacheData); + this.textureCacheId = null; + this.originalRenderWebGL = null; this.originalRenderCanvas = null; this.originalCalculateBounds = null; @@ -27257,6 +31348,9 @@ Object.defineProperties(DisplayObject.prototype, { * provide a performance benefit for complex static displayObjects. * To remove simply set this property to 'false' * + * IMPORTANT GOTCHA - make sure that all your textures are preloaded BEFORE setting this property to true + * as it will take a snapshot of what is currently there. If the textures have not loaded then they will not appear. + * * @member {boolean} * @memberof PIXI.DisplayObject# */ @@ -27385,6 +31479,13 @@ DisplayObject.prototype._initCachedDisplayObject = function _initCachedDisplayOb var renderTexture = core.RenderTexture.create(bounds.width | 0, bounds.height | 0); + var textureCacheId = 'cacheAsBitmap_' + (0, _utils.uid)(); + + this._cacheData.textureCacheId = textureCacheId; + + _BaseTexture2.default.addToCache(renderTexture.baseTexture, textureCacheId); + _Texture2.default.addToCache(renderTexture, textureCacheId); + // need to set // var m = _tempMatrix; @@ -27427,7 +31528,13 @@ DisplayObject.prototype._initCachedDisplayObject = function _initCachedDisplayOb this.transform._parentID = -1; // restore the transform of the cached sprite to avoid the nasty flicker.. - this.updateTransform(); + if (!this.parent) { + this.parent = renderer._tempDisplayObjectParent; + this.updateTransform(); + this.parent = null; + } else { + this.updateTransform(); + } // map the hit test.. this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite); @@ -27476,10 +31583,17 @@ DisplayObject.prototype._initCachedDisplayObjectCanvas = function _initCachedDis var renderTexture = core.RenderTexture.create(bounds.width | 0, bounds.height | 0); + var textureCacheId = 'cacheAsBitmap_' + (0, _utils.uid)(); + + this._cacheData.textureCacheId = textureCacheId; + + _BaseTexture2.default.addToCache(renderTexture.baseTexture, textureCacheId); + _Texture2.default.addToCache(renderTexture, textureCacheId); + // need to set // var m = _tempMatrix; - this.transform.worldTransform.copy(m); + this.transform.localTransform.copy(m); m.invert(); m.tx -= bounds.x; @@ -27510,7 +31624,14 @@ DisplayObject.prototype._initCachedDisplayObjectCanvas = function _initCachedDis cachedSprite._bounds = this._bounds; cachedSprite.alpha = cacheAlpha; - this.updateTransform(); + if (!this.parent) { + this.parent = renderer._tempDisplayObjectParent; + this.updateTransform(); + this.parent = null; + } else { + this.updateTransform(); + } + this.updateTransform = this.displayObjectUpdateTransform; this._cacheData.sprite = cachedSprite; @@ -27545,19 +31666,27 @@ DisplayObject.prototype._getCachedLocalBounds = function _getCachedLocalBounds() DisplayObject.prototype._destroyCachedDisplayObject = function _destroyCachedDisplayObject() { this._cacheData.sprite._texture.destroy(true); this._cacheData.sprite = null; + + _BaseTexture2.default.removeFromCache(this._cacheData.textureCacheId); + _Texture2.default.removeFromCache(this._cacheData.textureCacheId); + + this._cacheData.textureCacheId = null; }; /** * Destroys the cached object. * * @private + * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options + * have been set to that value. + * Used when destroying containers, see the Container.destroy method. */ -DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy() { +DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options) { this.cacheAsBitmap = false; - this.destroy(); + this.destroy(options); }; -},{"../core":61}],127:[function(require,module,exports){ +},{"../core":65,"../core/textures/BaseTexture":112,"../core/textures/Texture":115,"../core/utils":124}],139:[function(require,module,exports){ 'use strict'; var _core = require('../core'); @@ -27591,7 +31720,7 @@ core.Container.prototype.getChildByName = function getChildByName(name) { return null; }; -},{"../core":61}],128:[function(require,module,exports){ +},{"../core":65}],140:[function(require,module,exports){ 'use strict'; var _core = require('../core'); @@ -27624,26 +31753,27 @@ core.DisplayObject.prototype.getGlobalPosition = function getGlobalPosition() { return point; }; -},{"../core":61}],129:[function(require,module,exports){ +},{"../core":65}],141:[function(require,module,exports){ 'use strict'; exports.__esModule = true; +exports.BitmapText = exports.TilingSpriteRenderer = exports.TilingSprite = exports.TextureTransform = exports.AnimatedSprite = undefined; -var _TextureTransform = require('./TextureTransform'); +var _AnimatedSprite = require('./AnimatedSprite'); -Object.defineProperty(exports, 'TextureTransform', { +Object.defineProperty(exports, 'AnimatedSprite', { enumerable: true, get: function get() { - return _interopRequireDefault(_TextureTransform).default; + return _interopRequireDefault(_AnimatedSprite).default; } }); -var _MovieClip = require('./MovieClip'); +var _TextureTransform = require('./TextureTransform'); -Object.defineProperty(exports, 'MovieClip', { +Object.defineProperty(exports, 'TextureTransform', { enumerable: true, get: function get() { - return _interopRequireDefault(_MovieClip).default; + return _interopRequireDefault(_TextureTransform).default; } }); @@ -27674,40 +31804,20 @@ Object.defineProperty(exports, 'BitmapText', { } }); -var _cacheAsBitmap = require('./cacheAsBitmap'); - -Object.defineProperty(exports, 'cacheAsBitmap', { - enumerable: true, - get: function get() { - return _interopRequireDefault(_cacheAsBitmap).default; - } -}); - -var _getChildByName = require('./getChildByName'); - -Object.defineProperty(exports, 'getChildByName', { - enumerable: true, - get: function get() { - return _interopRequireDefault(_getChildByName).default; - } -}); +require('./cacheAsBitmap'); -var _getGlobalPosition = require('./getGlobalPosition'); +require('./getChildByName'); -Object.defineProperty(exports, 'getGlobalPosition', { - enumerable: true, - get: function get() { - return _interopRequireDefault(_getGlobalPosition).default; - } -}); +require('./getGlobalPosition'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -},{"./BitmapText":122,"./MovieClip":123,"./TextureTransform":124,"./TilingSprite":125,"./cacheAsBitmap":126,"./getChildByName":127,"./getGlobalPosition":128,"./webgl/TilingSpriteRenderer":130}],130:[function(require,module,exports){ +// imported for side effect of extending the prototype only, contains no exports + +},{"./AnimatedSprite":134,"./BitmapText":135,"./TextureTransform":136,"./TilingSprite":137,"./cacheAsBitmap":138,"./getChildByName":139,"./getGlobalPosition":140,"./webgl/TilingSpriteRenderer":142}],142:[function(require,module,exports){ 'use strict'; exports.__esModule = true; -exports.TilingSpriteRenderer = undefined; var _core = require('../../core'); @@ -27715,6 +31825,8 @@ var core = _interopRequireWildcard(_core); var _const = require('../../core/const'); +var _path = require('path'); + function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -27723,16 +31835,17 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - // eslint-disable-line no-undef - var tempMat = new core.Matrix(); -var tempArray = new Float32Array(4); /** * WebGL renderer plugin for tiling sprites + * + * @class + * @memberof PIXI.extras + * @extends PIXI.ObjectRenderer */ -var TilingSpriteRenderer = exports.TilingSpriteRenderer = function (_core$ObjectRenderer) { +var TilingSpriteRenderer = function (_core$ObjectRenderer) { _inherits(TilingSpriteRenderer, _core$ObjectRenderer); /** @@ -27761,10 +31874,11 @@ var TilingSpriteRenderer = exports.TilingSpriteRenderer = function (_core$Object TilingSpriteRenderer.prototype.onContextChange = function onContextChange() { var gl = this.renderer.gl; - this.shader = new core.Shader(gl, "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 projectionMatrix;\nuniform mat3 translationMatrix;\nuniform mat3 uTransform;\n\nvarying vec2 vTextureCoord;\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n\n vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;\n}\n", "#define GLSLIFY 1\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uSampler;\nuniform vec4 uColor;\nuniform mat3 uMapCoord;\nuniform vec4 uClampFrame;\nuniform vec2 uClampOffset;\n\nvoid main(void)\n{\n vec2 coord = mod(vTextureCoord - uClampOffset, vec2(1.0, 1.0)) + uClampOffset;\n coord = (uMapCoord * vec3(coord, 1.0)).xy;\n coord = clamp(coord, uClampFrame.xy, uClampFrame.zw);\n\n vec4 sample = texture2D(uSampler, coord);\n vec4 color = vec4(uColor.rgb * uColor.a, uColor.a);\n\n gl_FragColor = sample * color ;\n}\n"); - this.simpleShader = new core.Shader(gl, "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 projectionMatrix;\nuniform mat3 translationMatrix;\nuniform mat3 uTransform;\n\nvarying vec2 vTextureCoord;\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n\n vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;\n}\n", "#define GLSLIFY 1\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uSampler;\nuniform vec4 uColor;\n\nvoid main(void)\n{\n vec4 sample = texture2D(uSampler, vTextureCoord);\n vec4 color = vec4(uColor.rgb * uColor.a, uColor.a);\n gl_FragColor = sample * color;\n}\n"); + this.shader = new core.Shader(gl, 'attribute vec2 aVertexPosition;\r\nattribute vec2 aTextureCoord;\r\n\r\nuniform mat3 projectionMatrix;\r\nuniform mat3 translationMatrix;\r\nuniform mat3 uTransform;\r\n\r\nvarying vec2 vTextureCoord;\r\n\r\nvoid main(void)\r\n{\r\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\r\n\r\n vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;\r\n}\r\n', 'varying vec2 vTextureCoord;\r\n\r\nuniform sampler2D uSampler;\r\nuniform vec4 uColor;\r\nuniform mat3 uMapCoord;\r\nuniform vec4 uClampFrame;\r\nuniform vec2 uClampOffset;\r\n\r\nvoid main(void)\r\n{\r\n vec2 coord = mod(vTextureCoord - uClampOffset, vec2(1.0, 1.0)) + uClampOffset;\r\n coord = (uMapCoord * vec3(coord, 1.0)).xy;\r\n coord = clamp(coord, uClampFrame.xy, uClampFrame.zw);\r\n\r\n vec4 sample = texture2D(uSampler, coord);\r\n gl_FragColor = sample * uColor;\r\n}\r\n'); + this.simpleShader = new core.Shader(gl, 'attribute vec2 aVertexPosition;\r\nattribute vec2 aTextureCoord;\r\n\r\nuniform mat3 projectionMatrix;\r\nuniform mat3 translationMatrix;\r\nuniform mat3 uTransform;\r\n\r\nvarying vec2 vTextureCoord;\r\n\r\nvoid main(void)\r\n{\r\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\r\n\r\n vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;\r\n}\r\n', 'varying vec2 vTextureCoord;\r\n\r\nuniform sampler2D uSampler;\r\nuniform vec4 uColor;\r\n\r\nvoid main(void)\r\n{\r\n vec4 sample = texture2D(uSampler, vTextureCoord);\r\n gl_FragColor = sample * uColor;\r\n}\r\n'); - this.quad = new core.Quad(gl); + this.renderer.bindVao(null); + this.quad = new core.Quad(gl, this.renderer.state.attribState); this.quad.initVao(this.shader); }; @@ -27775,7 +31889,11 @@ var TilingSpriteRenderer = exports.TilingSpriteRenderer = function (_core$Object TilingSpriteRenderer.prototype.render = function render(ts) { + var renderer = this.renderer; var quad = this.quad; + + renderer.bindVao(quad.vao); + var vertices = quad.vertices; vertices[0] = vertices[6] = ts._width * -ts.anchor.x; @@ -27784,17 +31902,18 @@ var TilingSpriteRenderer = exports.TilingSpriteRenderer = function (_core$Object vertices[2] = vertices[4] = ts._width * (1.0 - ts.anchor.x); vertices[5] = vertices[7] = ts._height * (1.0 - ts.anchor.y); - vertices = quad.uvs; + if (ts.uvRespectAnchor) { + vertices = quad.uvs; - vertices[0] = vertices[6] = -ts.anchor.x; - vertices[1] = vertices[3] = -ts.anchor.y; + vertices[0] = vertices[6] = -ts.anchor.x; + vertices[1] = vertices[3] = -ts.anchor.y; - vertices[2] = vertices[4] = 1.0 - ts.anchor.x; - vertices[5] = vertices[7] = 1.0 - ts.anchor.y; + vertices[2] = vertices[4] = 1.0 - ts.anchor.x; + vertices[5] = vertices[7] = 1.0 - ts.anchor.y; + } quad.upload(); - var renderer = this.renderer; var tex = ts._texture; var baseTex = tex.baseTexture; var lt = ts.tileTransform.localTransform; @@ -27831,33 +31950,33 @@ var TilingSpriteRenderer = exports.TilingSpriteRenderer = function (_core$Object tempMat.invert(); if (isSimple) { - tempMat.append(uv.mapCoord); + tempMat.prepend(uv.mapCoord); } else { shader.uniforms.uMapCoord = uv.mapCoord.toArray(true); shader.uniforms.uClampFrame = uv.uClampFrame; shader.uniforms.uClampOffset = uv.uClampOffset; } - shader.uniforms.uTransform = tempMat.toArray(true); - var color = tempArray; - - core.utils.hex2rgb(ts.tint, color); - color[3] = ts.worldAlpha; - shader.uniforms.uColor = color; + shader.uniforms.uTransform = tempMat.toArray(true); + shader.uniforms.uColor = core.utils.premultiplyTintToRgba(ts.tint, ts.worldAlpha, shader.uniforms.uColor, baseTex.premultipliedAlpha); shader.uniforms.translationMatrix = ts.transform.worldTransform.toArray(true); - renderer.bindTexture(tex); - renderer.setBlendMode(ts.blendMode); + shader.uniforms.uSampler = renderer.bindTexture(tex); - quad.draw(); + renderer.setBlendMode(core.utils.correctBlendMode(ts.blendMode, baseTex.premultipliedAlpha)); + + quad.vao.draw(this.renderer.gl.TRIANGLES, 6, 0); }; return TilingSpriteRenderer; }(core.ObjectRenderer); +exports.default = TilingSpriteRenderer; + + core.WebGLRenderer.registerPlugin('tilingSprite', TilingSpriteRenderer); -},{"../../core":61,"../../core/const":42}],131:[function(require,module,exports){ +},{"../../core":65,"../../core/const":46,"path":25}],143:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -27895,154 +32014,143 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" * @memberof PIXI.filters */ var BlurFilter = function (_core$Filter) { - _inherits(BlurFilter, _core$Filter); - - /** - * @param {number} strength - The strength of the blur filter. - * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. - */ - function BlurFilter(strength, quality, resolution) { - _classCallCheck(this, BlurFilter); - - var _this = _possibleConstructorReturn(this, _core$Filter.call(this)); - - _this.blurXFilter = new _BlurXFilter2.default(); - _this.blurYFilter = new _BlurYFilter2.default(); - _this.resolution = 1; - - _this.padding = 0; - _this.resolution = resolution || 1; - _this.quality = quality || 4; - _this.blur = strength || 8; - return _this; - } - - /** - * Applies the filter. - * - * @param {PIXI.FilterManager} filterManager - The manager. - * @param {PIXI.RenderTarget} input - The input target. - * @param {PIXI.RenderTarget} output - The output target. - */ + _inherits(BlurFilter, _core$Filter); + /** + * @param {number} strength - The strength of the blur filter. + * @param {number} quality - The quality of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. + */ + function BlurFilter(strength, quality, resolution, kernelSize) { + _classCallCheck(this, BlurFilter); - BlurFilter.prototype.apply = function apply(filterManager, input, output) { - var renderTarget = filterManager.getRenderTarget(true); + var _this = _possibleConstructorReturn(this, _core$Filter.call(this)); - this.blurXFilter.apply(filterManager, input, renderTarget, true); - this.blurYFilter.apply(filterManager, renderTarget, output, false); + _this.blurXFilter = new _BlurXFilter2.default(strength, quality, resolution, kernelSize); + _this.blurYFilter = new _BlurYFilter2.default(strength, quality, resolution, kernelSize); - filterManager.returnRenderTarget(renderTarget); - }; - - /** - * Sets the strength of both the blurX and blurY properties simultaneously - * - * @member {number} - * @memberOf PIXI.filters.BlurFilter# - * @default 2 - */ - - - _createClass(BlurFilter, [{ - key: 'blur', - get: function get() { - return this.blurXFilter.blur; + _this.padding = 0; + _this.resolution = resolution || core.settings.RESOLUTION; + _this.quality = quality || 4; + _this.blur = strength || 8; + return _this; } /** - * Sets the strength of the blur. + * Applies the filter. * - * @param {number} value - The value to set. + * @param {PIXI.FilterManager} filterManager - The manager. + * @param {PIXI.RenderTarget} input - The input target. + * @param {PIXI.RenderTarget} output - The output target. */ - , - set: function set(value) { - this.blurXFilter.blur = this.blurYFilter.blur = value; - this.padding = Math.max(Math.abs(this.blurXFilter.strength), Math.abs(this.blurYFilter.strength)) * 2; - } - /** - * Sets the number of passes for blur. More passes means higher quaility bluring. - * - * @member {number} - * @memberof PIXI.filters.BlurYFilter# - * @default 1 - */ - }, { - key: 'quality', - get: function get() { - return this.blurXFilter.quality; - } + BlurFilter.prototype.apply = function apply(filterManager, input, output) { + var renderTarget = filterManager.getRenderTarget(true); - /** - * Sets the quality of the blur. - * - * @param {number} value - The value to set. - */ - , - set: function set(value) { - this.blurXFilter.quality = this.blurYFilter.quality = value; - } + this.blurXFilter.apply(filterManager, input, renderTarget, true); + this.blurYFilter.apply(filterManager, renderTarget, output, false); + + filterManager.returnRenderTarget(renderTarget); + }; /** - * Sets the strength of the blurX property + * Sets the strength of both the blurX and blurY properties simultaneously * * @member {number} - * @memberOf PIXI.filters.BlurFilter# * @default 2 */ - }, { - key: 'blurX', - get: function get() { - return this.blurXFilter.blur; - } - /** - * Sets the strength of the blurX. - * - * @param {number} value - The value to set. - */ - , - set: function set(value) { - this.blurXFilter.blur = value; - this.padding = Math.max(Math.abs(this.blurXFilter.strength), Math.abs(this.blurYFilter.strength)) * 2; - } + _createClass(BlurFilter, [{ + key: 'blur', + get: function get() { + return this.blurXFilter.blur; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { + this.blurXFilter.blur = this.blurYFilter.blur = value; + this.padding = Math.max(Math.abs(this.blurXFilter.strength), Math.abs(this.blurYFilter.strength)) * 2; + } - /** - * Sets the strength of the blurY property - * - * @member {number} - * @memberOf PIXI.filters.BlurFilter# - * @default 2 - */ + /** + * Sets the number of passes for blur. More passes means higher quaility bluring. + * + * @member {number} + * @default 1 + */ - }, { - key: 'blurY', - get: function get() { - return this.blurYFilter.blur; - } + }, { + key: 'quality', + get: function get() { + return this.blurXFilter.quality; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { + this.blurXFilter.quality = this.blurYFilter.quality = value; + } - /** - * Sets the strength of the blurY. - * - * @param {number} value - The value to set. - */ - , - set: function set(value) { - this.blurYFilter.blur = value; - this.padding = Math.max(Math.abs(this.blurXFilter.strength), Math.abs(this.blurYFilter.strength)) * 2; - } - }]); + /** + * Sets the strength of the blurX property + * + * @member {number} + * @default 2 + */ + + }, { + key: 'blurX', + get: function get() { + return this.blurXFilter.blur; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { + this.blurXFilter.blur = value; + this.padding = Math.max(Math.abs(this.blurXFilter.strength), Math.abs(this.blurYFilter.strength)) * 2; + } + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @default 2 + */ - return BlurFilter; + }, { + key: 'blurY', + get: function get() { + return this.blurYFilter.blur; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { + this.blurYFilter.blur = value; + this.padding = Math.max(Math.abs(this.blurXFilter.strength), Math.abs(this.blurYFilter.strength)) * 2; + } + + /** + * Sets the blendmode of the filter + * + * @member {number} + * @default PIXI.BLEND_MODES.NORMAL + */ + + }, { + key: 'blendMode', + get: function get() { + return this.blurYFilter._blendMode; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { + this.blurYFilter._blendMode = value; + } + }]); + + return BlurFilter; }(core.Filter); exports.default = BlurFilter; -},{"../../core":61,"./BlurXFilter":132,"./BlurYFilter":133}],132:[function(require,module,exports){ +},{"../../core":65,"./BlurXFilter":144,"./BlurYFilter":145}],144:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -28088,13 +32196,15 @@ var BlurXFilter = function (_core$Filter) { /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - function BlurXFilter(strength, quality, resolution) { + function BlurXFilter(strength, quality, resolution, kernelSize) { _classCallCheck(this, BlurXFilter); - var vertSrc = (0, _generateBlurVertSource2.default)(5, true); - var fragSrc = (0, _generateBlurFragSource2.default)(5); + kernelSize = kernelSize || 5; + var vertSrc = (0, _generateBlurVertSource2.default)(kernelSize, true); + var fragSrc = (0, _generateBlurFragSource2.default)(kernelSize); var _this = _possibleConstructorReturn(this, _core$Filter.call(this, // vertex shader @@ -28102,7 +32212,7 @@ var BlurXFilter = function (_core$Filter) { // fragment shader fragSrc)); - _this.resolution = resolution || 1; + _this.resolution = resolution || core.settings.RESOLUTION; _this._quality = 0; @@ -28166,7 +32276,6 @@ var BlurXFilter = function (_core$Filter) { * Sets the strength of both the blur. * * @member {number} - * @memberof PIXI.filters.BlurXFilter# * @default 16 */ @@ -28175,15 +32284,9 @@ var BlurXFilter = function (_core$Filter) { key: 'blur', get: function get() { return this.strength; - } - - /** - * Sets the strength of the blur. - * - * @param {number} value - The value to set. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.padding = Math.abs(value) * 2; this.strength = value; } @@ -28193,7 +32296,6 @@ var BlurXFilter = function (_core$Filter) { * quaility bluring but the lower the performance. * * @member {number} - * @memberof PIXI.filters.BlurXFilter# * @default 4 */ @@ -28201,15 +32303,9 @@ var BlurXFilter = function (_core$Filter) { key: 'quality', get: function get() { return this._quality; - } - - /** - * Sets the quality of the blur. - * - * @param {number} value - The value to set. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._quality = value; this.passes = value; } @@ -28220,7 +32316,7 @@ var BlurXFilter = function (_core$Filter) { exports.default = BlurXFilter; -},{"../../core":61,"./generateBlurFragSource":134,"./generateBlurVertSource":135,"./getMaxBlurKernelSize":136}],133:[function(require,module,exports){ +},{"../../core":65,"./generateBlurFragSource":146,"./generateBlurVertSource":147,"./getMaxBlurKernelSize":148}],145:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -28266,13 +32362,15 @@ var BlurYFilter = function (_core$Filter) { /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - function BlurYFilter(strength, quality, resolution) { + function BlurYFilter(strength, quality, resolution, kernelSize) { _classCallCheck(this, BlurYFilter); - var vertSrc = (0, _generateBlurVertSource2.default)(5, false); - var fragSrc = (0, _generateBlurFragSource2.default)(5); + kernelSize = kernelSize || 5; + var vertSrc = (0, _generateBlurVertSource2.default)(kernelSize, false); + var fragSrc = (0, _generateBlurFragSource2.default)(kernelSize); var _this = _possibleConstructorReturn(this, _core$Filter.call(this, // vertex shader @@ -28280,7 +32378,7 @@ var BlurYFilter = function (_core$Filter) { // fragment shader fragSrc)); - _this.resolution = resolution || 1; + _this.resolution = resolution || core.settings.RESOLUTION; _this._quality = 0; @@ -28343,7 +32441,6 @@ var BlurYFilter = function (_core$Filter) { * Sets the strength of both the blur. * * @member {number} - * @memberof PIXI.filters.BlurYFilter# * @default 2 */ @@ -28352,15 +32449,9 @@ var BlurYFilter = function (_core$Filter) { key: 'blur', get: function get() { return this.strength; - } - - /** - * Sets the strength of the blur. - * - * @param {number} value - The value to set. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.padding = Math.abs(value) * 2; this.strength = value; } @@ -28370,7 +32461,6 @@ var BlurYFilter = function (_core$Filter) { * quaility bluring but the lower the performance. * * @member {number} - * @memberof PIXI.filters.BlurXFilter# * @default 4 */ @@ -28378,15 +32468,9 @@ var BlurYFilter = function (_core$Filter) { key: 'quality', get: function get() { return this._quality; - } - - /** - * Sets the quality of the blur. - * - * @param {number} value - The value to set. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._quality = value; this.passes = value; } @@ -28397,7 +32481,7 @@ var BlurYFilter = function (_core$Filter) { exports.default = BlurYFilter; -},{"../../core":61,"./generateBlurFragSource":134,"./generateBlurVertSource":135,"./getMaxBlurKernelSize":136}],134:[function(require,module,exports){ +},{"../../core":65,"./generateBlurFragSource":146,"./generateBlurVertSource":147,"./getMaxBlurKernelSize":148}],146:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -28444,7 +32528,7 @@ function generateFragBlurSource(kernelSize) { return fragSource; } -},{}],135:[function(require,module,exports){ +},{}],147:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -28488,7 +32572,7 @@ function generateVertBlurSource(kernelSize, x) { return vertSource; } -},{}],136:[function(require,module,exports){ +},{}],148:[function(require,module,exports){ "use strict"; exports.__esModule = true; @@ -28504,7 +32588,7 @@ function getMaxKernelSize(gl) { return kernelSize; } -},{}],137:[function(require,module,exports){ +},{}],149:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -28515,6 +32599,8 @@ var _core = require('../../core'); var core = _interopRequireWildcard(_core); +var _path = require('path'); + function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -28523,8 +32609,6 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - // eslint-disable-line no-undef - /** * The ColorMatrixFilter class lets you apply a 5x4 matrix transformation on the RGBA * color and alpha values of every pixel on your displayObject to produce a result @@ -28540,7 +32624,6 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" * @extends PIXI.Filter * @memberof PIXI.filters */ - var ColorMatrixFilter = function (_core$Filter) { _inherits(ColorMatrixFilter, _core$Filter); @@ -28552,11 +32635,13 @@ var ColorMatrixFilter = function (_core$Filter) { var _this = _possibleConstructorReturn(this, _core$Filter.call(this, // vertex shader - "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 projectionMatrix;\n\nvarying vec2 vTextureCoord;\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n vTextureCoord = aTextureCoord;\n}", + 'attribute vec2 aVertexPosition;\r\nattribute vec2 aTextureCoord;\r\n\r\nuniform mat3 projectionMatrix;\r\n\r\nvarying vec2 vTextureCoord;\r\n\r\nvoid main(void)\r\n{\r\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\r\n vTextureCoord = aTextureCoord;\r\n}', // fragment shader - "#define GLSLIFY 1\nvarying vec2 vTextureCoord;\nuniform sampler2D uSampler;\nuniform float m[20];\n\nvoid main(void)\n{\n\n vec4 c = texture2D(uSampler, vTextureCoord);\n\n gl_FragColor.r = (m[0] * c.r);\n gl_FragColor.r += (m[1] * c.g);\n gl_FragColor.r += (m[2] * c.b);\n gl_FragColor.r += (m[3] * c.a);\n gl_FragColor.r += m[4] * c.a;\n\n gl_FragColor.g = (m[5] * c.r);\n gl_FragColor.g += (m[6] * c.g);\n gl_FragColor.g += (m[7] * c.b);\n gl_FragColor.g += (m[8] * c.a);\n gl_FragColor.g += m[9] * c.a;\n\n gl_FragColor.b = (m[10] * c.r);\n gl_FragColor.b += (m[11] * c.g);\n gl_FragColor.b += (m[12] * c.b);\n gl_FragColor.b += (m[13] * c.a);\n gl_FragColor.b += m[14] * c.a;\n\n gl_FragColor.a = (m[15] * c.r);\n gl_FragColor.a += (m[16] * c.g);\n gl_FragColor.a += (m[17] * c.b);\n gl_FragColor.a += (m[18] * c.a);\n gl_FragColor.a += m[19] * c.a;\n\n// gl_FragColor = vec4(m[0]);\n}\n")); + 'varying vec2 vTextureCoord;\r\nuniform sampler2D uSampler;\r\nuniform float m[20];\r\nuniform float uAlpha;\r\n\r\nvoid main(void)\r\n{\r\n vec4 c = texture2D(uSampler, vTextureCoord);\r\n\r\n if (uAlpha == 0.0) {\r\n gl_FragColor = c;\r\n return;\r\n }\r\n\r\n // Un-premultiply alpha before applying the color matrix. See issue #3539.\r\n if (c.a > 0.0) {\r\n c.rgb /= c.a;\r\n }\r\n\r\n vec4 result;\r\n\r\n result.r = (m[0] * c.r);\r\n result.r += (m[1] * c.g);\r\n result.r += (m[2] * c.b);\r\n result.r += (m[3] * c.a);\r\n result.r += m[4];\r\n\r\n result.g = (m[5] * c.r);\r\n result.g += (m[6] * c.g);\r\n result.g += (m[7] * c.b);\r\n result.g += (m[8] * c.a);\r\n result.g += m[9];\r\n\r\n result.b = (m[10] * c.r);\r\n result.b += (m[11] * c.g);\r\n result.b += (m[12] * c.b);\r\n result.b += (m[13] * c.a);\r\n result.b += m[14];\r\n\r\n result.a = (m[15] * c.r);\r\n result.a += (m[16] * c.g);\r\n result.a += (m[17] * c.b);\r\n result.a += (m[18] * c.a);\r\n result.a += m[19];\r\n\r\n vec3 rgb = mix(c.rgb, result.rgb, uAlpha);\r\n\r\n // Premultiply alpha again.\r\n rgb *= result.a;\r\n\r\n gl_FragColor = vec4(rgb, result.a);\r\n}\r\n')); _this.uniforms.m = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0]; + + _this.alpha = 1; return _this; } @@ -28600,28 +32685,28 @@ var ColorMatrixFilter = function (_core$Filter) { out[1] = a[0] * b[1] + a[1] * b[6] + a[2] * b[11] + a[3] * b[16]; out[2] = a[0] * b[2] + a[1] * b[7] + a[2] * b[12] + a[3] * b[17]; out[3] = a[0] * b[3] + a[1] * b[8] + a[2] * b[13] + a[3] * b[18]; - out[4] = a[0] * b[4] + a[1] * b[9] + a[2] * b[14] + a[3] * b[19]; + out[4] = a[0] * b[4] + a[1] * b[9] + a[2] * b[14] + a[3] * b[19] + a[4]; // Green Channel out[5] = a[5] * b[0] + a[6] * b[5] + a[7] * b[10] + a[8] * b[15]; out[6] = a[5] * b[1] + a[6] * b[6] + a[7] * b[11] + a[8] * b[16]; out[7] = a[5] * b[2] + a[6] * b[7] + a[7] * b[12] + a[8] * b[17]; out[8] = a[5] * b[3] + a[6] * b[8] + a[7] * b[13] + a[8] * b[18]; - out[9] = a[5] * b[4] + a[6] * b[9] + a[7] * b[14] + a[8] * b[19]; + out[9] = a[5] * b[4] + a[6] * b[9] + a[7] * b[14] + a[8] * b[19] + a[9]; // Blue Channel out[10] = a[10] * b[0] + a[11] * b[5] + a[12] * b[10] + a[13] * b[15]; out[11] = a[10] * b[1] + a[11] * b[6] + a[12] * b[11] + a[13] * b[16]; out[12] = a[10] * b[2] + a[11] * b[7] + a[12] * b[12] + a[13] * b[17]; out[13] = a[10] * b[3] + a[11] * b[8] + a[12] * b[13] + a[13] * b[18]; - out[14] = a[10] * b[4] + a[11] * b[9] + a[12] * b[14] + a[13] * b[19]; + out[14] = a[10] * b[4] + a[11] * b[9] + a[12] * b[14] + a[13] * b[19] + a[14]; // Alpha Channel out[15] = a[15] * b[0] + a[16] * b[5] + a[17] * b[10] + a[18] * b[15]; out[16] = a[15] * b[1] + a[16] * b[6] + a[17] * b[11] + a[18] * b[16]; out[17] = a[15] * b[2] + a[16] * b[7] + a[17] * b[12] + a[18] * b[17]; out[18] = a[15] * b[3] + a[16] * b[8] + a[17] * b[13] + a[18] * b[18]; - out[19] = a[15] * b[4] + a[16] * b[9] + a[17] * b[14] + a[18] * b[19]; + out[19] = a[15] * b[4] + a[16] * b[9] + a[17] * b[14] + a[18] * b[19] + a[19]; return out; }; @@ -28751,7 +32836,7 @@ var ColorMatrixFilter = function (_core$Filter) { ColorMatrixFilter.prototype.contrast = function contrast(amount, multiply) { var v = (amount || 0) + 1; - var o = -128 * (v - 1); + var o = -0.5 * (v - 1); var matrix = [v, 0, 0, 0, o, 0, v, 0, 0, o, 0, 0, v, 0, o, 0, 0, 0, 1, 0]; @@ -29009,7 +33094,6 @@ var ColorMatrixFilter = function (_core$Filter) { * The matrix of the color matrix filter * * @member {number[]} - * @memberof PIXI.filters.ColorMatrixFilter# * @default [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0] */ @@ -29018,16 +33102,31 @@ var ColorMatrixFilter = function (_core$Filter) { key: 'matrix', get: function get() { return this.uniforms.m; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { + this.uniforms.m = value; } /** - * Sets the matrix directly. + * The opacity value to use when mixing the original and resultant colors. + * + * When the value is 0, the original color is used without modification. + * When the value is 1, the result color is used. + * When in the range (0, 1) the color is interpolated between the original and result by this amount. * - * @param {number[]} value - the value to set to. + * @member {number} + * @default 1 */ - , - set: function set(value) { - this.uniforms.m = value; + + }, { + key: 'alpha', + get: function get() { + return this.uniforms.uAlpha; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { + this.uniforms.uAlpha = value; } }]); @@ -29040,7 +33139,7 @@ var ColorMatrixFilter = function (_core$Filter) { exports.default = ColorMatrixFilter; ColorMatrixFilter.prototype.grayscale = ColorMatrixFilter.prototype.greyscale; -},{"../../core":61}],138:[function(require,module,exports){ +},{"../../core":65,"path":25}],150:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -29051,6 +33150,8 @@ var _core = require('../../core'); var core = _interopRequireWildcard(_core); +var _path = require('path'); + function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -29059,8 +33160,6 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - // eslint-disable-line no-undef - /** * The DisplacementFilter class uses the pixel values from the specified texture * (called the displacement map) to perform a displacement of an object. You can @@ -29072,7 +33171,6 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" * @extends PIXI.Filter * @memberof PIXI.filters */ - var DisplacementFilter = function (_core$Filter) { _inherits(DisplacementFilter, _core$Filter); @@ -29089,15 +33187,15 @@ var DisplacementFilter = function (_core$Filter) { var _this = _possibleConstructorReturn(this, _core$Filter.call(this, // vertex shader - "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 projectionMatrix;\nuniform mat3 filterMatrix;\n\nvarying vec2 vTextureCoord;\nvarying vec2 vFilterCoord;\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n vFilterCoord = ( filterMatrix * vec3( aTextureCoord, 1.0) ).xy;\n vTextureCoord = aTextureCoord;\n}", + 'attribute vec2 aVertexPosition;\r\nattribute vec2 aTextureCoord;\r\n\r\nuniform mat3 projectionMatrix;\r\nuniform mat3 filterMatrix;\r\n\r\nvarying vec2 vTextureCoord;\r\nvarying vec2 vFilterCoord;\r\n\r\nvoid main(void)\r\n{\r\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\r\n vFilterCoord = ( filterMatrix * vec3( aTextureCoord, 1.0) ).xy;\r\n vTextureCoord = aTextureCoord;\r\n}', // fragment shader - "#define GLSLIFY 1\nvarying vec2 vFilterCoord;\nvarying vec2 vTextureCoord;\n\nuniform vec2 scale;\n\nuniform sampler2D uSampler;\nuniform sampler2D mapSampler;\n\nuniform vec4 filterClamp;\n\nvoid main(void)\n{\n vec4 map = texture2D(mapSampler, vFilterCoord);\n\n map -= 0.5;\n map.xy *= scale;\n\n gl_FragColor = texture2D(uSampler, clamp(vec2(vTextureCoord.x + map.x, vTextureCoord.y + map.y), filterClamp.xy, filterClamp.zw));\n}\n")); + 'varying vec2 vFilterCoord;\r\nvarying vec2 vTextureCoord;\r\n\r\nuniform vec2 scale;\r\n\r\nuniform sampler2D uSampler;\r\nuniform sampler2D mapSampler;\r\n\r\nuniform vec4 filterClamp;\r\n\r\nvoid main(void)\r\n{\r\n vec4 map = texture2D(mapSampler, vFilterCoord);\r\n\r\n map -= 0.5;\r\n map.xy *= scale;\r\n\r\n gl_FragColor = texture2D(uSampler, clamp(vec2(vTextureCoord.x + map.x, vTextureCoord.y + map.y), filterClamp.xy, filterClamp.zw));\r\n}\r\n')); _this.maskSprite = sprite; _this.maskMatrix = maskMatrix; - _this.uniforms.mapSampler = sprite.texture; - _this.uniforms.filterMatrix = maskMatrix.toArray(true); + _this.uniforms.mapSampler = sprite._texture; + _this.uniforms.filterMatrix = maskMatrix; _this.uniforms.scale = { x: 1, y: 1 }; if (scale === null || scale === undefined) { @@ -29132,7 +33230,6 @@ var DisplacementFilter = function (_core$Filter) { * The texture used for the displacement map. Must be power of 2 sized texture. * * @member {PIXI.Texture} - * @memberof PIXI.filters.DisplacementFilter# */ @@ -29140,15 +33237,9 @@ var DisplacementFilter = function (_core$Filter) { key: 'map', get: function get() { return this.uniforms.mapSampler; - } - - /** - * Sets the texture to use for the displacement. - * - * @param {PIXI.Texture} value - The texture to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.uniforms.mapSampler = value; } }]); @@ -29158,7 +33249,7 @@ var DisplacementFilter = function (_core$Filter) { exports.default = DisplacementFilter; -},{"../../core":61}],139:[function(require,module,exports){ +},{"../../core":65,"path":25}],151:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -29167,6 +33258,8 @@ var _core = require('../../core'); var core = _interopRequireWildcard(_core); +var _path = require('path'); + function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -29175,8 +33268,6 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - // eslint-disable-line no-undef - /** * * Basic FXAA implementation based on the code on geeks3d.com with the @@ -29187,10 +33278,9 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" * * @class * @extends PIXI.Filter - * @memberof PIXI + * @memberof PIXI.filters * */ - var FXAAFilter = function (_core$Filter) { _inherits(FXAAFilter, _core$Filter); @@ -29203,9 +33293,9 @@ var FXAAFilter = function (_core$Filter) { // TODO - needs work return _possibleConstructorReturn(this, _core$Filter.call(this, // vertex shader - "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 projectionMatrix;\n\nvarying vec2 v_rgbNW;\nvarying vec2 v_rgbNE;\nvarying vec2 v_rgbSW;\nvarying vec2 v_rgbSE;\nvarying vec2 v_rgbM;\n\nuniform vec4 filterArea;\n\nvarying vec2 vTextureCoord;\n\nvec2 mapCoord( vec2 coord )\n{\n coord *= filterArea.xy;\n coord += filterArea.zw;\n\n return coord;\n}\n\nvec2 unmapCoord( vec2 coord )\n{\n coord -= filterArea.zw;\n coord /= filterArea.xy;\n\n return coord;\n}\n\nvoid texcoords(vec2 fragCoord, vec2 resolution,\n out vec2 v_rgbNW, out vec2 v_rgbNE,\n out vec2 v_rgbSW, out vec2 v_rgbSE,\n out vec2 v_rgbM) {\n vec2 inverseVP = 1.0 / resolution.xy;\n v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP;\n v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP;\n v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP;\n v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP;\n v_rgbM = vec2(fragCoord * inverseVP);\n}\n\nvoid main(void) {\n\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n\n vTextureCoord = aTextureCoord;\n\n vec2 fragCoord = vTextureCoord * filterArea.xy;\n\n texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);\n}", + '\r\nattribute vec2 aVertexPosition;\r\nattribute vec2 aTextureCoord;\r\n\r\nuniform mat3 projectionMatrix;\r\n\r\nvarying vec2 v_rgbNW;\r\nvarying vec2 v_rgbNE;\r\nvarying vec2 v_rgbSW;\r\nvarying vec2 v_rgbSE;\r\nvarying vec2 v_rgbM;\r\n\r\nuniform vec4 filterArea;\r\n\r\nvarying vec2 vTextureCoord;\r\n\r\nvec2 mapCoord( vec2 coord )\r\n{\r\n coord *= filterArea.xy;\r\n coord += filterArea.zw;\r\n\r\n return coord;\r\n}\r\n\r\nvec2 unmapCoord( vec2 coord )\r\n{\r\n coord -= filterArea.zw;\r\n coord /= filterArea.xy;\r\n\r\n return coord;\r\n}\r\n\r\nvoid texcoords(vec2 fragCoord, vec2 resolution,\r\n out vec2 v_rgbNW, out vec2 v_rgbNE,\r\n out vec2 v_rgbSW, out vec2 v_rgbSE,\r\n out vec2 v_rgbM) {\r\n vec2 inverseVP = 1.0 / resolution.xy;\r\n v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP;\r\n v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP;\r\n v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP;\r\n v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP;\r\n v_rgbM = vec2(fragCoord * inverseVP);\r\n}\r\n\r\nvoid main(void) {\r\n\r\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\r\n\r\n vTextureCoord = aTextureCoord;\r\n\r\n vec2 fragCoord = vTextureCoord * filterArea.xy;\r\n\r\n texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);\r\n}', // fragment shader - "#define GLSLIFY 1\nvarying vec2 v_rgbNW;\nvarying vec2 v_rgbNE;\nvarying vec2 v_rgbSW;\nvarying vec2 v_rgbSE;\nvarying vec2 v_rgbM;\n\nvarying vec2 vTextureCoord;\nuniform sampler2D uSampler;\nuniform vec4 filterArea;\n\n/**\n Basic FXAA implementation based on the code on geeks3d.com with the\n modification that the texture2DLod stuff was removed since it's\n unsupported by WebGL.\n \n --\n \n From:\n https://github.com/mitsuhiko/webgl-meincraft\n \n Copyright (c) 2011 by Armin Ronacher.\n \n Some rights reserved.\n \n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n \n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n \n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following\n disclaimer in the documentation and/or other materials provided\n with the distribution.\n \n * The names of the contributors may not be used to endorse or\n promote products derived from this software without specific\n prior written permission.\n \n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#ifndef FXAA_REDUCE_MIN\n#define FXAA_REDUCE_MIN (1.0/ 128.0)\n#endif\n#ifndef FXAA_REDUCE_MUL\n#define FXAA_REDUCE_MUL (1.0 / 8.0)\n#endif\n#ifndef FXAA_SPAN_MAX\n#define FXAA_SPAN_MAX 8.0\n#endif\n\n//optimized version for mobile, where dependent\n//texture reads can be a bottleneck\nvec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution,\n vec2 v_rgbNW, vec2 v_rgbNE,\n vec2 v_rgbSW, vec2 v_rgbSE,\n vec2 v_rgbM) {\n vec4 color;\n mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y);\n vec3 rgbNW = texture2D(tex, v_rgbNW).xyz;\n vec3 rgbNE = texture2D(tex, v_rgbNE).xyz;\n vec3 rgbSW = texture2D(tex, v_rgbSW).xyz;\n vec3 rgbSE = texture2D(tex, v_rgbSE).xyz;\n vec4 texColor = texture2D(tex, v_rgbM);\n vec3 rgbM = texColor.xyz;\n vec3 luma = vec3(0.299, 0.587, 0.114);\n float lumaNW = dot(rgbNW, luma);\n float lumaNE = dot(rgbNE, luma);\n float lumaSW = dot(rgbSW, luma);\n float lumaSE = dot(rgbSE, luma);\n float lumaM = dot(rgbM, luma);\n float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));\n float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));\n \n mediump vec2 dir;\n dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));\n dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));\n \n float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) *\n (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);\n \n float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);\n dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),\n max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),\n dir * rcpDirMin)) * inverseVP;\n \n vec3 rgbA = 0.5 * (\n texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz +\n texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz);\n vec3 rgbB = rgbA * 0.5 + 0.25 * (\n texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz +\n texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz);\n \n float lumaB = dot(rgbB, luma);\n if ((lumaB < lumaMin) || (lumaB > lumaMax))\n color = vec4(rgbA, texColor.a);\n else\n color = vec4(rgbB, texColor.a);\n return color;\n}\n\nvoid main() {\n\n vec2 fragCoord = vTextureCoord * filterArea.xy;\n\n vec4 color;\n\n color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);\n\n gl_FragColor = color;\n}\n")); + 'varying vec2 v_rgbNW;\r\nvarying vec2 v_rgbNE;\r\nvarying vec2 v_rgbSW;\r\nvarying vec2 v_rgbSE;\r\nvarying vec2 v_rgbM;\r\n\r\nvarying vec2 vTextureCoord;\r\nuniform sampler2D uSampler;\r\nuniform vec4 filterArea;\r\n\r\n/**\r\n Basic FXAA implementation based on the code on geeks3d.com with the\r\n modification that the texture2DLod stuff was removed since it\'s\r\n unsupported by WebGL.\r\n \r\n --\r\n \r\n From:\r\n https://github.com/mitsuhiko/webgl-meincraft\r\n \r\n Copyright (c) 2011 by Armin Ronacher.\r\n \r\n Some rights reserved.\r\n \r\n Redistribution and use in source and binary forms, with or without\r\n modification, are permitted provided that the following conditions are\r\n met:\r\n \r\n * Redistributions of source code must retain the above copyright\r\n notice, this list of conditions and the following disclaimer.\r\n \r\n * Redistributions in binary form must reproduce the above\r\n copyright notice, this list of conditions and the following\r\n disclaimer in the documentation and/or other materials provided\r\n with the distribution.\r\n \r\n * The names of the contributors may not be used to endorse or\r\n promote products derived from this software without specific\r\n prior written permission.\r\n \r\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r\n "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\r\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\n#ifndef FXAA_REDUCE_MIN\r\n#define FXAA_REDUCE_MIN (1.0/ 128.0)\r\n#endif\r\n#ifndef FXAA_REDUCE_MUL\r\n#define FXAA_REDUCE_MUL (1.0 / 8.0)\r\n#endif\r\n#ifndef FXAA_SPAN_MAX\r\n#define FXAA_SPAN_MAX 8.0\r\n#endif\r\n\r\n//optimized version for mobile, where dependent\r\n//texture reads can be a bottleneck\r\nvec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution,\r\n vec2 v_rgbNW, vec2 v_rgbNE,\r\n vec2 v_rgbSW, vec2 v_rgbSE,\r\n vec2 v_rgbM) {\r\n vec4 color;\r\n mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y);\r\n vec3 rgbNW = texture2D(tex, v_rgbNW).xyz;\r\n vec3 rgbNE = texture2D(tex, v_rgbNE).xyz;\r\n vec3 rgbSW = texture2D(tex, v_rgbSW).xyz;\r\n vec3 rgbSE = texture2D(tex, v_rgbSE).xyz;\r\n vec4 texColor = texture2D(tex, v_rgbM);\r\n vec3 rgbM = texColor.xyz;\r\n vec3 luma = vec3(0.299, 0.587, 0.114);\r\n float lumaNW = dot(rgbNW, luma);\r\n float lumaNE = dot(rgbNE, luma);\r\n float lumaSW = dot(rgbSW, luma);\r\n float lumaSE = dot(rgbSE, luma);\r\n float lumaM = dot(rgbM, luma);\r\n float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));\r\n float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));\r\n \r\n mediump vec2 dir;\r\n dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));\r\n dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));\r\n \r\n float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) *\r\n (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);\r\n \r\n float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);\r\n dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),\r\n max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),\r\n dir * rcpDirMin)) * inverseVP;\r\n \r\n vec3 rgbA = 0.5 * (\r\n texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz +\r\n texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz);\r\n vec3 rgbB = rgbA * 0.5 + 0.25 * (\r\n texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz +\r\n texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz);\r\n \r\n float lumaB = dot(rgbB, luma);\r\n if ((lumaB < lumaMin) || (lumaB > lumaMax))\r\n color = vec4(rgbA, texColor.a);\r\n else\r\n color = vec4(rgbB, texColor.a);\r\n return color;\r\n}\r\n\r\nvoid main() {\r\n\r\n vec2 fragCoord = vTextureCoord * filterArea.xy;\r\n\r\n vec4 color;\r\n\r\n color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);\r\n\r\n gl_FragColor = color;\r\n}\r\n')); } return FXAAFilter; @@ -29213,7 +33303,7 @@ var FXAAFilter = function (_core$Filter) { exports.default = FXAAFilter; -},{"../../core":61}],140:[function(require,module,exports){ +},{"../../core":65,"path":25}],152:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -29292,7 +33382,7 @@ Object.defineProperty(exports, 'VoidFilter', { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -},{"./blur/BlurFilter":131,"./blur/BlurXFilter":132,"./blur/BlurYFilter":133,"./colormatrix/ColorMatrixFilter":137,"./displacement/DisplacementFilter":138,"./fxaa/FXAAFilter":139,"./noise/NoiseFilter":141,"./void/VoidFilter":142}],141:[function(require,module,exports){ +},{"./blur/BlurFilter":143,"./blur/BlurXFilter":144,"./blur/BlurYFilter":145,"./colormatrix/ColorMatrixFilter":149,"./displacement/DisplacementFilter":150,"./fxaa/FXAAFilter":151,"./noise/NoiseFilter":153,"./void/VoidFilter":154}],153:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -29303,6 +33393,8 @@ var _core = require('../../core'); var core = _interopRequireWildcard(_core); +var _path = require('path'); + function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -29311,8 +33403,6 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - // eslint-disable-line no-undef - /** * @author Vico @vicocotea * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/noise.js @@ -29325,58 +33415,71 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" * @extends PIXI.Filter * @memberof PIXI.filters */ - var NoiseFilter = function (_core$Filter) { - _inherits(NoiseFilter, _core$Filter); + _inherits(NoiseFilter, _core$Filter); - /** - * - */ - function NoiseFilter() { - _classCallCheck(this, NoiseFilter); - - var _this = _possibleConstructorReturn(this, _core$Filter.call(this, - // vertex shader - "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 projectionMatrix;\n\nvarying vec2 vTextureCoord;\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n vTextureCoord = aTextureCoord;\n}", - // fragment shader - "precision highp float;\n#define GLSLIFY 1\n\nvarying vec2 vTextureCoord;\nvarying vec4 vColor;\n\nuniform float noise;\nuniform sampler2D uSampler;\n\nfloat rand(vec2 co)\n{\n return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\nvoid main()\n{\n vec4 color = texture2D(uSampler, vTextureCoord);\n\n float diff = (rand(gl_FragCoord.xy) - 0.5) * noise;\n\n color.r += diff;\n color.g += diff;\n color.b += diff;\n\n gl_FragColor = color;\n}\n")); - - _this.noise = 0.5; - return _this; - } + /** + * @param {number} noise - The noise intensity, should be a normalized value in the range [0, 1]. + * @param {number} seed - A random seed for the noise generation. Default is `Math.random()`. + */ + function NoiseFilter() { + var noise = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0.5; + var seed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Math.random(); - /** - * The amount of noise to apply. - * - * @member {number} - * @memberof PIXI.filters.NoiseFilter# - * @default 0.5 - */ + _classCallCheck(this, NoiseFilter); + var _this = _possibleConstructorReturn(this, _core$Filter.call(this, + // vertex shader + 'attribute vec2 aVertexPosition;\r\nattribute vec2 aTextureCoord;\r\n\r\nuniform mat3 projectionMatrix;\r\n\r\nvarying vec2 vTextureCoord;\r\n\r\nvoid main(void)\r\n{\r\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\r\n vTextureCoord = aTextureCoord;\r\n}', + // fragment shader + 'precision highp float;\r\n\r\nvarying vec2 vTextureCoord;\r\nvarying vec4 vColor;\r\n\r\nuniform float uNoise;\r\nuniform float uSeed;\r\nuniform sampler2D uSampler;\r\n\r\nfloat rand(vec2 co)\r\n{\r\n return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);\r\n}\r\n\r\nvoid main()\r\n{\r\n vec4 color = texture2D(uSampler, vTextureCoord);\r\n float randomValue = rand(gl_FragCoord.xy * uSeed);\r\n float diff = (randomValue - 0.5) * uNoise;\r\n\r\n // Un-premultiply alpha before applying the color matrix. See issue #3539.\r\n if (color.a > 0.0) {\r\n color.rgb /= color.a;\r\n }\r\n\r\n color.r += diff;\r\n color.g += diff;\r\n color.b += diff;\r\n\r\n // Premultiply alpha again.\r\n color.rgb *= color.a;\r\n\r\n gl_FragColor = color;\r\n}\r\n')); - _createClass(NoiseFilter, [{ - key: 'noise', - get: function get() { - return this.uniforms.noise; + _this.noise = noise; + _this.seed = seed; + return _this; } /** - * Sets the amount of noise to apply. + * The amount of noise to apply, this value should be in the range (0, 1]. * - * @param {number} value - The value to set to. + * @member {number} + * @default 0.5 */ - , - set: function set(value) { - this.uniforms.noise = value; - } - }]); - return NoiseFilter; + + _createClass(NoiseFilter, [{ + key: 'noise', + get: function get() { + return this.uniforms.uNoise; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { + this.uniforms.uNoise = value; + } + + /** + * A seed value to apply to the random noise generation. `Math.random()` is a good value to use. + * + * @member {number} + */ + + }, { + key: 'seed', + get: function get() { + return this.uniforms.uSeed; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { + this.uniforms.uSeed = value; + } + }]); + + return NoiseFilter; }(core.Filter); exports.default = NoiseFilter; -},{"../../core":61}],142:[function(require,module,exports){ +},{"../../core":65,"path":25}],154:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -29385,6 +33488,8 @@ var _core = require('../../core'); var core = _interopRequireWildcard(_core); +var _path = require('path'); + function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -29393,9 +33498,6 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } -// @see https://github.com/substack/brfs/issues/25 - // eslint-disable-line no-undef - /** * Does nothing. Very handy. * @@ -29403,7 +33505,6 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" * @extends PIXI.Filter * @memberof PIXI.filters */ - var VoidFilter = function (_core$Filter) { _inherits(VoidFilter, _core$Filter); @@ -29415,9 +33516,9 @@ var VoidFilter = function (_core$Filter) { var _this = _possibleConstructorReturn(this, _core$Filter.call(this, // vertex shader - "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 projectionMatrix;\n\nvarying vec2 vTextureCoord;\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n vTextureCoord = aTextureCoord;\n}", + 'attribute vec2 aVertexPosition;\r\nattribute vec2 aTextureCoord;\r\n\r\nuniform mat3 projectionMatrix;\r\n\r\nvarying vec2 vTextureCoord;\r\n\r\nvoid main(void)\r\n{\r\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\r\n vTextureCoord = aTextureCoord;\r\n}', // fragment shader - "#define GLSLIFY 1\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uSampler;\n\nvoid main(void)\n{\n gl_FragColor = texture2D(uSampler, vTextureCoord);\n}\n")); + 'varying vec2 vTextureCoord;\r\n\r\nuniform sampler2D uSampler;\r\n\r\nvoid main(void)\r\n{\r\n gl_FragColor = texture2D(uSampler, vTextureCoord);\r\n}\r\n')); _this.glShaderKey = 'void'; return _this; @@ -29428,11 +33529,13 @@ var VoidFilter = function (_core$Filter) { exports.default = VoidFilter; -},{"../../core":61}],143:[function(require,module,exports){ +},{"../../core":65,"path":25}],155:[function(require,module,exports){ 'use strict'; exports.__esModule = true; +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + var _core = require('../core'); var core = _interopRequireWildcard(_core); @@ -29462,20 +33565,125 @@ var InteractionData = function () { this.global = new core.Point(); /** - * The target Sprite that was interacted with + * The target DisplayObject that was interacted with * - * @member {PIXI.Sprite} + * @member {PIXI.DisplayObject} */ this.target = null; /** * When passed to an event handler, this will be the original DOM Event that was captured * - * @member {Event} + * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent + * @see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent + * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent + * @member {MouseEvent|TouchEvent|PointerEvent} */ this.originalEvent = null; + + /** + * Unique identifier for this interaction + * + * @member {number} + */ + this.identifier = null; + + /** + * Indicates whether or not the pointer device that created the event is the primary pointer. + * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/isPrimary + * @type {Boolean} + */ + this.isPrimary = false; + + /** + * Indicates which button was pressed on the mouse or pointer device to trigger the event. + * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button + * @type {number} + */ + this.button = 0; + + /** + * Indicates which buttons are pressed on the mouse or pointer device when the event is triggered. + * @see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons + * @type {number} + */ + this.buttons = 0; + + /** + * The width of the pointer's contact along the x-axis, measured in CSS pixels. + * radiusX of TouchEvents will be represented by this value. + * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/width + * @type {number} + */ + this.width = 0; + + /** + * The height of the pointer's contact along the y-axis, measured in CSS pixels. + * radiusY of TouchEvents will be represented by this value. + * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/height + * @type {number} + */ + this.height = 0; + + /** + * The angle, in degrees, between the pointer device and the screen. + * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/tiltX + * @type {number} + */ + this.tiltX = 0; + + /** + * The angle, in degrees, between the pointer device and the screen. + * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/tiltY + * @type {number} + */ + this.tiltY = 0; + + /** + * The type of pointer that triggered the event. + * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/pointerType + * @type {string} + */ + this.pointerType = null; + + /** + * Pressure applied by the pointing device during the event. A Touch's force property + * will be represented by this value. + * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/pressure + * @type {number} + */ + this.pressure = 0; + + /** + * From TouchEvents (not PointerEvents triggered by touches), the rotationAngle of the Touch. + * @see https://developer.mozilla.org/en-US/docs/Web/API/Touch/rotationAngle + * @type {number} + */ + this.rotationAngle = 0; + + /** + * Twist of a stylus pointer. + * @see https://w3c.github.io/pointerevents/#pointerevent-interface + * @type {number} + */ + this.twist = 0; + + /** + * Barrel pressure on a stylus pointer. + * @see https://w3c.github.io/pointerevents/#pointerevent-interface + * @type {number} + */ + this.tangentialPressure = 0; } + /** + * The unique identifier of the pointer. It will be the same as `identifier`. + * @readonly + * @member {number} + * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/pointerId + */ + + /** * This will return the local coordinates of the specified displayObject for this InteractionData * @@ -29488,18 +33696,64 @@ var InteractionData = function () { * @return {PIXI.Point} A point containing the coordinates of the InteractionData position relative * to the DisplayObject */ - - InteractionData.prototype.getLocalPosition = function getLocalPosition(displayObject, point, globalPos) { return displayObject.worldTransform.applyInverse(globalPos || this.global, point); }; + /** + * Copies properties from normalized event data. + * + * @param {Touch|MouseEvent|PointerEvent} event The normalized event data + * @private + */ + + + InteractionData.prototype._copyEvent = function _copyEvent(event) { + // isPrimary should only change on touchstart/pointerdown, so we don't want to overwrite + // it with "false" on later events when our shim for it on touch events might not be + // accurate + if (event.isPrimary) { + this.isPrimary = true; + } + this.button = event.button; + this.buttons = event.buttons; + this.width = event.width; + this.height = event.height; + this.tiltX = event.tiltX; + this.tiltY = event.tiltY; + this.pointerType = event.pointerType; + this.pressure = event.pressure; + this.rotationAngle = event.rotationAngle; + this.twist = event.twist || 0; + this.tangentialPressure = event.tangentialPressure || 0; + }; + + /** + * Resets the data for pooling. + * + * @private + */ + + + InteractionData.prototype._reset = function _reset() { + // isPrimary is the only property that we really need to reset - everything else is + // guaranteed to be overwritten + this.isPrimary = false; + }; + + _createClass(InteractionData, [{ + key: 'pointerId', + get: function get() { + return this.identifier; + } + }]); + return InteractionData; }(); exports.default = InteractionData; -},{"../core":61}],144:[function(require,module,exports){ +},{"../core":65}],156:[function(require,module,exports){ "use strict"; exports.__esModule = true; @@ -29520,14 +33774,15 @@ var InteractionEvent = function () { _classCallCheck(this, InteractionEvent); /** - * Which this event will continue propagating in the tree + * Whether this event will continue propagating in the tree * * @member {boolean} */ this.stopped = false; /** - * The object to which event is dispatched. + * The object which caused this event to be dispatched. + * For listener callback see {@link PIXI.interaction.InteractionEvent.currentTarget}. * * @member {PIXI.DisplayObject} */ @@ -29540,14 +33795,14 @@ var InteractionEvent = function () { */ this.currentTarget = null; - /* + /** * Type of the event * * @member {string} */ this.type = null; - /* + /** * InteractionData related to this event * * @member {PIXI.interaction.InteractionData} @@ -29566,7 +33821,7 @@ var InteractionEvent = function () { }; /** - * Prevents event from reaching any objects other than the current object. + * Resets the event. * * @private */ @@ -29583,11 +33838,13 @@ var InteractionEvent = function () { exports.default = InteractionEvent; -},{}],145:[function(require,module,exports){ +},{}],157:[function(require,module,exports){ 'use strict'; exports.__esModule = true; +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + var _core = require('../core'); var core = _interopRequireWildcard(_core); @@ -29600,6 +33857,10 @@ var _InteractionEvent = require('./InteractionEvent'); var _InteractionEvent2 = _interopRequireDefault(_InteractionEvent); +var _InteractionTrackingData = require('./InteractionTrackingData'); + +var _InteractionTrackingData2 = _interopRequireDefault(_InteractionTrackingData); + var _eventemitter = require('eventemitter3'); var _eventemitter2 = _interopRequireDefault(_eventemitter); @@ -29608,10 +33869,6 @@ var _interactiveTarget = require('./interactiveTarget'); var _interactiveTarget2 = _interopRequireDefault(_interactiveTarget); -var _ismobilejs = require('ismobilejs'); - -var _ismobilejs2 = _interopRequireDefault(_ismobilejs); - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } @@ -29622,14 +33879,26 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } -// Mix interactiveTarget into core.DisplayObject.prototype -Object.assign(core.DisplayObject.prototype, _interactiveTarget2.default); +// Mix interactiveTarget into core.DisplayObject.prototype, after deprecation has been handled +core.utils.mixins.delayMixin(core.DisplayObject.prototype, _interactiveTarget2.default); + +var MOUSE_POINTER_ID = 'MOUSE'; + +// helpers for hitTest() - only used inside hitTest() +var hitTestEvent = { + target: null, + data: { + global: null + } +}; /** - * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive + * The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive * if its interactive parameter is set to true * This manager also supports multitouch. * + * An instance of this class is automatically created by default, and can be found at renderer.plugins.interaction + * * @class * @extends EventEmitter * @memberof PIXI.interaction @@ -29660,6 +33929,9 @@ var InteractionManager = function (_EventEmitter) { /** * Should default browser actions automatically be prevented. + * Does not apply to pointer events for backwards compatibility + * preventDefault on pointer events stops mouse events from firing + * Thus, for every pointer event, there will always be either a mouse of touch event alongside it. * * @member {boolean} * @default true @@ -29667,7 +33939,7 @@ var InteractionManager = function (_EventEmitter) { _this.autoPreventDefault = options.autoPreventDefault !== undefined ? options.autoPreventDefault : true; /** - * As this frequency increases the interaction events will be checked more often. + * Frequency in milliseconds that the mousemove, moveover & mouseout interaction events will be checked. * * @member {number} * @default 10 @@ -29680,35 +33952,35 @@ var InteractionManager = function (_EventEmitter) { * @member {PIXI.interaction.InteractionData} */ _this.mouse = new _InteractionData2.default(); + _this.mouse.identifier = MOUSE_POINTER_ID; // setting the mouse to start off far off screen will mean that mouse over does // not get called before we even move the mouse. _this.mouse.global.set(-999999); /** - * The pointer data + * Actively tracked InteractionData * - * @member {PIXI.interaction.InteractionData} + * @private + * @member {Object.} */ - _this.pointer = new _InteractionData2.default(); - - // setting the pointer to start off far off screen will mean that pointer over does - // not get called before we even move the pointer. - _this.pointer.global.set(-999999); + _this.activeInteractionData = {}; + _this.activeInteractionData[MOUSE_POINTER_ID] = _this.mouse; /** - * An event data object to handle all the event tracking/dispatching + * Pool of unused InteractionData * - * @member {object} + * @private + * @member {PIXI.interation.InteractionData[]} */ - _this.eventData = new _InteractionEvent2.default(); + _this.interactionDataPool = []; /** - * Tiny little interactiveData pool ! + * An event data object to handle all the event tracking/dispatching * - * @member {PIXI.interaction.InteractionData[]} + * @member {object} */ - _this.interactiveDataPool = []; + _this.eventData = new _InteractionEvent2.default(); /** * The DOM element to bind to. @@ -29719,15 +33991,15 @@ var InteractionManager = function (_EventEmitter) { _this.interactionDOMElement = null; /** - * This property determins if mousemove and touchmove events are fired only when the cursror + * This property determines if mousemove and touchmove events are fired only when the cursor * is over the object. * Setting to true will make things work more in line with how the DOM verison works. * Setting to false can make things easier for things like dragging - * It is currently set to false as this is how pixi used to work. This will be set to true in + * It is currently set to false as this is how PixiJS used to work. This will be set to true in * future versions of pixi. * - * @private * @member {boolean} + * @default false */ _this.moveWhenInside = false; @@ -29765,68 +34037,21 @@ var InteractionManager = function (_EventEmitter) { */ _this.supportsPointerEvents = !!window.PointerEvent; - /** - * Are touch events being 'normalized' and converted into pointer events if pointer events are not supported - * For example, on a touch screen mobile device, a touchstart would also be emitted as a pointerdown - * - * @private - * @readonly - * @member {boolean} - */ - _this.normalizeTouchEvents = !_this.supportsPointerEvents && _this.supportsTouchEvents; - - /** - * Are mouse events being 'normalized' and converted into pointer events if pointer events are not supported - * For example, on a desktop pc, a mousedown would also be emitted as a pointerdown - * - * @private - * @readonly - * @member {boolean} - */ - _this.normalizeMouseEvents = !_this.supportsPointerEvents && !_ismobilejs2.default.any; - // this will make it so that you don't have to call bind all the time /** * @private * @member {Function} */ - _this.onMouseUp = _this.onMouseUp.bind(_this); - _this.processMouseUp = _this.processMouseUp.bind(_this); - - /** - * @private - * @member {Function} - */ - _this.onMouseDown = _this.onMouseDown.bind(_this); - _this.processMouseDown = _this.processMouseDown.bind(_this); - - /** - * @private - * @member {Function} - */ - _this.onMouseMove = _this.onMouseMove.bind(_this); - _this.processMouseMove = _this.processMouseMove.bind(_this); - - /** - * @private - * @member {Function} - */ - _this.onMouseOut = _this.onMouseOut.bind(_this); - _this.processMouseOverOut = _this.processMouseOverOut.bind(_this); - - /** - * @private - * @member {Function} - */ - _this.onMouseOver = _this.onMouseOver.bind(_this); + _this.onPointerUp = _this.onPointerUp.bind(_this); + _this.processPointerUp = _this.processPointerUp.bind(_this); /** * @private * @member {Function} */ - _this.onPointerUp = _this.onPointerUp.bind(_this); - _this.processPointerUp = _this.processPointerUp.bind(_this); + _this.onPointerCancel = _this.onPointerCancel.bind(_this); + _this.processPointerCancel = _this.processPointerCancel.bind(_this); /** * @private @@ -29856,41 +34081,32 @@ var InteractionManager = function (_EventEmitter) { _this.onPointerOver = _this.onPointerOver.bind(_this); /** - * @private - * @member {Function} + * Dictionary of how different cursor modes are handled. Strings are handled as CSS cursor + * values, objects are handled as dictionaries of CSS values for interactionDOMElement, + * and functions are called instead of changing the CSS. + * Default CSS cursor values are provided for 'default' and 'pointer' modes. + * @member {Object.)>} */ - _this.onTouchStart = _this.onTouchStart.bind(_this); - _this.processTouchStart = _this.processTouchStart.bind(_this); - - /** - * @private - * @member {Function} - */ - _this.onTouchEnd = _this.onTouchEnd.bind(_this); - _this.processTouchEnd = _this.processTouchEnd.bind(_this); - - /** - * @private - * @member {Function} - */ - _this.onTouchMove = _this.onTouchMove.bind(_this); - _this.processTouchMove = _this.processTouchMove.bind(_this); + _this.cursorStyles = { + default: 'inherit', + pointer: 'pointer' + }; /** - * Every update cursor will be reset to this value, if some element wont override it in - * its hitTest. + * The mode of the cursor that is being used. + * The value of this is a key from the cursorStyles dictionary. * * @member {string} - * @default 'inherit' */ - _this.defaultCursorStyle = 'inherit'; + _this.currentCursorMode = null; /** - * The css style of the cursor that is being used. + * Internal cached let. * + * @private * @member {string} */ - _this.currentCursorStyle = 'inherit'; + _this.cursor = null; /** * Internal cached let. @@ -29911,60 +34127,60 @@ var InteractionManager = function (_EventEmitter) { _this.setTargetElement(_this.renderer.view, _this.renderer.resolution); /** - * Fired when a pointer device button (usually a mouse button) is pressed on the display + * Fired when a pointer device button (usually a mouse left-button) is pressed on the display * object. * - * @event mousedown - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#mousedown + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a pointer device secondary button (usually a mouse right-button) is pressed * on the display object. * - * @event rightdown - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#rightdown + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** - * Fired when a pointer device button (usually a mouse button) is released over the display + * Fired when a pointer device button (usually a mouse left-button) is released over the display * object. * - * @event mouseup - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#mouseup + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a pointer device secondary button (usually a mouse right-button) is released * over the display object. * - * @event rightup - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#rightup + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** - * Fired when a pointer device button (usually a mouse button) is pressed and released on + * Fired when a pointer device button (usually a mouse left-button) is pressed and released on * the display object. * - * @event click - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#click + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a pointer device secondary button (usually a mouse right-button) is pressed * and released on the display object. * - * @event rightclick - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#rightclick + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** - * Fired when a pointer device button (usually a mouse button) is released outside the + * Fired when a pointer device button (usually a mouse left-button) is released outside the * display object that initially registered a * [mousedown]{@link PIXI.interaction.InteractionManager#event:mousedown}. * - * @event mouseupoutside - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#mouseupoutside + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** @@ -29972,119 +34188,365 @@ var InteractionManager = function (_EventEmitter) { * outside the display object that initially registered a * [rightdown]{@link PIXI.interaction.InteractionManager#event:rightdown}. * - * @event rightupoutside - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#rightupoutside + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a pointer device (usually a mouse) is moved while over the display object * - * @event mousemove - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#mousemove + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a pointer device (usually a mouse) is moved onto the display object * - * @event mouseover - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#mouseover + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a pointer device (usually a mouse) is moved off the display object * - * @event mouseout - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#mouseout + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a pointer device button is pressed on the display object. * - * @event pointerdown - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#pointerdown + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a pointer device button is released over the display object. * - * @event pointerup - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#pointerup + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when the operating system cancels a pointer event + * + * @event PIXI.interaction.InteractionManager#pointercancel + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a pointer device button is pressed and released on the display object. * - * @event pointertap - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#pointertap + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a pointer device button is released outside the display object that initially * registered a [pointerdown]{@link PIXI.interaction.InteractionManager#event:pointerdown}. * - * @event pointerupoutside - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#pointerupoutside + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a pointer device is moved while over the display object * - * @event pointermove - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#pointermove + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a pointer device is moved onto the display object * - * @event pointerover - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#pointerover + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a pointer device is moved off the display object * - * @event pointerout - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#pointerout + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a touch point is placed on the display object. * - * @event touchstart - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#touchstart + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a touch point is removed from the display object. * - * @event touchend - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#touchend + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when the operating system cancels a touch + * + * @event PIXI.interaction.InteractionManager#touchcancel + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a touch point is placed and removed from the display object. * - * @event tap - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#tap + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a touch point is removed outside of the display object that initially * registered a [touchstart]{@link PIXI.interaction.InteractionManager#event:touchstart}. * - * @event touchendoutside - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.interaction.InteractionManager#touchendoutside + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a touch point is moved along the display object. + * + * @event PIXI.interaction.InteractionManager#touchmove + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device button (usually a mouse left-button) is pressed on the display. + * object. DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#mousedown + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device secondary button (usually a mouse right-button) is pressed + * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#rightdown + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device button (usually a mouse left-button) is released over the display + * object. DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#mouseup + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device secondary button (usually a mouse right-button) is released + * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#rightup + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device button (usually a mouse left-button) is pressed and released on + * the display object. DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#click + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device secondary button (usually a mouse right-button) is pressed + * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#rightclick + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device button (usually a mouse left-button) is released outside the + * display object that initially registered a + * [mousedown]{@link PIXI.DisplayObject#event:mousedown}. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#mouseupoutside + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device secondary button (usually a mouse right-button) is released + * outside the display object that initially registered a + * [rightdown]{@link PIXI.DisplayObject#event:rightdown}. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#rightupoutside + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device (usually a mouse) is moved while over the display object. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#mousemove + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device (usually a mouse) is moved onto the display object. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#mouseover + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device (usually a mouse) is moved off the display object. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#mouseout + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device button is pressed on the display object. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#pointerdown + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device button is released over the display object. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#pointerup + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when the operating system cancels a pointer event. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#pointercancel + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device button is pressed and released on the display object. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#pointertap + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device button is released outside the display object that initially + * registered a [pointerdown]{@link PIXI.DisplayObject#event:pointerdown}. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#pointerupoutside + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device is moved while over the display object. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#pointermove + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device is moved onto the display object. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#pointerover + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a pointer device is moved off the display object. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#pointerout + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a touch point is placed on the display object. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#touchstart + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a touch point is removed from the display object. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#touchend + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when the operating system cancels a touch. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#touchcancel + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a touch point is placed and removed from the display object. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#tap + * @param {PIXI.interaction.InteractionEvent} event - Interaction event + */ + + /** + * Fired when a touch point is removed outside of the display object that initially + * registered a [touchstart]{@link PIXI.DisplayObject#event:touchstart}. + * DisplayObject's `interactive` property must be set to `true` to fire event. + * + * @event PIXI.DisplayObject#touchendoutside + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ /** * Fired when a touch point is moved along the display object. + * DisplayObject's `interactive` property must be set to `true` to fire event. * - * @event touchmove - * @memberof PIXI.interaction.InteractionManager# + * @event PIXI.DisplayObject#touchmove + * @param {PIXI.interaction.InteractionEvent} event - Interaction event */ return _this; } + /** + * Hit tests a point against the display tree, returning the first interactive object that is hit. + * + * @param {PIXI.Point} globalPoint - A point to hit test with, in global space. + * @param {PIXI.Container} [root] - The root display object to start from. If omitted, defaults + * to the last rendered root of the associated renderer. + * @return {PIXI.DisplayObject} The hit display object, if any. + */ + + + InteractionManager.prototype.hitTest = function hitTest(globalPoint, root) { + // clear the target for our hit test + hitTestEvent.target = null; + // assign the global point + hitTestEvent.data.global = globalPoint; + // ensure safety of the root + if (!root) { + root = this.renderer._lastObjectRendered; + } + // run the hit test + this.processInteractive(hitTestEvent, root, null, true); + // return our found object - it'll be null if we didn't hit anything + + return hitTestEvent.target; + }; + /** * Sets the DOM element which will receive mouse/touch events. This is useful for when you have * other DOM elements on top of the renderers Canvas element. With this you'll be bale to deletegate @@ -30120,7 +34582,7 @@ var InteractionManager = function (_EventEmitter) { return; } - core.ticker.shared.add(this.update, this); + core.ticker.shared.add(this.update, this, core.UPDATE_PRIORITY.INTERACTION); if (window.navigator.msPointerEnabled) { this.interactionDOMElement.style['-ms-content-zooming'] = 'none'; @@ -30129,43 +34591,36 @@ var InteractionManager = function (_EventEmitter) { this.interactionDOMElement.style['touch-action'] = 'none'; } - window.document.addEventListener('mousemove', this.onMouseMove, true); - this.interactionDOMElement.addEventListener('mousedown', this.onMouseDown, true); - this.interactionDOMElement.addEventListener('mouseout', this.onMouseOut, true); - this.interactionDOMElement.addEventListener('mouseover', this.onMouseOver, true); - window.addEventListener('mouseup', this.onMouseUp, true); - - if (this.supportsTouchEvents) { - this.interactionDOMElement.addEventListener('touchstart', this.onTouchStart, true); - this.interactionDOMElement.addEventListener('touchend', this.onTouchEnd, true); - this.interactionDOMElement.addEventListener('touchmove', this.onTouchMove, true); - } - + /** + * These events are added first, so that if pointer events are normalised, they are fired + * in the same order as non-normalised events. ie. pointer event 1st, mouse / touch 2nd + */ if (this.supportsPointerEvents) { window.document.addEventListener('pointermove', this.onPointerMove, true); this.interactionDOMElement.addEventListener('pointerdown', this.onPointerDown, true); - this.interactionDOMElement.addEventListener('pointerout', this.onPointerOut, true); + // pointerout is fired in addition to pointerup (for touch events) and pointercancel + // we already handle those, so for the purposes of what we do in onPointerOut, we only + // care about the pointerleave event + this.interactionDOMElement.addEventListener('pointerleave', this.onPointerOut, true); this.interactionDOMElement.addEventListener('pointerover', this.onPointerOver, true); + window.addEventListener('pointercancel', this.onPointerCancel, true); window.addEventListener('pointerup', this.onPointerUp, true); } else { - /** - * If pointer events aren't available on a device, this will turn either the touch or - * mouse events into pointer events. This allows a developer to just listen for emitted - * pointer events on interactive sprites - */ - if (this.normalizeTouchEvents) { - this.interactionDOMElement.addEventListener('touchstart', this.onPointerDown, true); - this.interactionDOMElement.addEventListener('touchend', this.onPointerUp, true); - this.interactionDOMElement.addEventListener('touchmove', this.onPointerMove, true); - } + window.document.addEventListener('mousemove', this.onPointerMove, true); + this.interactionDOMElement.addEventListener('mousedown', this.onPointerDown, true); + this.interactionDOMElement.addEventListener('mouseout', this.onPointerOut, true); + this.interactionDOMElement.addEventListener('mouseover', this.onPointerOver, true); + window.addEventListener('mouseup', this.onPointerUp, true); + } - if (this.normalizeMouseEvents) { - window.document.addEventListener('mousemove', this.onPointerMove, true); - this.interactionDOMElement.addEventListener('mousedown', this.onPointerDown, true); - this.interactionDOMElement.addEventListener('mouseout', this.onPointerOut, true); - this.interactionDOMElement.addEventListener('mouseover', this.onPointerOver, true); - window.addEventListener('mouseup', this.onPointerUp, true); - } + // always look directly for touch events so that we can provide original data + // In a future version we should change this to being just a fallback and rely solely on + // PointerEvents whenever available + if (this.supportsTouchEvents) { + this.interactionDOMElement.addEventListener('touchstart', this.onPointerDown, true); + this.interactionDOMElement.addEventListener('touchcancel', this.onPointerCancel, true); + this.interactionDOMElement.addEventListener('touchend', this.onPointerUp, true); + this.interactionDOMElement.addEventListener('touchmove', this.onPointerMove, true); } this.eventsAdded = true; @@ -30192,43 +34647,26 @@ var InteractionManager = function (_EventEmitter) { this.interactionDOMElement.style['touch-action'] = ''; } - window.document.removeEventListener('mousemove', this.onMouseMove, true); - this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); - this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); - this.interactionDOMElement.removeEventListener('mouseover', this.onMouseOver, true); - window.removeEventListener('mouseup', this.onMouseUp, true); - - if (this.supportsTouchEvents) { - this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); - this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); - this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); - } - if (this.supportsPointerEvents) { window.document.removeEventListener('pointermove', this.onPointerMove, true); this.interactionDOMElement.removeEventListener('pointerdown', this.onPointerDown, true); - this.interactionDOMElement.removeEventListener('pointerout', this.onPointerOut, true); + this.interactionDOMElement.removeEventListener('pointerleave', this.onPointerOut, true); this.interactionDOMElement.removeEventListener('pointerover', this.onPointerOver, true); + window.removeEventListener('pointercancel', this.onPointerCancel, true); window.removeEventListener('pointerup', this.onPointerUp, true); } else { - /** - * If pointer events aren't available on a device, this will turn either the touch or - * mouse events into pointer events. This allows a developer to just listen for emitted - * pointer events on interactive sprites - */ - if (this.normalizeTouchEvents) { - this.interactionDOMElement.removeEventListener('touchstart', this.onPointerDown, true); - this.interactionDOMElement.removeEventListener('touchend', this.onPointerUp, true); - this.interactionDOMElement.removeEventListener('touchmove', this.onPointerMove, true); - } + window.document.removeEventListener('mousemove', this.onPointerMove, true); + this.interactionDOMElement.removeEventListener('mousedown', this.onPointerDown, true); + this.interactionDOMElement.removeEventListener('mouseout', this.onPointerOut, true); + this.interactionDOMElement.removeEventListener('mouseover', this.onPointerOver, true); + window.removeEventListener('mouseup', this.onPointerUp, true); + } - if (this.normalizeMouseEvents) { - window.document.removeEventListener('mousemove', this.onPointerMove, true); - this.interactionDOMElement.removeEventListener('mousedown', this.onPointerDown, true); - this.interactionDOMElement.removeEventListener('mouseout', this.onPointerOut, true); - this.interactionDOMElement.removeEventListener('mouseover', this.onPointerOver, true); - window.removeEventListener('mouseup', this.onPointerUp, true); - } + if (this.supportsTouchEvents) { + this.interactionDOMElement.removeEventListener('touchstart', this.onPointerDown, true); + this.interactionDOMElement.removeEventListener('touchcancel', this.onPointerCancel, true); + this.interactionDOMElement.removeEventListener('touchend', this.onPointerUp, true); + this.interactionDOMElement.removeEventListener('touchmove', this.onPointerMove, true); } this.interactionDOMElement = null; @@ -30257,30 +34695,76 @@ var InteractionManager = function (_EventEmitter) { return; } - // if the user move the mouse this check has already been dfone using the mouse move! + // if the user move the mouse this check has already been done using the mouse move! if (this.didMove) { this.didMove = false; return; } - this.cursor = this.defaultCursorStyle; + this.cursor = null; // Resets the flag as set by a stopPropagation call. This flag is usually reset by a user interaction of any kind, // but there was a scenario of a display object moving under a static mouse cursor. // In this case, mouseover and mouseevents would not pass the flag test in dispatchEvent function - this.eventData._reset(); + for (var k in this.activeInteractionData) { + // eslint-disable-next-line no-prototype-builtins + if (this.activeInteractionData.hasOwnProperty(k)) { + var interactionData = this.activeInteractionData[k]; - this.processInteractive(this.mouse.global, this.renderer._lastObjectRendered, this.processMouseOverOut, true); + if (interactionData.originalEvent && interactionData.pointerType !== 'touch') { + var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, interactionData.originalEvent, interactionData); - if (this.currentCursorStyle !== this.cursor) { - this.currentCursorStyle = this.cursor; - this.interactionDOMElement.style.cursor = this.cursor; + this.processInteractive(interactionEvent, this.renderer._lastObjectRendered, this.processPointerOverOut, true); + } + } } + this.setCursorMode(this.cursor); + // TODO }; + /** + * Sets the current cursor mode, handling any callbacks or CSS style changes. + * + * @param {string} mode - cursor mode, a key from the cursorStyles dictionary + */ + + + InteractionManager.prototype.setCursorMode = function setCursorMode(mode) { + mode = mode || 'default'; + // if the mode didn't actually change, bail early + if (this.currentCursorMode === mode) { + return; + } + this.currentCursorMode = mode; + var style = this.cursorStyles[mode]; + + // only do things if there is a cursor style for it + if (style) { + switch (typeof style === 'undefined' ? 'undefined' : _typeof(style)) { + case 'string': + // string styles are handled as cursor CSS + this.interactionDOMElement.style.cursor = style; + break; + case 'function': + // functions are just called, and passed the cursor mode + style(mode); + break; + case 'object': + // if it is an object, assume that it is a dictionary of CSS styles, + // apply it to the interactionDOMElement + Object.assign(this.interactionDOMElement.style, style); + break; + } + } else if (typeof mode === 'string' && !Object.prototype.hasOwnProperty.call(this.cursorStyles, mode)) { + // if it mode is a string (not a Symbol) and cursorStyles doesn't have any entry + // for the mode, then assume that the dev wants it to be CSS for the cursor. + this.interactionDOMElement.style.cursor = mode; + } + }; + /** * Dispatches an event on the display object that was interacted with * @@ -30305,7 +34789,7 @@ var InteractionManager = function (_EventEmitter) { }; /** - * Maps x and y coords from a DOM object and maps them correctly to the pixi view. The + * Maps x and y coords from a DOM object and maps them correctly to the PixiJS view. The * resulting value is stored in the point. This takes into account the fact that the DOM * element could be scaled and positioned anywhere on the screen. * @@ -30325,8 +34809,10 @@ var InteractionManager = function (_EventEmitter) { rect = this.interactionDOMElement.getBoundingClientRect(); } - point.x = (x - rect.left) * (this.interactionDOMElement.width / rect.width) / this.resolution; - point.y = (y - rect.top) * (this.interactionDOMElement.height / rect.height) / this.resolution; + var resolutionMultiplier = navigator.isCocoonJS ? this.resolution : 1.0 / this.resolution; + + point.x = (x - rect.left) * (this.interactionDOMElement.width / rect.width) * resolutionMultiplier; + point.y = (y - rect.top) * (this.interactionDOMElement.height / rect.height) * resolutionMultiplier; }; /** @@ -30334,22 +34820,26 @@ var InteractionManager = function (_EventEmitter) { * specified function on all interactive objects it finds. It will also take care of hit * testing the interactive objects and passes the hit across in the function. * - * @param {PIXI.Point} point - the point that is tested for collision + * @private + * @param {PIXI.interaction.InteractionEvent} interactionEvent - event containing the point that + * is tested for collision * @param {PIXI.Container|PIXI.Sprite|PIXI.extras.TilingSprite} displayObject - the displayObject - * that will be hit test (recurcsivly crawls its children) + * that will be hit test (recursively crawls its children) * @param {Function} [func] - the function that will be called on each interactive object. The - * displayObject and hit will be passed to the function + * interactionEvent, displayObject and hit will be passed to the function * @param {boolean} [hitTest] - this indicates if the objects inside should be hit test against the point * @param {boolean} [interactive] - Whether the displayObject is interactive * @return {boolean} returns true if the displayObject hit the point */ - InteractionManager.prototype.processInteractive = function processInteractive(point, displayObject, func, hitTest, interactive) { + InteractionManager.prototype.processInteractive = function processInteractive(interactionEvent, displayObject, func, hitTest, interactive) { if (!displayObject || !displayObject.visible) { return false; } + var point = interactionEvent.data.global; + // Took a little while to rework this function correctly! But now it is done and nice and optimised. ^_^ // // This function will now loop through all objects and then only hit test the objects it HAS @@ -30372,40 +34862,32 @@ var InteractionManager = function (_EventEmitter) { if (displayObject.hitArea) { interactiveParent = false; } - - // it has a mask! Then lets hit test that before continuing.. - if (hitTest && displayObject._mask) { - if (!displayObject._mask.containsPoint(point)) { - hitTest = false; - } - } - - // it has a filterArea! Same as mask but easier, its a rectangle - if (hitTest && displayObject.filterArea) { - if (!displayObject.filterArea.contains(point.x, point.y)) { - hitTest = false; + // it has a mask! Then lets hit test that before continuing + else if (hitTest && displayObject._mask) { + if (!displayObject._mask.containsPoint(point)) { + hitTest = false; + } } - } // ** FREE TIP **! If an object is not interactive or has no buttons in it // (such as a game scene!) set interactiveChildren to false for that displayObject. - // This will allow pixi to completly ignore and bypass checking the displayObjects children. - if (displayObject.interactiveChildren) { + // This will allow PixiJS to completely ignore and bypass checking the displayObjects children. + if (displayObject.interactiveChildren && displayObject.children) { var children = displayObject.children; for (var i = children.length - 1; i >= 0; i--) { var child = children[i]; - // time to get recursive.. if this function will return if somthing is hit.. - if (this.processInteractive(point, child, func, hitTest, interactiveParent)) { + // time to get recursive.. if this function will return if something is hit.. + var childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent); + + if (childHit) { // its a good idea to check if a child has lost its parent. // this means it has been removed whilst looping so its best if (!child.parent) { continue; } - hit = true; - // we no longer need to hit test any more objects in this container as we we // now know the parent has been hit interactiveParent = false; @@ -30415,11 +34897,12 @@ var InteractionManager = function (_EventEmitter) { // This means we no longer need to hit test anything else. We still need to run // through all objects, but we don't need to perform any hit tests. - // { - hitTest = false; - // } - - // we can break now as we have hit an object. + if (childHit) { + if (interactionEvent.target) { + hitTest = false; + } + hit = true; + } } } } @@ -30428,669 +34911,643 @@ var InteractionManager = function (_EventEmitter) { if (interactive) { // if we are hit testing (as in we have no hit any objects yet) // We also don't need to worry about hit testing if once of the displayObjects children - // has already been hit! - if (hitTest && !hit) { + // has already been hit - but only if it was interactive, otherwise we need to keep + // looking for an interactive child, just in case we hit one + if (hitTest && !interactionEvent.target) { if (displayObject.hitArea) { displayObject.worldTransform.applyInverse(point, this._tempPoint); - hit = displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y); + if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y)) { + hit = true; + } } else if (displayObject.containsPoint) { - hit = displayObject.containsPoint(point); + if (displayObject.containsPoint(point)) { + hit = true; + } } } if (displayObject.interactive) { - if (hit && !this.eventData.target) { - this.eventData.target = displayObject; - this.mouse.target = displayObject; - this.pointer.target = displayObject; + if (hit && !interactionEvent.target) { + interactionEvent.target = displayObject; } - func(displayObject, hit); - } - } - - return hit; - }; - - /** - * Is called when the mouse button is pressed down on the renderer element - * - * @private - * @param {MouseEvent} event - The DOM event of a mouse button being pressed down - */ - - - InteractionManager.prototype.onMouseDown = function onMouseDown(event) { - this.mouse.originalEvent = event; - this.eventData.data = this.mouse; - this.eventData._reset(); - - // Update internal mouse reference - this.mapPositionToPoint(this.mouse.global, event.clientX, event.clientY); - - if (this.autoPreventDefault) { - this.mouse.originalEvent.preventDefault(); - } - - this.processInteractive(this.mouse.global, this.renderer._lastObjectRendered, this.processMouseDown, true); - - var isRightButton = event.button === 2 || event.which === 3; - - this.emit(isRightButton ? 'rightdown' : 'mousedown', this.eventData); - }; - - /** - * Processes the result of the mouse down check and dispatches the event if need be - * - * @private - * @param {PIXI.Container|PIXI.Sprite|PIXI.extras.TilingSprite} displayObject - The display object that was tested - * @param {boolean} hit - the result of the hit test on the display object - */ - - - InteractionManager.prototype.processMouseDown = function processMouseDown(displayObject, hit) { - var e = this.mouse.originalEvent; - - var isRightButton = e.button === 2 || e.which === 3; - - if (hit) { - displayObject[isRightButton ? '_isRightDown' : '_isLeftDown'] = true; - this.dispatchEvent(displayObject, isRightButton ? 'rightdown' : 'mousedown', this.eventData); - } - }; - - /** - * Is called when the mouse button is released on the renderer element - * - * @private - * @param {MouseEvent} event - The DOM event of a mouse button being released - */ - - - InteractionManager.prototype.onMouseUp = function onMouseUp(event) { - this.mouse.originalEvent = event; - this.eventData.data = this.mouse; - this.eventData._reset(); - - // Update internal mouse reference - this.mapPositionToPoint(this.mouse.global, event.clientX, event.clientY); - - this.processInteractive(this.mouse.global, this.renderer._lastObjectRendered, this.processMouseUp, true); - - var isRightButton = event.button === 2 || event.which === 3; - - this.emit(isRightButton ? 'rightup' : 'mouseup', this.eventData); - }; - - /** - * Processes the result of the mouse up check and dispatches the event if need be - * - * @private - * @param {PIXI.Container|PIXI.Sprite|PIXI.extras.TilingSprite} displayObject - The display object that was tested - * @param {boolean} hit - the result of the hit test on the display object - */ - - - InteractionManager.prototype.processMouseUp = function processMouseUp(displayObject, hit) { - var e = this.mouse.originalEvent; - - var isRightButton = e.button === 2 || e.which === 3; - var isDown = isRightButton ? '_isRightDown' : '_isLeftDown'; - - if (hit) { - this.dispatchEvent(displayObject, isRightButton ? 'rightup' : 'mouseup', this.eventData); - - if (displayObject[isDown]) { - displayObject[isDown] = false; - this.dispatchEvent(displayObject, isRightButton ? 'rightclick' : 'click', this.eventData); - } - } else if (displayObject[isDown]) { - displayObject[isDown] = false; - this.dispatchEvent(displayObject, isRightButton ? 'rightupoutside' : 'mouseupoutside', this.eventData); - } - }; - - /** - * Is called when the mouse moves across the renderer element - * - * @private - * @param {MouseEvent} event - The DOM event of the mouse moving - */ - - - InteractionManager.prototype.onMouseMove = function onMouseMove(event) { - this.mouse.originalEvent = event; - this.eventData.data = this.mouse; - this.eventData._reset(); - - this.mapPositionToPoint(this.mouse.global, event.clientX, event.clientY); - - this.didMove = true; - - this.cursor = this.defaultCursorStyle; - - this.processInteractive(this.mouse.global, this.renderer._lastObjectRendered, this.processMouseMove, true); - - this.emit('mousemove', this.eventData); - - if (this.currentCursorStyle !== this.cursor) { - this.currentCursorStyle = this.cursor; - this.interactionDOMElement.style.cursor = this.cursor; + if (func) { + func(interactionEvent, displayObject, !!hit); + } + } } - // TODO BUG for parents ineractive object (border order issue) + return hit; }; /** - * Processes the result of the mouse move check and dispatches the event if need be + * Is called when the pointer button is pressed down on the renderer element * * @private - * @param {PIXI.Container|PIXI.Sprite|PIXI.extras.TilingSprite} displayObject - The display object that was tested - * @param {boolean} hit - the result of the hit test on the display object + * @param {PointerEvent} originalEvent - The DOM event of a pointer button being pressed down */ - InteractionManager.prototype.processMouseMove = function processMouseMove(displayObject, hit) { - this.processMouseOverOut(displayObject, hit); + InteractionManager.prototype.onPointerDown = function onPointerDown(originalEvent) { + // if we support touch events, then only use those for touch events, not pointer events + if (this.supportsTouchEvents && originalEvent.pointerType === 'touch') return; - // only display on mouse over - if (!this.moveWhenInside || hit) { - this.dispatchEvent(displayObject, 'mousemove', this.eventData); - } - }; + var events = this.normalizeToPointerData(originalEvent); - /** - * Is called when the mouse is moved out of the renderer element - * - * @private - * @param {MouseEvent} event - The DOM event of the mouse being moved out - */ + /** + * No need to prevent default on natural pointer events, as there are no side effects + * Normalized events, however, may have the double mousedown/touchstart issue on the native android browser, + * so still need to be prevented. + */ + + // Guaranteed that there will be at least one event in events, and all events must have the same pointer type + if (this.autoPreventDefault && events[0].isNormalized) { + originalEvent.preventDefault(); + } + + var eventLen = events.length; - InteractionManager.prototype.onMouseOut = function onMouseOut(event) { - this.mouseOverRenderer = false; + for (var i = 0; i < eventLen; i++) { + var event = events[i]; - this.mouse.originalEvent = event; - this.eventData.data = this.mouse; - this.eventData._reset(); + var interactionData = this.getInteractionDataForPointerId(event); - // Update internal mouse reference - this.mapPositionToPoint(this.mouse.global, event.clientX, event.clientY); + var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData); - this.interactionDOMElement.style.cursor = this.defaultCursorStyle; + interactionEvent.data.originalEvent = originalEvent; - // TODO optimize by not check EVERY TIME! maybe half as often? // - this.mapPositionToPoint(this.mouse.global, event.clientX, event.clientY); + this.processInteractive(interactionEvent, this.renderer._lastObjectRendered, this.processPointerDown, true); - this.processInteractive(this.mouse.global, this.renderer._lastObjectRendered, this.processMouseOverOut, false); + this.emit('pointerdown', interactionEvent); + if (event.pointerType === 'touch') { + this.emit('touchstart', interactionEvent); + } + // emit a mouse event for "pen" pointers, the way a browser would emit a fallback event + else if (event.pointerType === 'mouse' || event.pointerType === 'pen') { + var isRightButton = event.button === 2; - this.emit('mouseout', this.eventData); + this.emit(isRightButton ? 'rightdown' : 'mousedown', this.eventData); + } + } }; /** - * Processes the result of the mouse over/out check and dispatches the event if need be + * Processes the result of the pointer down check and dispatches the event if need be * * @private + * @param {PIXI.interaction.InteractionEvent} interactionEvent - The interaction event wrapping the DOM event * @param {PIXI.Container|PIXI.Sprite|PIXI.extras.TilingSprite} displayObject - The display object that was tested * @param {boolean} hit - the result of the hit test on the display object */ - InteractionManager.prototype.processMouseOverOut = function processMouseOverOut(displayObject, hit) { - if (hit && this.mouseOverRenderer) { - if (!displayObject._mouseOver) { - displayObject._mouseOver = true; - this.dispatchEvent(displayObject, 'mouseover', this.eventData); + InteractionManager.prototype.processPointerDown = function processPointerDown(interactionEvent, displayObject, hit) { + var data = interactionEvent.data; + var id = interactionEvent.data.identifier; + + if (hit) { + if (!displayObject.trackedPointers[id]) { + displayObject.trackedPointers[id] = new _InteractionTrackingData2.default(id); } + this.dispatchEvent(displayObject, 'pointerdown', interactionEvent); + + if (data.pointerType === 'touch') { + this.dispatchEvent(displayObject, 'touchstart', interactionEvent); + } else if (data.pointerType === 'mouse' || data.pointerType === 'pen') { + var isRightButton = data.button === 2; + + if (isRightButton) { + displayObject.trackedPointers[id].rightDown = true; + } else { + displayObject.trackedPointers[id].leftDown = true; + } - if (displayObject.buttonMode) { - this.cursor = displayObject.defaultCursor; + this.dispatchEvent(displayObject, isRightButton ? 'rightdown' : 'mousedown', interactionEvent); } - } else if (displayObject._mouseOver) { - displayObject._mouseOver = false; - this.dispatchEvent(displayObject, 'mouseout', this.eventData); } }; /** - * Is called when the mouse enters the renderer element area + * Is called when the pointer button is released on the renderer element * * @private - * @param {MouseEvent} event - The DOM event of the mouse moving into the renderer view + * @param {PointerEvent} originalEvent - The DOM event of a pointer button being released + * @param {boolean} cancelled - true if the pointer is cancelled + * @param {Function} func - Function passed to {@link processInteractive} */ - InteractionManager.prototype.onMouseOver = function onMouseOver(event) { - this.mouseOverRenderer = true; - - this.mouse.originalEvent = event; - this.eventData.data = this.mouse; - this.eventData._reset(); - - this.emit('mouseover', this.eventData); - }; + InteractionManager.prototype.onPointerComplete = function onPointerComplete(originalEvent, cancelled, func) { + var events = this.normalizeToPointerData(originalEvent); - /** - * Is called when the pointer button is pressed down on the renderer element - * - * @private - * @param {PointerEvent} event - The DOM event of a pointer button being pressed down - */ + var eventLen = events.length; + // if the event wasn't targeting our canvas, then consider it to be pointerupoutside + // in all cases (unless it was a pointercancel) + var eventAppend = originalEvent.target !== this.interactionDOMElement ? 'outside' : ''; - InteractionManager.prototype.onPointerDown = function onPointerDown(event) { - this.normalizeToPointerData(event); - this.pointer.originalEvent = event; - this.eventData.data = this.pointer; - this.eventData._reset(); + for (var i = 0; i < eventLen; i++) { + var event = events[i]; - // Update internal pointer reference - this.mapPositionToPoint(this.pointer.global, event.clientX, event.clientY); + var interactionData = this.getInteractionDataForPointerId(event); - if (this.autoPreventDefault) { - this.pointer.originalEvent.preventDefault(); - } + var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData); - this.processInteractive(this.pointer.global, this.renderer._lastObjectRendered, this.processPointerDown, true); + interactionEvent.data.originalEvent = originalEvent; - this.emit('pointerdown', this.eventData); - }; + // perform hit testing for events targeting our canvas or cancel events + this.processInteractive(interactionEvent, this.renderer._lastObjectRendered, func, cancelled || !eventAppend); - /** - * Processes the result of the pointer down check and dispatches the event if need be - * - * @private - * @param {PIXI.Container|PIXI.Sprite|PIXI.extras.TilingSprite} displayObject - The display object that was tested - * @param {boolean} hit - the result of the hit test on the display object - */ + this.emit(cancelled ? 'pointercancel' : 'pointerup' + eventAppend, interactionEvent); + if (event.pointerType === 'mouse' || event.pointerType === 'pen') { + var isRightButton = event.button === 2; - InteractionManager.prototype.processPointerDown = function processPointerDown(displayObject, hit) { - if (hit) { - displayObject._pointerDown = true; - this.dispatchEvent(displayObject, 'pointerdown', this.eventData); + this.emit(isRightButton ? 'rightup' + eventAppend : 'mouseup' + eventAppend, interactionEvent); + } else if (event.pointerType === 'touch') { + this.emit(cancelled ? 'touchcancel' : 'touchend' + eventAppend, interactionEvent); + this.releaseInteractionDataForPointerId(event.pointerId, interactionData); + } } }; /** - * Is called when the pointer button is released on the renderer element + * Is called when the pointer button is cancelled * * @private * @param {PointerEvent} event - The DOM event of a pointer button being released */ - InteractionManager.prototype.onPointerUp = function onPointerUp(event) { - this.normalizeToPointerData(event); - this.pointer.originalEvent = event; - this.eventData.data = this.pointer; - this.eventData._reset(); - - // Update internal pointer reference - this.mapPositionToPoint(this.pointer.global, event.clientX, event.clientY); - - this.processInteractive(this.pointer.global, this.renderer._lastObjectRendered, this.processPointerUp, true); + InteractionManager.prototype.onPointerCancel = function onPointerCancel(event) { + // if we support touch events, then only use those for touch events, not pointer events + if (this.supportsTouchEvents && event.pointerType === 'touch') return; - this.emit('pointerup', this.eventData); + this.onPointerComplete(event, true, this.processPointerCancel); }; /** - * Processes the result of the pointer up check and dispatches the event if need be + * Processes the result of the pointer cancel check and dispatches the event if need be * * @private + * @param {PIXI.interaction.InteractionEvent} interactionEvent - The interaction event wrapping the DOM event * @param {PIXI.Container|PIXI.Sprite|PIXI.extras.TilingSprite} displayObject - The display object that was tested - * @param {boolean} hit - the result of the hit test on the display object */ - InteractionManager.prototype.processPointerUp = function processPointerUp(displayObject, hit) { - if (hit) { - this.dispatchEvent(displayObject, 'pointerup', this.eventData); + InteractionManager.prototype.processPointerCancel = function processPointerCancel(interactionEvent, displayObject) { + var data = interactionEvent.data; - if (displayObject._pointerDown) { - displayObject._pointerDown = false; - this.dispatchEvent(displayObject, 'pointertap', this.eventData); + var id = interactionEvent.data.identifier; + + if (displayObject.trackedPointers[id] !== undefined) { + delete displayObject.trackedPointers[id]; + this.dispatchEvent(displayObject, 'pointercancel', interactionEvent); + + if (data.pointerType === 'touch') { + this.dispatchEvent(displayObject, 'touchcancel', interactionEvent); } - } else if (displayObject._pointerDown) { - displayObject._pointerDown = false; - this.dispatchEvent(displayObject, 'pointerupoutside', this.eventData); } }; /** - * Is called when the pointer moves across the renderer element + * Is called when the pointer button is released on the renderer element * * @private - * @param {PointerEvent} event - The DOM event of a pointer moving + * @param {PointerEvent} event - The DOM event of a pointer button being released */ - InteractionManager.prototype.onPointerMove = function onPointerMove(event) { - this.normalizeToPointerData(event); - this.pointer.originalEvent = event; - this.eventData.data = this.pointer; - this.eventData._reset(); - - this.mapPositionToPoint(this.pointer.global, event.clientX, event.clientY); - - this.processInteractive(this.pointer.global, this.renderer._lastObjectRendered, this.processPointerMove, true); + InteractionManager.prototype.onPointerUp = function onPointerUp(event) { + // if we support touch events, then only use those for touch events, not pointer events + if (this.supportsTouchEvents && event.pointerType === 'touch') return; - this.emit('pointermove', this.eventData); + this.onPointerComplete(event, false, this.processPointerUp); }; /** - * Processes the result of the pointer move check and dispatches the event if need be + * Processes the result of the pointer up check and dispatches the event if need be * * @private + * @param {PIXI.interaction.InteractionEvent} interactionEvent - The interaction event wrapping the DOM event * @param {PIXI.Container|PIXI.Sprite|PIXI.extras.TilingSprite} displayObject - The display object that was tested * @param {boolean} hit - the result of the hit test on the display object */ - InteractionManager.prototype.processPointerMove = function processPointerMove(displayObject, hit) { - if (!this.pointer.originalEvent.changedTouches) { - this.processPointerOverOut(displayObject, hit); - } + InteractionManager.prototype.processPointerUp = function processPointerUp(interactionEvent, displayObject, hit) { + var data = interactionEvent.data; - if (!this.moveWhenInside || hit) { - this.dispatchEvent(displayObject, 'pointermove', this.eventData); - } - }; + var id = interactionEvent.data.identifier; - /** - * Is called when the pointer is moved out of the renderer element - * - * @private - * @param {PointerEvent} event - The DOM event of a pointer being moved out - */ + var trackingData = displayObject.trackedPointers[id]; + var isTouch = data.pointerType === 'touch'; - InteractionManager.prototype.onPointerOut = function onPointerOut(event) { - this.normalizeToPointerData(event); - this.pointer.originalEvent = event; - this.eventData.data = this.pointer; - this.eventData._reset(); + var isMouse = data.pointerType === 'mouse' || data.pointerType === 'pen'; - // Update internal pointer reference - this.mapPositionToPoint(this.pointer.global, event.clientX, event.clientY); + // Mouse only + if (isMouse) { + var isRightButton = data.button === 2; - this.processInteractive(this.pointer.global, this.renderer._lastObjectRendered, this.processPointerOverOut, false); + var flags = _InteractionTrackingData2.default.FLAGS; - this.emit('pointerout', this.eventData); - }; + var test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN; - /** - * Processes the result of the pointer over/out check and dispatches the event if need be - * - * @private - * @param {PIXI.Container|PIXI.Sprite|PIXI.extras.TilingSprite} displayObject - The display object that was tested - * @param {boolean} hit - the result of the hit test on the display object - */ + var isDown = trackingData !== undefined && trackingData.flags & test; + if (hit) { + this.dispatchEvent(displayObject, isRightButton ? 'rightup' : 'mouseup', interactionEvent); - InteractionManager.prototype.processPointerOverOut = function processPointerOverOut(displayObject, hit) { - if (hit && this.mouseOverRenderer) { - if (!displayObject._pointerOver) { - displayObject._pointerOver = true; - this.dispatchEvent(displayObject, 'pointerover', this.eventData); + if (isDown) { + this.dispatchEvent(displayObject, isRightButton ? 'rightclick' : 'click', interactionEvent); + } + } else if (isDown) { + this.dispatchEvent(displayObject, isRightButton ? 'rightupoutside' : 'mouseupoutside', interactionEvent); } - } else if (displayObject._pointerOver) { - displayObject._pointerOver = false; - this.dispatchEvent(displayObject, 'pointerout', this.eventData); + // update the down state of the tracking data + if (trackingData) { + if (isRightButton) { + trackingData.rightDown = false; + } else { + trackingData.leftDown = false; + } + } + } + + // Pointers and Touches, and Mouse + if (hit) { + this.dispatchEvent(displayObject, 'pointerup', interactionEvent); + if (isTouch) this.dispatchEvent(displayObject, 'touchend', interactionEvent); + + if (trackingData) { + this.dispatchEvent(displayObject, 'pointertap', interactionEvent); + if (isTouch) { + this.dispatchEvent(displayObject, 'tap', interactionEvent); + // touches are no longer over (if they ever were) when we get the touchend + // so we should ensure that we don't keep pretending that they are + trackingData.over = false; + } + } + } else if (trackingData) { + this.dispatchEvent(displayObject, 'pointerupoutside', interactionEvent); + if (isTouch) this.dispatchEvent(displayObject, 'touchendoutside', interactionEvent); + } + // Only remove the tracking data if there is no over/down state still associated with it + if (trackingData && trackingData.none) { + delete displayObject.trackedPointers[id]; } }; /** - * Is called when the pointer is moved into the renderer element + * Is called when the pointer moves across the renderer element * * @private - * @param {PointerEvent} event - The DOM event of a pointer button being moved into the renderer view + * @param {PointerEvent} originalEvent - The DOM event of a pointer moving */ - InteractionManager.prototype.onPointerOver = function onPointerOver(event) { - this.pointer.originalEvent = event; - this.eventData.data = this.pointer; - this.eventData._reset(); - - this.emit('pointerover', this.eventData); - }; + InteractionManager.prototype.onPointerMove = function onPointerMove(originalEvent) { + // if we support touch events, then only use those for touch events, not pointer events + if (this.supportsTouchEvents && originalEvent.pointerType === 'touch') return; - /** - * Is called when a touch is started on the renderer element - * - * @private - * @param {TouchEvent} event - The DOM event of a touch starting on the renderer view - */ + var events = this.normalizeToPointerData(originalEvent); + if (events[0].pointerType === 'mouse') { + this.didMove = true; - InteractionManager.prototype.onTouchStart = function onTouchStart(event) { - if (this.autoPreventDefault) { - event.preventDefault(); + this.cursor = null; } - var changedTouches = event.changedTouches; - var cLength = changedTouches.length; + var eventLen = events.length; + + for (var i = 0; i < eventLen; i++) { + var event = events[i]; - for (var i = 0; i < cLength; i++) { - var touch = changedTouches[i]; - var touchData = this.getTouchData(touch); + var interactionData = this.getInteractionDataForPointerId(event); - touchData.originalEvent = event; + var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData); - this.eventData.data = touchData; - this.eventData._reset(); + interactionEvent.data.originalEvent = originalEvent; - this.processInteractive(touchData.global, this.renderer._lastObjectRendered, this.processTouchStart, true); + var interactive = event.pointerType === 'touch' ? this.moveWhenInside : true; - this.emit('touchstart', this.eventData); + this.processInteractive(interactionEvent, this.renderer._lastObjectRendered, this.processPointerMove, interactive); + this.emit('pointermove', interactionEvent); + if (event.pointerType === 'touch') this.emit('touchmove', interactionEvent); + if (event.pointerType === 'mouse' || event.pointerType === 'pen') this.emit('mousemove', interactionEvent); + } + + if (events[0].pointerType === 'mouse') { + this.setCursorMode(this.cursor); - this.returnTouchData(touchData); + // TODO BUG for parents interactive object (border order issue) } }; /** - * Processes the result of a touch check and dispatches the event if need be + * Processes the result of the pointer move check and dispatches the event if need be * * @private + * @param {PIXI.interaction.InteractionEvent} interactionEvent - The interaction event wrapping the DOM event * @param {PIXI.Container|PIXI.Sprite|PIXI.extras.TilingSprite} displayObject - The display object that was tested * @param {boolean} hit - the result of the hit test on the display object */ - InteractionManager.prototype.processTouchStart = function processTouchStart(displayObject, hit) { - if (hit) { - displayObject._touchDown = true; - this.dispatchEvent(displayObject, 'touchstart', this.eventData); + InteractionManager.prototype.processPointerMove = function processPointerMove(interactionEvent, displayObject, hit) { + var data = interactionEvent.data; + + var isTouch = data.pointerType === 'touch'; + + var isMouse = data.pointerType === 'mouse' || data.pointerType === 'pen'; + + if (isMouse) { + this.processPointerOverOut(interactionEvent, displayObject, hit); + } + + if (!this.moveWhenInside || hit) { + this.dispatchEvent(displayObject, 'pointermove', interactionEvent); + if (isTouch) this.dispatchEvent(displayObject, 'touchmove', interactionEvent); + if (isMouse) this.dispatchEvent(displayObject, 'mousemove', interactionEvent); } }; /** - * Is called when a touch ends on the renderer element + * Is called when the pointer is moved out of the renderer element * * @private - * @param {TouchEvent} event - The DOM event of a touch ending on the renderer view + * @param {PointerEvent} originalEvent - The DOM event of a pointer being moved out */ - InteractionManager.prototype.onTouchEnd = function onTouchEnd(event) { - if (this.autoPreventDefault) { - event.preventDefault(); - } + InteractionManager.prototype.onPointerOut = function onPointerOut(originalEvent) { + // if we support touch events, then only use those for touch events, not pointer events + if (this.supportsTouchEvents && originalEvent.pointerType === 'touch') return; - var changedTouches = event.changedTouches; - var cLength = changedTouches.length; + var events = this.normalizeToPointerData(originalEvent); - for (var i = 0; i < cLength; i++) { - var touchEvent = changedTouches[i]; + // Only mouse and pointer can call onPointerOut, so events will always be length 1 + var event = events[0]; - var touchData = this.getTouchData(touchEvent); + if (event.pointerType === 'mouse') { + this.mouseOverRenderer = false; + this.setCursorMode(null); + } - touchData.originalEvent = event; + var interactionData = this.getInteractionDataForPointerId(event); - // TODO this should be passed along.. no set - this.eventData.data = touchData; - this.eventData._reset(); + var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData); - this.processInteractive(touchData.global, this.renderer._lastObjectRendered, this.processTouchEnd, true); + interactionEvent.data.originalEvent = event; - this.emit('touchend', this.eventData); + this.processInteractive(interactionEvent, this.renderer._lastObjectRendered, this.processPointerOverOut, false); - this.returnTouchData(touchData); + this.emit('pointerout', interactionEvent); + if (event.pointerType === 'mouse' || event.pointerType === 'pen') { + this.emit('mouseout', interactionEvent); + } else { + // we can get touchleave events after touchend, so we want to make sure we don't + // introduce memory leaks + this.releaseInteractionDataForPointerId(interactionData.identifier); } }; /** - * Processes the result of the end of a touch and dispatches the event if need be + * Processes the result of the pointer over/out check and dispatches the event if need be * * @private + * @param {PIXI.interaction.InteractionEvent} interactionEvent - The interaction event wrapping the DOM event * @param {PIXI.Container|PIXI.Sprite|PIXI.extras.TilingSprite} displayObject - The display object that was tested * @param {boolean} hit - the result of the hit test on the display object */ - InteractionManager.prototype.processTouchEnd = function processTouchEnd(displayObject, hit) { - if (hit) { - this.dispatchEvent(displayObject, 'touchend', this.eventData); + InteractionManager.prototype.processPointerOverOut = function processPointerOverOut(interactionEvent, displayObject, hit) { + var data = interactionEvent.data; + + var id = interactionEvent.data.identifier; + + var isMouse = data.pointerType === 'mouse' || data.pointerType === 'pen'; + + var trackingData = displayObject.trackedPointers[id]; + + // if we just moused over the display object, then we need to track that state + if (hit && !trackingData) { + trackingData = displayObject.trackedPointers[id] = new _InteractionTrackingData2.default(id); + } + + if (trackingData === undefined) return; + + if (hit && this.mouseOverRenderer) { + if (!trackingData.over) { + trackingData.over = true; + this.dispatchEvent(displayObject, 'pointerover', interactionEvent); + if (isMouse) { + this.dispatchEvent(displayObject, 'mouseover', interactionEvent); + } + } - if (displayObject._touchDown) { - displayObject._touchDown = false; - this.dispatchEvent(displayObject, 'tap', this.eventData); + // only change the cursor if it has not already been changed (by something deeper in the + // display tree) + if (isMouse && this.cursor === null) { + this.cursor = displayObject.cursor; + } + } else if (trackingData.over) { + trackingData.over = false; + this.dispatchEvent(displayObject, 'pointerout', this.eventData); + if (isMouse) { + this.dispatchEvent(displayObject, 'mouseout', interactionEvent); + } + // if there is no mouse down information for the pointer, then it is safe to delete + if (trackingData.none) { + delete displayObject.trackedPointers[id]; } - } else if (displayObject._touchDown) { - displayObject._touchDown = false; - this.dispatchEvent(displayObject, 'touchendoutside', this.eventData); } }; /** - * Is called when a touch is moved across the renderer element + * Is called when the pointer is moved into the renderer element * * @private - * @param {TouchEvent} event - The DOM event of a touch moving accross the renderer view + * @param {PointerEvent} originalEvent - The DOM event of a pointer button being moved into the renderer view */ - InteractionManager.prototype.onTouchMove = function onTouchMove(event) { - if (this.autoPreventDefault) { - event.preventDefault(); - } - - var changedTouches = event.changedTouches; - var cLength = changedTouches.length; - - for (var i = 0; i < cLength; i++) { - var touchEvent = changedTouches[i]; + InteractionManager.prototype.onPointerOver = function onPointerOver(originalEvent) { + var events = this.normalizeToPointerData(originalEvent); - var touchData = this.getTouchData(touchEvent); + // Only mouse and pointer can call onPointerOver, so events will always be length 1 + var event = events[0]; - touchData.originalEvent = event; + var interactionData = this.getInteractionDataForPointerId(event); - this.eventData.data = touchData; - this.eventData._reset(); + var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData); - this.processInteractive(touchData.global, this.renderer._lastObjectRendered, this.processTouchMove, this.moveWhenInside); + interactionEvent.data.originalEvent = event; - this.emit('touchmove', this.eventData); + if (event.pointerType === 'mouse') { + this.mouseOverRenderer = true; + } - this.returnTouchData(touchData); + this.emit('pointerover', interactionEvent); + if (event.pointerType === 'mouse' || event.pointerType === 'pen') { + this.emit('mouseover', interactionEvent); } }; /** - * Processes the result of a touch move check and dispatches the event if need be + * Get InteractionData for a given pointerId. Store that data as well * * @private - * @param {PIXI.Container|PIXI.Sprite|PIXI.extras.TilingSprite} displayObject - The display object that was tested - * @param {boolean} hit - the result of the hit test on the display object + * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerData + * @return {PIXI.interaction.InteractionData} - Interaction data for the given pointer identifier */ - InteractionManager.prototype.processTouchMove = function processTouchMove(displayObject, hit) { - if (!this.moveWhenInside || hit) { - this.dispatchEvent(displayObject, 'touchmove', this.eventData); + InteractionManager.prototype.getInteractionDataForPointerId = function getInteractionDataForPointerId(event) { + var pointerId = event.pointerId; + + var interactionData = void 0; + + if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse') { + interactionData = this.mouse; + } else if (this.activeInteractionData[pointerId]) { + interactionData = this.activeInteractionData[pointerId]; + } else { + interactionData = this.interactionDataPool.pop() || new _InteractionData2.default(); + interactionData.identifier = pointerId; + this.activeInteractionData[pointerId] = interactionData; } + // copy properties from the event, so that we can make sure that touch/pointer specific + // data is available + interactionData._copyEvent(event); + + return interactionData; }; /** - * Grabs an interaction data object from the internal pool + * Return unused InteractionData to the pool, for a given pointerId * * @private - * @param {Touch} touch - The touch data we need to pair with an interactionData object - * @return {PIXI.interaction.InteractionData} The built data object. + * @param {number} pointerId - Identifier from a pointer event */ - InteractionManager.prototype.getTouchData = function getTouchData(touch) { - var touchData = this.interactiveDataPool.pop() || new _InteractionData2.default(); - - touchData.identifier = touch.identifier; - this.mapPositionToPoint(touchData.global, touch.clientX, touch.clientY); + InteractionManager.prototype.releaseInteractionDataForPointerId = function releaseInteractionDataForPointerId(pointerId) { + var interactionData = this.activeInteractionData[pointerId]; - if (navigator.isCocoonJS) { - touchData.global.x = touchData.global.x / this.resolution; - touchData.global.y = touchData.global.y / this.resolution; + if (interactionData) { + delete this.activeInteractionData[pointerId]; + interactionData._reset(); + this.interactionDataPool.push(interactionData); } - - touch.globalX = touchData.global.x; - touch.globalY = touchData.global.y; - - return touchData; }; /** - * Returns an interaction data object to the internal pool + * Configure an InteractionEvent to wrap a DOM PointerEvent and InteractionData * * @private - * @param {PIXI.interaction.InteractionData} touchData - The touch data object we want to return to the pool + * @param {PIXI.interaction.InteractionEvent} interactionEvent - The event to be configured + * @param {PointerEvent} pointerEvent - The DOM event that will be paired with the InteractionEvent + * @param {PIXI.interaction.InteractionData} interactionData - The InteractionData that will be paired + * with the InteractionEvent + * @return {PIXI.interaction.InteractionEvent} the interaction event that was passed in */ - InteractionManager.prototype.returnTouchData = function returnTouchData(touchData) { - this.interactiveDataPool.push(touchData); + InteractionManager.prototype.configureInteractionEventForDOMEvent = function configureInteractionEventForDOMEvent(interactionEvent, pointerEvent, interactionData) { + interactionEvent.data = interactionData; + + this.mapPositionToPoint(interactionData.global, pointerEvent.clientX, pointerEvent.clientY); + + // This is the way InteractionManager processed touch events before the refactoring, so I've kept + // it here. But it doesn't make that much sense to me, since mapPositionToPoint already factors + // in this.resolution, so this just divides by this.resolution twice for touch events... + if (navigator.isCocoonJS && pointerEvent.pointerType === 'touch') { + interactionData.global.x = interactionData.global.x / this.resolution; + interactionData.global.y = interactionData.global.y / this.resolution; + } + + // Not really sure why this is happening, but it's how a previous version handled things + if (pointerEvent.pointerType === 'touch') { + pointerEvent.globalX = interactionData.global.x; + pointerEvent.globalY = interactionData.global.y; + } + + interactionData.originalEvent = pointerEvent; + interactionEvent._reset(); + + return interactionEvent; }; /** * Ensures that the original event object contains all data that a regular pointer event would have * * @private - * @param {TouchEvent|MouseEvent} event - The original event data from a touch or mouse event + * @param {TouchEvent|MouseEvent|PointerEvent} event - The original event data from a touch or mouse event + * @return {PointerEvent[]} An array containing a single normalized pointer event, in the case of a pointer + * or mouse event, or a multiple normalized pointer events if there are multiple changed touches */ InteractionManager.prototype.normalizeToPointerData = function normalizeToPointerData(event) { - if (this.normalizeTouchEvents && event.changedTouches) { - if (typeof event.button === 'undefined') event.button = event.touches.length ? 1 : 0; - if (typeof event.buttons === 'undefined') event.buttons = event.touches.length ? 1 : 0; - if (typeof event.isPrimary === 'undefined') event.isPrimary = event.touches.length === 1; - if (typeof event.width === 'undefined') event.width = event.changedTouches[0].radiusX || 1; - if (typeof event.height === 'undefined') event.height = event.changedTouches[0].radiusY || 1; - if (typeof event.tiltX === 'undefined') event.tiltX = 0; - if (typeof event.tiltY === 'undefined') event.tiltY = 0; - if (typeof event.pointerType === 'undefined') event.pointerType = 'touch'; - if (typeof event.pointerId === 'undefined') event.pointerId = event.changedTouches[0].identifier || 0; - if (typeof event.pressure === 'undefined') event.pressure = event.changedTouches[0].force || 0.5; - if (typeof event.rotation === 'undefined') event.rotation = event.changedTouches[0].rotationAngle || 0; - - if (typeof event.clientX === 'undefined') event.clientX = event.changedTouches[0].clientX; - if (typeof event.clientY === 'undefined') event.clientY = event.changedTouches[0].clientY; - if (typeof event.pageX === 'undefined') event.pageX = event.changedTouches[0].pageX; - if (typeof event.pageY === 'undefined') event.pageY = event.changedTouches[0].pageY; - if (typeof event.screenX === 'undefined') event.screenX = event.changedTouches[0].screenX; - if (typeof event.screenY === 'undefined') event.screenY = event.changedTouches[0].screenY; - if (typeof event.layerX === 'undefined') event.layerX = event.offsetX = event.clientX; - if (typeof event.layerY === 'undefined') event.layerY = event.offsetY = event.clientY; - } else if (this.normalizeMouseEvents) { - if (typeof event.isPrimary === 'undefined') event.isPrimary = true; - if (typeof event.width === 'undefined') event.width = 1; - if (typeof event.height === 'undefined') event.height = 1; - if (typeof event.tiltX === 'undefined') event.tiltX = 0; - if (typeof event.tiltY === 'undefined') event.tiltY = 0; - if (typeof event.pointerType === 'undefined') event.pointerType = 'mouse'; - if (typeof event.pointerId === 'undefined') event.pointerId = 1; - if (typeof event.pressure === 'undefined') event.pressure = 0.5; - if (typeof event.rotation === 'undefined') event.rotation = 0; - } + var normalizedEvents = []; + + if (this.supportsTouchEvents && event instanceof TouchEvent) { + for (var i = 0, li = event.changedTouches.length; i < li; i++) { + var touch = event.changedTouches[i]; + + if (typeof touch.button === 'undefined') touch.button = event.touches.length ? 1 : 0; + if (typeof touch.buttons === 'undefined') touch.buttons = event.touches.length ? 1 : 0; + if (typeof touch.isPrimary === 'undefined') { + touch.isPrimary = event.touches.length === 1 && event.type === 'touchstart'; + } + if (typeof touch.width === 'undefined') touch.width = touch.radiusX || 1; + if (typeof touch.height === 'undefined') touch.height = touch.radiusY || 1; + if (typeof touch.tiltX === 'undefined') touch.tiltX = 0; + if (typeof touch.tiltY === 'undefined') touch.tiltY = 0; + if (typeof touch.pointerType === 'undefined') touch.pointerType = 'touch'; + if (typeof touch.pointerId === 'undefined') touch.pointerId = touch.identifier || 0; + if (typeof touch.pressure === 'undefined') touch.pressure = touch.force || 0.5; + touch.twist = 0; + touch.tangentialPressure = 0; + // TODO: Remove these, as layerX/Y is not a standard, is deprecated, has uneven + // support, and the fill ins are not quite the same + // offsetX/Y might be okay, but is not the same as clientX/Y when the canvas's top + // left is not 0,0 on the page + if (typeof touch.layerX === 'undefined') touch.layerX = touch.offsetX = touch.clientX; + if (typeof touch.layerY === 'undefined') touch.layerY = touch.offsetY = touch.clientY; + + // mark the touch as normalized, just so that we know we did it + touch.isNormalized = true; + + normalizedEvents.push(touch); + } + } + // apparently PointerEvent subclasses MouseEvent, so yay + else if (event instanceof MouseEvent && (!this.supportsPointerEvents || !(event instanceof window.PointerEvent))) { + if (typeof event.isPrimary === 'undefined') event.isPrimary = true; + if (typeof event.width === 'undefined') event.width = 1; + if (typeof event.height === 'undefined') event.height = 1; + if (typeof event.tiltX === 'undefined') event.tiltX = 0; + if (typeof event.tiltY === 'undefined') event.tiltY = 0; + if (typeof event.pointerType === 'undefined') event.pointerType = 'mouse'; + if (typeof event.pointerId === 'undefined') event.pointerId = MOUSE_POINTER_ID; + if (typeof event.pressure === 'undefined') event.pressure = 0.5; + event.twist = 0; + event.tangentialPressure = 0; + + // mark the mouse event as normalized, just so that we know we did it + event.isNormalized = true; + + normalizedEvents.push(event); + } else { + normalizedEvents.push(event); + } + + return normalizedEvents; }; /** @@ -31110,30 +35567,17 @@ var InteractionManager = function (_EventEmitter) { this.eventData = null; - this.interactiveDataPool = null; - this.interactionDOMElement = null; - this.onMouseDown = null; - this.processMouseDown = null; - - this.onMouseUp = null; - this.processMouseUp = null; - - this.onMouseMove = null; - this.processMouseMove = null; - - this.onMouseOut = null; - this.processMouseOverOut = null; - - this.onMouseOver = null; - this.onPointerDown = null; this.processPointerDown = null; this.onPointerUp = null; this.processPointerUp = null; + this.onPointerCancel = null; + this.processPointerCancel = null; + this.onPointerMove = null; this.processPointerMove = null; @@ -31142,15 +35586,6 @@ var InteractionManager = function (_EventEmitter) { this.onPointerOver = null; - this.onTouchStart = null; - this.processTouchStart = null; - - this.onTouchEnd = null; - this.processTouchEnd = null; - - this.onTouchMove = null; - this.processTouchMove = null; - this._tempPoint = null; }; @@ -31163,7 +35598,183 @@ exports.default = InteractionManager; core.WebGLRenderer.registerPlugin('interaction', InteractionManager); core.CanvasRenderer.registerPlugin('interaction', InteractionManager); -},{"../core":61,"./InteractionData":143,"./InteractionEvent":144,"./interactiveTarget":147,"eventemitter3":19,"ismobilejs":20}],146:[function(require,module,exports){ +},{"../core":65,"./InteractionData":155,"./InteractionEvent":156,"./InteractionTrackingData":158,"./interactiveTarget":160,"eventemitter3":20}],158:[function(require,module,exports){ +"use strict"; + +exports.__esModule = true; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * DisplayObjects with the {@link PIXI.interaction.interactiveTarget} mixin use this class to track interactions + * + * @class + * @private + * @memberof PIXI.interaction + */ +var InteractionTrackingData = function () { + /** + * @param {number} pointerId - Unique pointer id of the event + */ + function InteractionTrackingData(pointerId) { + _classCallCheck(this, InteractionTrackingData); + + this._pointerId = pointerId; + this._flags = InteractionTrackingData.FLAGS.NONE; + } + + /** + * + * @private + * @param {number} flag - The interaction flag to set + * @param {boolean} yn - Should the flag be set or unset + */ + + + InteractionTrackingData.prototype._doSet = function _doSet(flag, yn) { + if (yn) { + this._flags = this._flags | flag; + } else { + this._flags = this._flags & ~flag; + } + }; + + /** + * Unique pointer id of the event + * + * @readonly + * @member {number} + */ + + + _createClass(InteractionTrackingData, [{ + key: "pointerId", + get: function get() { + return this._pointerId; + } + + /** + * State of the tracking data, expressed as bit flags + * + * @member {number} + * @memberof PIXI.interaction.InteractionTrackingData# + */ + + }, { + key: "flags", + get: function get() { + return this._flags; + } + + /** + * Set the flags for the tracking data + * + * @param {number} flags - Flags to set + */ + , + set: function set(flags) { + this._flags = flags; + } + + /** + * Is the tracked event inactive (not over or down)? + * + * @member {number} + * @memberof PIXI.interaction.InteractionTrackingData# + */ + + }, { + key: "none", + get: function get() { + return this._flags === this.constructor.FLAGS.NONE; + } + + /** + * Is the tracked event over the DisplayObject? + * + * @member {boolean} + * @memberof PIXI.interaction.InteractionTrackingData# + */ + + }, { + key: "over", + get: function get() { + return (this._flags & this.constructor.FLAGS.OVER) !== 0; + } + + /** + * Set the over flag + * + * @param {boolean} yn - Is the event over? + */ + , + set: function set(yn) { + this._doSet(this.constructor.FLAGS.OVER, yn); + } + + /** + * Did the right mouse button come down in the DisplayObject? + * + * @member {boolean} + * @memberof PIXI.interaction.InteractionTrackingData# + */ + + }, { + key: "rightDown", + get: function get() { + return (this._flags & this.constructor.FLAGS.RIGHT_DOWN) !== 0; + } + + /** + * Set the right down flag + * + * @param {boolean} yn - Is the right mouse button down? + */ + , + set: function set(yn) { + this._doSet(this.constructor.FLAGS.RIGHT_DOWN, yn); + } + + /** + * Did the left mouse button come down in the DisplayObject? + * + * @member {boolean} + * @memberof PIXI.interaction.InteractionTrackingData# + */ + + }, { + key: "leftDown", + get: function get() { + return (this._flags & this.constructor.FLAGS.LEFT_DOWN) !== 0; + } + + /** + * Set the left down flag + * + * @param {boolean} yn - Is the left mouse button down? + */ + , + set: function set(yn) { + this._doSet(this.constructor.FLAGS.LEFT_DOWN, yn); + } + }]); + + return InteractionTrackingData; +}(); + +exports.default = InteractionTrackingData; + + +InteractionTrackingData.FLAGS = Object.freeze({ + NONE: 0, + OVER: 1 << 0, + LEFT_DOWN: 1 << 1, + RIGHT_DOWN: 1 << 2 +}); + +},{}],159:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -31195,9 +35806,27 @@ Object.defineProperty(exports, 'interactiveTarget', { } }); +var _InteractionTrackingData = require('./InteractionTrackingData'); + +Object.defineProperty(exports, 'InteractionTrackingData', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_InteractionTrackingData).default; + } +}); + +var _InteractionEvent = require('./InteractionEvent'); + +Object.defineProperty(exports, 'InteractionEvent', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_InteractionEvent).default; + } +}); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -},{"./InteractionData":143,"./InteractionManager":145,"./interactiveTarget":147}],147:[function(require,module,exports){ +},{"./InteractionData":155,"./InteractionEvent":156,"./InteractionManager":157,"./InteractionTrackingData":158,"./interactiveTarget":160}],160:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -31205,30 +35834,40 @@ exports.__esModule = true; * Default property values of interactive objects * Used by {@link PIXI.interaction.InteractionManager} to automatically give all DisplayObjects these properties * - * @mixin + * @private * @name interactiveTarget * @memberof PIXI.interaction * @example * function MyObject() {} * * Object.assign( - * MyObject.prototype, + * core.DisplayObject.prototype, * PIXI.interaction.interactiveTarget * ); */ exports.default = { + /** - * Determines if the displayObject be clicked/touched + * Enable interaction events for the DisplayObject. Touch, pointer and mouse + * events will not be emitted unless `interactive` is set to `true`. * - * @inner {boolean} + * @example + * const sprite = new PIXI.Sprite(texture); + * sprite.interactive = true; + * sprite.on('tap', (event) => { + * //handle event + * }); + * @member {boolean} + * @memberof PIXI.DisplayObject# */ interactive: false, /** * Determines if the children to the displayObject can be clicked/touched - * Setting this to false allows pixi to bypass a recursive hitTest function + * Setting this to false allows PixiJS to bypass a recursive `hitTest` function * - * @inner {boolean} + * @member {boolean} + * @memberof PIXI.Container# */ interactiveChildren: true, @@ -31236,78 +35875,75 @@ exports.default = { * Interaction shape. Children will be hit first, then this shape will be checked. * Setting this will cause this shape to be checked in hit tests rather than the displayObject's bounds. * - * @inner {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle} + * @example + * const sprite = new PIXI.Sprite(texture); + * sprite.interactive = true; + * sprite.hitArea = new PIXI.Rectangle(0, 0, 100, 100); + * @member {PIXI.Rectangle|PIXI.Circle|PIXI.Ellipse|PIXI.Polygon|PIXI.RoundedRectangle} + * @memberof PIXI.DisplayObject# */ hitArea: null, /** - * If enabled, the mouse cursor will change when hovered over the displayObject if it is interactive + * If enabled, the mouse cursor use the pointer behavior when hovered over the displayObject if it is interactive + * Setting this changes the 'cursor' property to `'pointer'`. * - * @inner {boolean} + * @example + * const sprite = new PIXI.Sprite(texture); + * sprite.interactive = true; + * sprite.buttonMode = true; + * @member {boolean} + * @memberof PIXI.DisplayObject# */ - buttonMode: false, + get buttonMode() { + return this.cursor === 'pointer'; + }, + set buttonMode(value) { + if (value) { + this.cursor = 'pointer'; + } else if (this.cursor === 'pointer') { + this.cursor = null; + } + }, /** - * If buttonMode is enabled, this defines what CSS cursor property is used when the mouse cursor - * is hovered over the displayObject + * This defines what cursor mode is used when the mouse cursor + * is hovered over the displayObject. * + * @example + * const sprite = new PIXI.Sprite(texture); + * sprite.interactive = true; + * sprite.cursor = 'wait'; * @see https://developer.mozilla.org/en/docs/Web/CSS/cursor * - * @inner {string} - */ - defaultCursor: 'pointer', - - // some internal checks.. - /** - * Internal check to detect if the mouse cursor is hovered over the displayObject - * - * @inner {boolean} - * @private - */ - _over: false, - - /** - * Internal check to detect if the left mouse button is pressed on the displayObject - * - * @inner {boolean} - * @private - */ - _isLeftDown: false, - - /** - * Internal check to detect if the right mouse button is pressed on the displayObject - * - * @inner {boolean} - * @private + * @member {string} + * @memberof PIXI.DisplayObject# */ - _isRightDown: false, + cursor: null, /** - * Internal check to detect if the pointer cursor is hovered over the displayObject + * Internal set of all active pointers, by identifier * - * @inner {boolean} + * @member {Map} + * @memberof PIXI.DisplayObject# * @private */ - _pointerOver: false, + get trackedPointers() { + if (this._trackedPointers === undefined) this._trackedPointers = {}; - /** - * Internal check to detect if the pointer is down on the displayObject - * - * @inner {boolean} - * @private - */ - _pointerDown: false, + return this._trackedPointers; + }, /** - * Internal check to detect if a user has touched the displayObject + * Map of all tracked pointers, by identifier. Use trackedPointers to access. * - * @inner {boolean} * @private + * @type {Map} */ - _touchDown: false + _trackedPointers: undefined }; -},{}],148:[function(require,module,exports){ +},{}],161:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -31316,7 +35952,7 @@ exports.parse = parse; exports.default = function () { return function bitmapFontParser(resource, next) { // skip if no data or not xml data - if (!resource.data || !resource.isXml) { + if (!resource.data || resource.type !== _resourceLoader.Resource.TYPE.XML) { next(); return; @@ -31341,12 +35977,12 @@ exports.default = function () { if (this.baseUrl.charAt(this.baseUrl.length - 1) === '/') { xmlUrl += '/'; } - - // remove baseUrl from xmlUrl - xmlUrl = xmlUrl.replace(this.baseUrl, ''); } } + // remove baseUrl from xmlUrl + xmlUrl = xmlUrl.replace(this.baseUrl, ''); + // if there is an xmlUrl now, it needs a trailing slash. Ensure that it does if the string isn't empty. if (xmlUrl && xmlUrl.charAt(xmlUrl.length - 1) !== '/') { xmlUrl += '/'; @@ -31362,7 +35998,8 @@ exports.default = function () { var loadOptions = { crossOrigin: resource.crossOrigin, loadType: _resourceLoader.Resource.LOAD_TYPE.IMAGE, - metadata: resource.metadata.imageMetadata + metadata: resource.metadata.imageMetadata, + parentResource: resource }; // load the texture for the font @@ -31386,113 +36023,147 @@ var _extras = require('../extras'); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } +/** + * Register a BitmapText font from loader resource. + * + * @function parseBitmapFontData + * @memberof PIXI.loaders + * @param {PIXI.loaders.Resource} resource - Loader resource. + * @param {PIXI.Texture} texture - Reference to texture. + */ function parse(resource, texture) { - var data = {}; - var info = resource.data.getElementsByTagName('info')[0]; - var common = resource.data.getElementsByTagName('common')[0]; - - data.font = info.getAttribute('face'); - data.size = parseInt(info.getAttribute('size'), 10); - data.lineHeight = parseInt(common.getAttribute('lineHeight'), 10); - data.chars = {}; - - // parse letters - var letters = resource.data.getElementsByTagName('char'); - - for (var i = 0; i < letters.length; i++) { - var charCode = parseInt(letters[i].getAttribute('id'), 10); - - var textureRect = new _core.Rectangle(parseInt(letters[i].getAttribute('x'), 10) + texture.frame.x, parseInt(letters[i].getAttribute('y'), 10) + texture.frame.y, parseInt(letters[i].getAttribute('width'), 10), parseInt(letters[i].getAttribute('height'), 10)); - - data.chars[charCode] = { - xOffset: parseInt(letters[i].getAttribute('xoffset'), 10), - yOffset: parseInt(letters[i].getAttribute('yoffset'), 10), - xAdvance: parseInt(letters[i].getAttribute('xadvance'), 10), - kerning: {}, - texture: new _core.Texture(texture.baseTexture, textureRect) - - }; - } - - // parse kernings - var kernings = resource.data.getElementsByTagName('kerning'); - - for (var _i = 0; _i < kernings.length; _i++) { - var first = parseInt(kernings[_i].getAttribute('first'), 10); - var second = parseInt(kernings[_i].getAttribute('second'), 10); - var amount = parseInt(kernings[_i].getAttribute('amount'), 10); - - if (data.chars[second]) { - data.chars[second].kerning[first] = amount; - } - } - - resource.bitmapFont = data; - - // I'm leaving this as a temporary fix so we can test the bitmap fonts in v3 - // but it's very likely to change - _extras.BitmapText.fonts[data.font] = data; + resource.bitmapFont = _extras.BitmapText.registerFont(resource.data, texture); } -},{"../core":61,"../extras":129,"path":23,"resource-loader":35}],149:[function(require,module,exports){ +},{"../core":65,"../extras":141,"path":25,"resource-loader":36}],162:[function(require,module,exports){ 'use strict'; exports.__esModule = true; - -var _loader = require('./loader'); - -Object.defineProperty(exports, 'Loader', { - enumerable: true, - get: function get() { - return _interopRequireDefault(_loader).default; - } -}); +exports.shared = exports.Resource = exports.textureParser = exports.getResourcePath = exports.spritesheetParser = exports.parseBitmapFontData = exports.bitmapFontParser = exports.Loader = undefined; var _bitmapFontParser = require('./bitmapFontParser'); Object.defineProperty(exports, 'bitmapFontParser', { - enumerable: true, - get: function get() { - return _interopRequireDefault(_bitmapFontParser).default; - } + enumerable: true, + get: function get() { + return _interopRequireDefault(_bitmapFontParser).default; + } }); Object.defineProperty(exports, 'parseBitmapFontData', { - enumerable: true, - get: function get() { - return _bitmapFontParser.parse; - } + enumerable: true, + get: function get() { + return _bitmapFontParser.parse; + } }); var _spritesheetParser = require('./spritesheetParser'); Object.defineProperty(exports, 'spritesheetParser', { - enumerable: true, - get: function get() { - return _interopRequireDefault(_spritesheetParser).default; - } + enumerable: true, + get: function get() { + return _interopRequireDefault(_spritesheetParser).default; + } +}); +Object.defineProperty(exports, 'getResourcePath', { + enumerable: true, + get: function get() { + return _spritesheetParser.getResourcePath; + } }); var _textureParser = require('./textureParser'); Object.defineProperty(exports, 'textureParser', { - enumerable: true, - get: function get() { - return _interopRequireDefault(_textureParser).default; - } + enumerable: true, + get: function get() { + return _interopRequireDefault(_textureParser).default; + } }); var _resourceLoader = require('resource-loader'); Object.defineProperty(exports, 'Resource', { - enumerable: true, - get: function get() { - return _resourceLoader.Resource; - } + enumerable: true, + get: function get() { + return _resourceLoader.Resource; + } }); +var _Application = require('../core/Application'); + +var _Application2 = _interopRequireDefault(_Application); + +var _loader = require('./loader'); + +var _loader2 = _interopRequireDefault(_loader); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -},{"./bitmapFontParser":148,"./loader":150,"./spritesheetParser":151,"./textureParser":152,"resource-loader":35}],150:[function(require,module,exports){ +/** + * This namespace contains APIs which extends the {@link https://github.com/englercj/resource-loader resource-loader} module + * for loading assets, data, and other resources dynamically. + * @example + * const loader = new PIXI.loaders.Loader(); + * loader.add('bunny', 'data/bunny.png') + * .add('spaceship', 'assets/spritesheet.json'); + * loader.load((loader, resources) => { + * // resources.bunny + * // resources.spaceship + * }); + * @namespace PIXI.loaders + */ +exports.Loader = _loader2.default; + + +/** + * A premade instance of the loader that can be used to load resources. + * @name shared + * @memberof PIXI.loaders + * @type {PIXI.loaders.Loader} + */ +var shared = new _loader2.default(); + +shared.destroy = function () { + // protect destroying shared loader +}; + +exports.shared = shared; + +// Mixin the loader construction + +var AppPrototype = _Application2.default.prototype; + +AppPrototype._loader = null; + +/** + * Loader instance to help with asset loading. + * @name PIXI.Application#loader + * @type {PIXI.loaders.Loader} + */ +Object.defineProperty(AppPrototype, 'loader', { + get: function get() { + if (!this._loader) { + var sharedLoader = this._options.sharedLoader; + + this._loader = sharedLoader ? shared : new _loader2.default(); + } + + return this._loader; + } +}); + +// Override the destroy function +// making sure to destroy the current Loader +AppPrototype._parentDestroy = AppPrototype.destroy; +AppPrototype.destroy = function destroy(removeView) { + if (this._loader) { + this._loader.destroy(); + this._loader = null; + } + this._parentDestroy(removeView); +}; + +},{"../core/Application":43,"./bitmapFontParser":161,"./loader":163,"./spritesheetParser":164,"./textureParser":165,"resource-loader":36}],163:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -31501,6 +36172,12 @@ var _resourceLoader = require('resource-loader'); var _resourceLoader2 = _interopRequireDefault(_resourceLoader); +var _blob = require('resource-loader/lib/middlewares/parsing/blob'); + +var _eventemitter = require('eventemitter3'); + +var _eventemitter2 = _interopRequireDefault(_eventemitter); + var _textureParser = require('./textureParser'); var _textureParser2 = _interopRequireDefault(_textureParser); @@ -31523,18 +36200,47 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" /** * - * The new loader, extends Resource Loader by Chad Engler : https://github.com/englercj/resource-loader + * The new loader, extends Resource Loader by Chad Engler: https://github.com/englercj/resource-loader * * ```js - * let loader = PIXI.loader; // pixi exposes a premade instance for you to use. + * const loader = PIXI.loader; // PixiJS exposes a premade instance for you to use. * //or - * let loader = new PIXI.loaders.Loader(); // you can also create your own if you want - * - * loader.add('bunny',"data/bunny.png"); - * - * loader.once('complete',onAssetsLoaded); + * const loader = new PIXI.loaders.Loader(); // you can also create your own if you want + * + * const sprites = {}; + * + * // Chainable `add` to enqueue a resource + * loader.add('bunny', 'data/bunny.png') + * .add('spaceship', 'assets/spritesheet.json'); + * loader.add('scoreFont', 'assets/score.fnt'); + * + * // Chainable `pre` to add a middleware that runs for each resource, *before* loading that resource. + * // This is useful to implement custom caching modules (using filesystem, indexeddb, memory, etc). + * loader.pre(cachingMiddleware); + * + * // Chainable `use` to add a middleware that runs for each resource, *after* loading that resource. + * // This is useful to implement custom parsing modules (like spritesheet parsers, spine parser, etc). + * loader.use(parsingMiddleware); + * + * // The `load` method loads the queue of resources, and calls the passed in callback called once all + * // resources have loaded. + * loader.load((loader, resources) => { + * // resources is an object where the key is the name of the resource loaded and the value is the resource object. + * // They have a couple default properties: + * // - `url`: The URL that the resource was loaded from + * // - `error`: The error that happened when trying to load (if any) + * // - `data`: The raw data that was loaded + * // also may contain other properties based on the middleware that runs. + * sprites.bunny = new PIXI.TilingSprite(resources.bunny.texture); + * sprites.spaceship = new PIXI.TilingSprite(resources.spaceship.texture); + * sprites.scoreFont = new PIXI.TilingSprite(resources.scoreFont.texture); + * }); * - * loader.load(); + * // throughout the process multiple signals can be dispatched. + * loader.onProgress.add(() => {}); // called once per loaded/errored file + * loader.onError.add(() => {}); // called once per errored file + * loader.onLoad.add(() => {}); // called once per loaded file + * loader.onComplete.add(() => {}); // called once when the queued resources all load. * ``` * * @see https://github.com/englercj/resource-loader @@ -31555,14 +36261,33 @@ var Loader = function (_ResourceLoader) { var _this = _possibleConstructorReturn(this, _ResourceLoader.call(this, baseUrl, concurrency)); + _eventemitter2.default.call(_this); + for (var i = 0; i < Loader._pixiMiddleware.length; ++i) { _this.use(Loader._pixiMiddleware[i]()); } + + // Compat layer, translate the new v2 signals into old v1 events. + _this.onStart.add(function (l) { + return _this.emit('start', l); + }); + _this.onProgress.add(function (l, r) { + return _this.emit('progress', l, r); + }); + _this.onError.add(function (e, l, r) { + return _this.emit('error', e, l, r); + }); + _this.onLoad.add(function (l, r) { + return _this.emit('load', l, r); + }); + _this.onComplete.add(function (l, r) { + return _this.emit('complete', l, r); + }); return _this; } /** - * Adds a default middleware to the pixi loader. + * Adds a default middleware to the PixiJS loader. * * @static * @param {Function} fn - The middleware to add. @@ -31573,15 +36298,30 @@ var Loader = function (_ResourceLoader) { Loader._pixiMiddleware.push(fn); }; + /** + * Destroy the loader, removes references. + */ + + + Loader.prototype.destroy = function destroy() { + this.removeAllListeners(); + this.reset(); + }; + return Loader; }(_resourceLoader2.default); -exports.default = Loader; +// Copy EE3 prototype (mixin) +exports.default = Loader; +for (var k in _eventemitter2.default.prototype) { + Loader.prototype[k] = _eventemitter2.default.prototype[k]; +} + Loader._pixiMiddleware = [ // parse any blob into more usable objects (e.g. Image) -_resourceLoader2.default.middleware.parsing.blob, +_blob.blobMiddlewareFactory, // parse any Image objects into textures _textureParser2.default, // parse any spritesheet data into multiple textures @@ -31594,18 +36334,17 @@ var Resource = _resourceLoader2.default.Resource; Resource.setExtensionXhrType('fnt', Resource.XHR_RESPONSE_TYPE.DOCUMENT); -},{"./bitmapFontParser":148,"./spritesheetParser":151,"./textureParser":152,"resource-loader":35}],151:[function(require,module,exports){ +},{"./bitmapFontParser":161,"./spritesheetParser":164,"./textureParser":165,"eventemitter3":20,"resource-loader":36,"resource-loader/lib/middlewares/parsing/blob":37}],164:[function(require,module,exports){ 'use strict'; exports.__esModule = true; exports.default = function () { return function spritesheetParser(resource, next) { - var resourcePath = void 0; var imageResourceName = resource.name + '_image'; // skip if no data, its not json, it isn't spritesheet data, or the image resource already exists - if (!resource.data || !resource.isJson || !resource.data.frames || this.resources[imageResourceName]) { + if (!resource.data || resource.type !== _resourceLoader.Resource.TYPE.JSON || !resource.data.frames || this.resources[imageResourceName]) { next(); return; @@ -31614,105 +36353,47 @@ exports.default = function () { var loadOptions = { crossOrigin: resource.crossOrigin, loadType: _resourceLoader.Resource.LOAD_TYPE.IMAGE, - metadata: resource.metadata.imageMetadata + metadata: resource.metadata.imageMetadata, + parentResource: resource }; - // Prepend url path unless the resource image is a data url - if (resource.isDataUrl) { - resourcePath = resource.data.meta.image; - } else { - resourcePath = _path2.default.dirname(resource.url.replace(this.baseUrl, '')) + '/' + resource.data.meta.image; - } + var resourcePath = getResourcePath(resource, this.baseUrl); // load the image for this sheet this.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res) { - resource.textures = {}; - - var frames = resource.data.frames; - var frameKeys = Object.keys(frames); - var resolution = core.utils.getResolutionOfUrl(resource.url); - var batchIndex = 0; - - function processFrames(initialFrameIndex, maxFrames) { - var frameIndex = initialFrameIndex; - - while (frameIndex - initialFrameIndex < maxFrames && frameIndex < frameKeys.length) { - var i = frameKeys[frameIndex]; - var rect = frames[i].frame; - - if (rect) { - var frame = null; - var trim = null; - var orig = new core.Rectangle(0, 0, frames[i].sourceSize.w / resolution, frames[i].sourceSize.h / resolution); - - if (frames[i].rotated) { - frame = new core.Rectangle(rect.x / resolution, rect.y / resolution, rect.h / resolution, rect.w / resolution); - } else { - frame = new core.Rectangle(rect.x / resolution, rect.y / resolution, rect.w / resolution, rect.h / resolution); - } - - // Check to see if the sprite is trimmed - if (frames[i].trimmed) { - trim = new core.Rectangle(frames[i].spriteSourceSize.x / resolution, frames[i].spriteSourceSize.y / resolution, frames[i].spriteSourceSize.w / resolution, frames[i].spriteSourceSize.h / resolution); - } - - resource.textures[i] = new core.Texture(res.texture.baseTexture, frame, orig, trim, frames[i].rotated ? 2 : 0); - - // lets also add the frame to pixi's global cache for fromFrame and fromImage functions - core.utils.TextureCache[i] = resource.textures[i]; - } - - frameIndex++; - } - } - - function shouldProcessNextBatch() { - return batchIndex * BATCH_SIZE < frameKeys.length; - } - - function processNextBatch(done) { - processFrames(batchIndex * BATCH_SIZE, BATCH_SIZE); - batchIndex++; - setTimeout(done, 0); - } - - function iteration() { - processNextBatch(function () { - if (shouldProcessNextBatch()) { - iteration(); - } else { - next(); - } - }); - } + var spritesheet = new _core.Spritesheet(res.texture.baseTexture, resource.data, resource.url); - if (frameKeys.length <= BATCH_SIZE) { - processFrames(0, BATCH_SIZE); + spritesheet.parse(function () { + resource.spritesheet = spritesheet; + resource.textures = spritesheet.textures; next(); - } else { - iteration(); - } + }); }); }; }; +exports.getResourcePath = getResourcePath; + var _resourceLoader = require('resource-loader'); -var _path = require('path'); +var _url = require('url'); -var _path2 = _interopRequireDefault(_path); +var _url2 = _interopRequireDefault(_url); var _core = require('../core'); -var core = _interopRequireWildcard(_core); - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -var BATCH_SIZE = 1000; +function getResourcePath(resource, baseUrl) { + // Prepend url path unless the resource image is a data url + if (resource.isDataUrl) { + return resource.data.meta.image; + } + + return _url2.default.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image); +} -},{"../core":61,"path":23,"resource-loader":35}],152:[function(require,module,exports){ +},{"../core":65,"resource-loader":36,"url":38}],165:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -31720,28 +36401,22 @@ exports.__esModule = true; exports.default = function () { return function textureParser(resource, next) { // create a new texture if the data is an Image object - if (resource.data && resource.isImage) { - var baseTexture = new core.BaseTexture(resource.data, null, core.utils.getResolutionOfUrl(resource.url)); - - baseTexture.imageUrl = resource.url; - resource.texture = new core.Texture(baseTexture); - - // lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions - core.utils.BaseTextureCache[resource.url] = baseTexture; - core.utils.TextureCache[resource.url] = resource.texture; + if (resource.data && resource.type === _resourceLoader.Resource.TYPE.IMAGE) { + resource.texture = _Texture2.default.fromLoader(resource.data, resource.url, resource.name); } - next(); }; }; -var _core = require('../core'); +var _resourceLoader = require('resource-loader'); -var core = _interopRequireWildcard(_core); +var _Texture = require('../core/textures/Texture'); -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } +var _Texture2 = _interopRequireDefault(_Texture); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -},{"../core":61}],153:[function(require,module,exports){ +},{"../core/textures/Texture":115,"resource-loader":36}],166:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -31752,6 +36427,12 @@ var _core = require('../core'); var core = _interopRequireWildcard(_core); +var _TextureTransform = require('../extras/TextureTransform'); + +var _TextureTransform2 = _interopRequireDefault(_TextureTransform); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -31791,7 +36472,7 @@ var Mesh = function (_core$Container) { */ var _this = _possibleConstructorReturn(this, _core$Container.call(this)); - _this._texture = null; + _this._texture = texture; /** * The Uvs of the Mesh @@ -31807,8 +36488,10 @@ var Mesh = function (_core$Container) { */ _this.vertices = vertices || new Float32Array([0, 0, 100, 0, 100, 100, 0, 100]); - /* - * @member {Uint16Array} An array containing the indices of the vertices + /** + * An array containing the indices of the vertices + * + * @member {Uint16Array} */ // TODO auto generate this based on draw mode! _this.indices = indices || new Uint16Array([0, 1, 3, 2]); @@ -31853,9 +36536,6 @@ var Mesh = function (_core$Container) { */ _this.drawMode = drawMode || Mesh.DRAW_MODES.TRIANGLE_MESH; - // run texture setter; - _this.texture = texture; - /** * The default shader that is used if a mesh doesn't have a more specific one. * @@ -31868,11 +36548,43 @@ var Mesh = function (_core$Container) { * tint effect. * * @member {number} - * @memberof PIXI.mesh.Mesh# */ _this.tintRgb = new Float32Array([1, 1, 1]); - _this._glDatas = []; + /** + * A map of renderer IDs to webgl render data + * + * @private + * @member {object} + */ + _this._glDatas = {}; + + /** + * transform that is applied to UV to get the texture coords + * its updated independently from texture uvTransform + * updates of uvs are tied to that thing + * + * @member {PIXI.extras.TextureTransform} + * @private + */ + _this._uvTransform = new _TextureTransform2.default(texture); + + /** + * whether or not upload uvTransform to shader + * if its false, then uvs should be pre-multiplied + * if you change it for generated mesh, please call 'refresh(true)' + * @member {boolean} + * @default false + */ + _this.uploadUvTransform = false; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * @member {string} + * @default 'mesh' + */ + _this.pluginName = 'mesh'; return _this; } @@ -31885,8 +36597,9 @@ var Mesh = function (_core$Container) { Mesh.prototype._renderWebGL = function _renderWebGL(renderer) { - renderer.setObjectRenderer(renderer.plugins.mesh); - renderer.plugins.mesh.render(this); + this.refresh(); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); }; /** @@ -31898,7 +36611,8 @@ var Mesh = function (_core$Container) { Mesh.prototype._renderCanvas = function _renderCanvas(renderer) { - renderer.plugins.mesh.render(this); + this.refresh(); + renderer.plugins[this.pluginName].render(this); }; /** @@ -31908,7 +36622,45 @@ var Mesh = function (_core$Container) { */ - Mesh.prototype._onTextureUpdate = function _onTextureUpdate() {} + Mesh.prototype._onTextureUpdate = function _onTextureUpdate() { + this._uvTransform.texture = this._texture; + this.refresh(); + }; + + /** + * multiplies uvs only if uploadUvTransform is false + * call it after you change uvs manually + * make sure that texture is valid + */ + + + Mesh.prototype.multiplyUvs = function multiplyUvs() { + if (!this.uploadUvTransform) { + this._uvTransform.multiplyUvs(this.uvs); + } + }; + + /** + * Refreshes uvs for generated meshes (rope, plane) + * sometimes refreshes vertices too + * + * @param {boolean} [forceUpdate=false] if true, matrices will be updated any case + */ + + + Mesh.prototype.refresh = function refresh(forceUpdate) { + if (this._uvTransform.update(forceUpdate)) { + this._refresh(); + } + }; + + /** + * re-calculates mesh coords + * @protected + */ + + + Mesh.prototype._refresh = function _refresh() {} /* empty */ @@ -31968,7 +36720,6 @@ var Mesh = function (_core$Container) { * The texture that the mesh uses. * * @member {PIXI.Texture} - * @memberof PIXI.mesh.Mesh# */ @@ -31976,15 +36727,9 @@ var Mesh = function (_core$Container) { key: 'texture', get: function get() { return this._texture; - } - - /** - * Sets the texture the mesh uses. - * - * @param {Texture} value - The value to set. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { if (this._texture === value) { return; } @@ -32005,7 +36750,6 @@ var Mesh = function (_core$Container) { * The tint applied to the mesh. This is a hex value. A value of 0xFFFFFF will remove any tint effect. * * @member {number} - * @memberof PIXI.mesh.Mesh# * @default 0xFFFFFF */ @@ -32013,15 +36757,9 @@ var Mesh = function (_core$Container) { key: 'tint', get: function get() { return core.utils.rgb2hex(this.tintRgb); - } - - /** - * Sets the tint the mesh uses. - * - * @param {number} value - The value to set. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this.tintRgb = core.utils.hex2rgb(value, this.tintRgb); } }]); @@ -32046,7 +36784,7 @@ Mesh.DRAW_MODES = { TRIANGLES: 1 }; -},{"../core":61}],154:[function(require,module,exports){ +},{"../core":65,"../extras/TextureTransform":136}],167:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -32114,16 +36852,8 @@ var NineSlicePlane = function (_Plane) { var _this = _possibleConstructorReturn(this, _Plane.call(this, texture, 4, 4)); - var uvs = _this.uvs; - - // right and bottom uv's are always 1 - uvs[6] = uvs[14] = uvs[22] = uvs[30] = 1; - uvs[25] = uvs[27] = uvs[29] = uvs[31] = 1; - - _this._origWidth = texture.width; - _this._origHeight = texture.height; - _this._uvw = 1 / _this._origWidth; - _this._uvh = 1 / _this._origHeight; + _this._origWidth = texture.orig.width; + _this._origHeight = texture.orig.height; /** * The width of the NineSlicePlane, setting this will actually modify the vertices and UV's of this plane @@ -32132,7 +36862,7 @@ var NineSlicePlane = function (_Plane) { * @memberof PIXI.NineSlicePlane# * @override */ - _this.width = texture.width; + _this._width = _this._origWidth; /** * The height of the NineSlicePlane, setting this will actually modify the vertices and UV's of this plane @@ -32141,17 +36871,14 @@ var NineSlicePlane = function (_Plane) { * @memberof PIXI.NineSlicePlane# * @override */ - _this.height = texture.height; - - uvs[2] = uvs[10] = uvs[18] = uvs[26] = _this._uvw * leftWidth; - uvs[4] = uvs[12] = uvs[20] = uvs[28] = 1 - _this._uvw * rightWidth; - uvs[9] = uvs[11] = uvs[13] = uvs[15] = _this._uvh * topHeight; - uvs[17] = uvs[19] = uvs[21] = uvs[23] = 1 - _this._uvh * bottomHeight; + _this._height = _this._origHeight; /** * The width of the left column (a) * * @member {number} + * @memberof PIXI.NineSlicePlane# + * @override */ _this.leftWidth = typeof leftWidth !== 'undefined' ? leftWidth : DEFAULT_BORDER_SIZE; @@ -32159,6 +36886,8 @@ var NineSlicePlane = function (_Plane) { * The width of the right column (b) * * @member {number} + * @memberof PIXI.NineSlicePlane# + * @override */ _this.rightWidth = typeof rightWidth !== 'undefined' ? rightWidth : DEFAULT_BORDER_SIZE; @@ -32166,6 +36895,8 @@ var NineSlicePlane = function (_Plane) { * The height of the top row (c) * * @member {number} + * @memberof PIXI.NineSlicePlane# + * @override */ _this.topHeight = typeof topHeight !== 'undefined' ? topHeight : DEFAULT_BORDER_SIZE; @@ -32173,8 +36904,12 @@ var NineSlicePlane = function (_Plane) { * The height of the bottom row (d) * * @member {number} + * @memberof PIXI.NineSlicePlane# + * @override */ _this.bottomHeight = typeof bottomHeight !== 'undefined' ? bottomHeight : DEFAULT_BORDER_SIZE; + + _this.refresh(true); return _this; } @@ -32297,49 +37032,68 @@ var NineSlicePlane = function (_Plane) { * The width of the NineSlicePlane, setting this will actually modify the vertices and UV's of this plane * * @member {number} - * @memberof PIXI.NineSlicePlane# */ + /** + * Refreshes NineSlicePlane coords. All of them. + */ + NineSlicePlane.prototype._refresh = function _refresh() { + _Plane.prototype._refresh.call(this); + + var uvs = this.uvs; + var texture = this._texture; + + this._origWidth = texture.orig.width; + this._origHeight = texture.orig.height; + + var _uvw = 1.0 / this._origWidth; + var _uvh = 1.0 / this._origHeight; + + uvs[0] = uvs[8] = uvs[16] = uvs[24] = 0; + uvs[1] = uvs[3] = uvs[5] = uvs[7] = 0; + uvs[6] = uvs[14] = uvs[22] = uvs[30] = 1; + uvs[25] = uvs[27] = uvs[29] = uvs[31] = 1; + + uvs[2] = uvs[10] = uvs[18] = uvs[26] = _uvw * this._leftWidth; + uvs[4] = uvs[12] = uvs[20] = uvs[28] = 1 - _uvw * this._rightWidth; + uvs[9] = uvs[11] = uvs[13] = uvs[15] = _uvh * this._topHeight; + uvs[17] = uvs[19] = uvs[21] = uvs[23] = 1 - _uvh * this._bottomHeight; + + this.updateHorizontalVertices(); + this.updateVerticalVertices(); + + this.dirty = true; + + this.multiplyUvs(); + }; + _createClass(NineSlicePlane, [{ key: 'width', get: function get() { return this._width; - } - - /** - * Sets the width. - * - * @param {number} value - the value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._width = value; - this.updateVerticalVertices(); + this._refresh(); } /** * The height of the NineSlicePlane, setting this will actually modify the vertices and UV's of this plane * * @member {number} - * @memberof PIXI.NineSlicePlane# */ }, { key: 'height', get: function get() { return this._height; - } - - /** - * Sets the height. - * - * @param {number} value - the value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._height = value; - this.updateHorizontalVertices(); + this._refresh(); } /** @@ -32352,24 +37106,11 @@ var NineSlicePlane = function (_Plane) { key: 'leftWidth', get: function get() { return this._leftWidth; - } - - /** - * Sets the width of the left column. - * - * @param {number} value - the value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._leftWidth = value; - - var uvs = this.uvs; - var vertices = this.vertices; - - uvs[2] = uvs[10] = uvs[18] = uvs[26] = this._uvw * value; - vertices[2] = vertices[10] = vertices[18] = vertices[26] = value; - - this.dirty = true; + this._refresh(); } /** @@ -32382,24 +37123,11 @@ var NineSlicePlane = function (_Plane) { key: 'rightWidth', get: function get() { return this._rightWidth; - } - - /** - * Sets the width of the right column. - * - * @param {number} value - the value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._rightWidth = value; - - var uvs = this.uvs; - var vertices = this.vertices; - - uvs[4] = uvs[12] = uvs[20] = uvs[28] = 1 - this._uvw * value; - vertices[4] = vertices[12] = vertices[20] = vertices[28] = this._width - value; - - this.dirty = true; + this._refresh(); } /** @@ -32412,24 +37140,11 @@ var NineSlicePlane = function (_Plane) { key: 'topHeight', get: function get() { return this._topHeight; - } - - /** - * Sets the height of the top row. - * - * @param {number} value - the value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._topHeight = value; - - var uvs = this.uvs; - var vertices = this.vertices; - - uvs[9] = uvs[11] = uvs[13] = uvs[15] = this._uvh * value; - vertices[9] = vertices[11] = vertices[13] = vertices[15] = value; - - this.dirty = true; + this._refresh(); } /** @@ -32442,24 +37157,11 @@ var NineSlicePlane = function (_Plane) { key: 'bottomHeight', get: function get() { return this._bottomHeight; - } - - /** - * Sets the height of the bottom row. - * - * @param {number} value - the value to set to. - */ - , - set: function set(value) { + }, + set: function set(value) // eslint-disable-line require-jsdoc + { this._bottomHeight = value; - - var uvs = this.uvs; - var vertices = this.vertices; - - uvs[17] = uvs[19] = uvs[21] = uvs[23] = 1 - this._uvh * value; - vertices[17] = vertices[19] = vertices[21] = vertices[23] = this._height - value; - - this.dirty = true; + this._refresh(); } }]); @@ -32468,7 +37170,7 @@ var NineSlicePlane = function (_Plane) { exports.default = NineSlicePlane; -},{"./Plane":155}],155:[function(require,module,exports){ +},{"./Plane":168}],168:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -32531,18 +37233,18 @@ var Plane = function (_Mesh) { } /** - * Refreshes + * Refreshes plane coordinates * */ - Plane.prototype.refresh = function refresh() { + Plane.prototype._refresh = function _refresh() { + var texture = this._texture; var total = this.verticesX * this.verticesY; var verts = []; var colors = []; var uvs = []; var indices = []; - var texture = this.texture; var segmentsX = this.verticesX - 1; var segmentsY = this.verticesY - 1; @@ -32556,8 +37258,7 @@ var Plane = function (_Mesh) { verts.push(x * sizeX, y * sizeY); - // this works for rectangular textures. - uvs.push(texture._uvs.x0 + (texture._uvs.x1 - texture._uvs.x0) * (x / (this.verticesX - 1)), texture._uvs.y0 + (texture._uvs.y3 - texture._uvs.y0) * (y / (this.verticesY - 1))); + uvs.push(x / segmentsX, y / segmentsY); } // cons @@ -32582,8 +37283,9 @@ var Plane = function (_Mesh) { this.uvs = new Float32Array(uvs); this.colors = new Float32Array(colors); this.indices = new Uint16Array(indices); - this.indexDirty = true; + + this.multiplyUvs(); }; /** @@ -32607,7 +37309,7 @@ var Plane = function (_Mesh) { exports.default = Plane; -},{"./Mesh":153}],156:[function(require,module,exports){ +},{"./Mesh":166}],169:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -32616,12 +37318,6 @@ var _Mesh2 = require('./Mesh'); var _Mesh3 = _interopRequireDefault(_Mesh2); -var _core = require('../core'); - -var core = _interopRequireWildcard(_core); - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -32655,41 +37351,49 @@ var Rope = function (_Mesh) { function Rope(texture, points) { _classCallCheck(this, Rope); - /* - * @member {PIXI.Point[]} An array of points that determine the rope + /** + * An array of points that determine the rope + * + * @member {PIXI.Point[]} */ var _this = _possibleConstructorReturn(this, _Mesh.call(this, texture)); _this.points = points; - /* - * @member {Float32Array} An array of vertices used to construct this rope. + /** + * An array of vertices used to construct this rope. + * + * @member {Float32Array} */ _this.vertices = new Float32Array(points.length * 4); - /* - * @member {Float32Array} The WebGL Uvs of the rope. + /** + * The WebGL Uvs of the rope. + * + * @member {Float32Array} */ _this.uvs = new Float32Array(points.length * 4); - /* - * @member {Float32Array} An array containing the color components + /** + * An array containing the color components + * + * @member {Float32Array} */ _this.colors = new Float32Array(points.length * 2); - /* - * @member {Uint16Array} An array containing the indices of the vertices + /** + * An array containing the indices of the vertices + * + * @member {Uint16Array} */ _this.indices = new Uint16Array(points.length * 2); /** - * Tracker for if the rope is ready to be drawn. Needed because Mesh ctor can - * call _onTextureUpdated which could call refresh too early. - * + * refreshes vertices on every updateTransform * @member {boolean} - * @private + * @default true */ - _this._ready = true; + _this.autoUpdate = true; _this.refresh(); return _this; @@ -32701,7 +37405,7 @@ var Rope = function (_Mesh) { */ - Rope.prototype.refresh = function refresh() { + Rope.prototype._refresh = function _refresh() { var points = this.points; // if too little points, or texture hasn't got UVs set yet just move on. @@ -32709,19 +37413,23 @@ var Rope = function (_Mesh) { return; } + // if the number of points has changed we will need to recreate the arraybuffers + if (this.vertices.length / 4 !== points.length) { + this.vertices = new Float32Array(points.length * 4); + this.uvs = new Float32Array(points.length * 4); + this.colors = new Float32Array(points.length * 2); + this.indices = new Uint16Array(points.length * 2); + } + var uvs = this.uvs; var indices = this.indices; var colors = this.colors; - var textureUvs = this._texture._uvs; - var offset = new core.Point(textureUvs.x0, textureUvs.y0); - var factor = new core.Point(textureUvs.x2 - textureUvs.x0, textureUvs.y2 - textureUvs.y0); - - uvs[0] = 0 + offset.x; - uvs[1] = 0 + offset.y; - uvs[2] = 0 + offset.x; - uvs[3] = Number(factor.y) + offset.y; + uvs[0] = 0; + uvs[1] = 0; + uvs[2] = 0; + uvs[3] = 1; colors[0] = 1; colors[1] = 1; @@ -32736,11 +37444,11 @@ var Rope = function (_Mesh) { var index = i * 4; var amount = i / (total - 1); - uvs[index] = amount * factor.x + offset.x; - uvs[index + 1] = 0 + offset.y; + uvs[index] = amount; + uvs[index + 1] = 0; - uvs[index + 2] = amount * factor.x + offset.x; - uvs[index + 3] = Number(factor.y) + offset.y; + uvs[index + 2] = amount; + uvs[index + 3] = 1; index = i * 2; colors[index] = 1; @@ -32751,34 +37459,20 @@ var Rope = function (_Mesh) { indices[index + 1] = index + 1; } - this.dirty = true; - this.indexDirty = true; - }; - - /** - * Clear texture UVs when new texture is set - * - * @private - */ - - - Rope.prototype._onTextureUpdate = function _onTextureUpdate() { - _Mesh.prototype._onTextureUpdate.call(this); + // ensure that the changes are uploaded + this.dirty++; + this.indexDirty++; - // wait for the Rope ctor to finish before calling refresh - if (this._ready) { - this.refresh(); - } + this.multiplyUvs(); + this.refreshVertices(); }; /** - * Updates the object transform for rendering - * - * @private + * refreshes vertices of Rope mesh */ - Rope.prototype.updateTransform = function updateTransform() { + Rope.prototype.refreshVertices = function refreshVertices() { var points = this.points; if (points.length < 1) { @@ -32830,7 +37524,19 @@ var Rope = function (_Mesh) { lastPoint = point; } + }; + + /** + * Updates the object transform for rendering + * + * @private + */ + + Rope.prototype.updateTransform = function updateTransform() { + if (this.autoUpdate) { + this.refreshVertices(); + } this.containerUpdateTransform(); }; @@ -32839,7 +37545,7 @@ var Rope = function (_Mesh) { exports.default = Rope; -},{"../core":61,"./Mesh":153}],157:[function(require,module,exports){ +},{"./Mesh":166}],170:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -32895,6 +37601,8 @@ var MeshSpriteRenderer = function () { context.setTransform(transform.a * res, transform.b * res, transform.c * res, transform.d * res, transform.tx * res, transform.ty * res); } + renderer.setBlendMode(mesh.blendMode); + if (mesh.drawMode === _Mesh2.default.DRAW_MODES.TRIANGLE_MESH) { this._renderTriangleMesh(mesh); } else { @@ -32971,12 +37679,30 @@ var MeshSpriteRenderer = function () { var textureWidth = base.width; var textureHeight = base.height; - var u0 = uvs[index0] * base.width; - var u1 = uvs[index1] * base.width; - var u2 = uvs[index2] * base.width; - var v0 = uvs[index0 + 1] * base.height; - var v1 = uvs[index1 + 1] * base.height; - var v2 = uvs[index2 + 1] * base.height; + var u0 = void 0; + var u1 = void 0; + var u2 = void 0; + var v0 = void 0; + var v1 = void 0; + var v2 = void 0; + + if (mesh.uploadUvTransform) { + var ut = mesh._uvTransform.mapCoord; + + u0 = (uvs[index0] * ut.a + uvs[index0 + 1] * ut.c + ut.tx) * base.width; + u1 = (uvs[index1] * ut.a + uvs[index1 + 1] * ut.c + ut.tx) * base.width; + u2 = (uvs[index2] * ut.a + uvs[index2 + 1] * ut.c + ut.tx) * base.width; + v0 = (uvs[index0] * ut.b + uvs[index0 + 1] * ut.d + ut.ty) * base.height; + v1 = (uvs[index1] * ut.b + uvs[index1 + 1] * ut.d + ut.ty) * base.height; + v2 = (uvs[index2] * ut.b + uvs[index2 + 1] * ut.d + ut.ty) * base.height; + } else { + u0 = uvs[index0] * base.width; + u1 = uvs[index1] * base.width; + u2 = uvs[index2] * base.width; + v0 = uvs[index0 + 1] * base.height; + v1 = uvs[index1 + 1] * base.height; + v2 = uvs[index2 + 1] * base.height; + } var x0 = vertices[index0]; var x1 = vertices[index1]; @@ -33041,6 +37767,7 @@ var MeshSpriteRenderer = function () { context.drawImage(textureSource, 0, 0, textureWidth * base.resolution, textureHeight * base.resolution, 0, 0, textureWidth, textureHeight); context.restore(); + this.renderer.invalidateBlendMode(); }; /** @@ -33101,7 +37828,7 @@ exports.default = MeshSpriteRenderer; core.CanvasRenderer.registerPlugin('mesh', MeshSpriteRenderer); -},{"../../core":61,"../Mesh":153}],158:[function(require,module,exports){ +},{"../../core":65,"../Mesh":166}],171:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -33162,11 +37889,10 @@ Object.defineProperty(exports, 'Rope', { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -},{"./Mesh":153,"./NineSlicePlane":154,"./Plane":155,"./Rope":156,"./canvas/CanvasMeshRenderer":157,"./webgl/MeshRenderer":159}],159:[function(require,module,exports){ +},{"./Mesh":166,"./NineSlicePlane":167,"./Plane":168,"./Rope":169,"./canvas/CanvasMeshRenderer":170,"./webgl/MeshRenderer":172}],172:[function(require,module,exports){ 'use strict'; exports.__esModule = true; -exports.MeshRenderer = undefined; var _core = require('../../core'); @@ -33180,6 +37906,8 @@ var _Mesh = require('../Mesh'); var _Mesh2 = _interopRequireDefault(_Mesh); +var _path = require('path'); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } @@ -33190,13 +37918,17 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - // eslint-disable-line no-undef +var matrixIdentity = core.Matrix.IDENTITY; /** * WebGL renderer plugin for tiling sprites + * + * @class + * @memberof PIXI + * @extends PIXI.ObjectRenderer */ -var MeshRenderer = exports.MeshRenderer = function (_core$ObjectRenderer) { +var MeshRenderer = function (_core$ObjectRenderer) { _inherits(MeshRenderer, _core$ObjectRenderer); /** @@ -33223,7 +37955,7 @@ var MeshRenderer = exports.MeshRenderer = function (_core$ObjectRenderer) { MeshRenderer.prototype.onContextChange = function onContextChange() { var gl = this.renderer.gl; - this.shader = new core.Shader(gl, "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 translationMatrix;\nuniform mat3 projectionMatrix;\n\nvarying vec2 vTextureCoord;\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n\n vTextureCoord = aTextureCoord;\n}\n", "#define GLSLIFY 1\nvarying vec2 vTextureCoord;\nuniform float alpha;\nuniform vec3 tint;\n\nuniform sampler2D uSampler;\n\nvoid main(void)\n{\n gl_FragColor = texture2D(uSampler, vTextureCoord) * vec4(tint * alpha, alpha);\n}\n"); + this.shader = new core.Shader(gl, 'attribute vec2 aVertexPosition;\r\nattribute vec2 aTextureCoord;\r\n\r\nuniform mat3 projectionMatrix;\r\nuniform mat3 translationMatrix;\r\nuniform mat3 uTransform;\r\n\r\nvarying vec2 vTextureCoord;\r\n\r\nvoid main(void)\r\n{\r\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\r\n\r\n vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;\r\n}\r\n', 'varying vec2 vTextureCoord;\r\nuniform vec4 uColor;\r\n\r\nuniform sampler2D uSampler;\r\n\r\nvoid main(void)\r\n{\r\n gl_FragColor = texture2D(uSampler, vTextureCoord) * uColor;\r\n}\r\n'); }; /** @@ -33245,13 +37977,15 @@ var MeshRenderer = exports.MeshRenderer = function (_core$ObjectRenderer) { var glData = mesh._glDatas[renderer.CONTEXT_UID]; if (!glData) { + renderer.bindVao(null); + glData = { shader: this.shader, vertexBuffer: _pixiGlCore2.default.GLBuffer.createVertexBuffer(gl, mesh.vertices, gl.STREAM_DRAW), uvBuffer: _pixiGlCore2.default.GLBuffer.createVertexBuffer(gl, mesh.uvs, gl.STREAM_DRAW), indexBuffer: _pixiGlCore2.default.GLBuffer.createIndexBuffer(gl, mesh.indices, gl.STATIC_DRAW), // build the vao object that will render.. - vao: new _pixiGlCore2.default.VertexArrayObject(gl), + vao: null, dirty: mesh.dirty, indexDirty: mesh.indexDirty }; @@ -33262,45 +37996,63 @@ var MeshRenderer = exports.MeshRenderer = function (_core$ObjectRenderer) { mesh._glDatas[renderer.CONTEXT_UID] = glData; } + renderer.bindVao(glData.vao); + if (mesh.dirty !== glData.dirty) { glData.dirty = mesh.dirty; - glData.uvBuffer.upload(); + glData.uvBuffer.upload(mesh.uvs); } if (mesh.indexDirty !== glData.indexDirty) { glData.indexDirty = mesh.indexDirty; - glData.indexBuffer.upload(); + glData.indexBuffer.upload(mesh.indices); } - glData.vertexBuffer.upload(); + glData.vertexBuffer.upload(mesh.vertices); renderer.bindShader(glData.shader); - renderer.bindTexture(texture, 0); - renderer.state.setBlendMode(mesh.blendMode); + glData.shader.uniforms.uSampler = renderer.bindTexture(texture); + + renderer.state.setBlendMode(core.utils.correctBlendMode(mesh.blendMode, texture.baseTexture.premultipliedAlpha)); + + if (glData.shader.uniforms.uTransform) { + if (mesh.uploadUvTransform) { + glData.shader.uniforms.uTransform = mesh._uvTransform.mapCoord.toArray(true); + } else { + glData.shader.uniforms.uTransform = matrixIdentity.toArray(true); + } + } glData.shader.uniforms.translationMatrix = mesh.worldTransform.toArray(true); - glData.shader.uniforms.alpha = mesh.worldAlpha; - glData.shader.uniforms.tint = mesh.tintRgb; + + glData.shader.uniforms.uColor = core.utils.premultiplyRgba(mesh.tintRgb, mesh.worldAlpha, glData.shader.uniforms.uColor, texture.baseTexture.premultipliedAlpha); var drawMode = mesh.drawMode === _Mesh2.default.DRAW_MODES.TRIANGLE_MESH ? gl.TRIANGLE_STRIP : gl.TRIANGLES; - glData.vao.bind().draw(drawMode, mesh.indices.length).unbind(); + glData.vao.draw(drawMode, mesh.indices.length, 0); }; return MeshRenderer; }(core.ObjectRenderer); +exports.default = MeshRenderer; + + core.WebGLRenderer.registerPlugin('mesh', MeshRenderer); -},{"../../core":61,"../Mesh":153,"pixi-gl-core":7}],160:[function(require,module,exports){ +},{"../../core":65,"../Mesh":166,"path":25,"pixi-gl-core":7}],173:[function(require,module,exports){ 'use strict'; exports.__esModule = true; +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + var _core = require('../core'); var core = _interopRequireWildcard(_core); +var _utils = require('../core/utils'); + function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -33327,7 +38079,7 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" * } * ``` * - * And here you have a hundred sprites that will be renderer at the speed of light. + * And here you have a hundred sprites that will be rendered at the speed of light. * * @class * @extends PIXI.Container @@ -33389,10 +38141,10 @@ var ParticleContainer = function (_core$Container) { _this._batchSize = batchSize; /** - * @member {WebGLBuffer} + * @member {object} * @private */ - _this._glBuffers = []; + _this._glBuffers = {}; /** * @member {number} @@ -33434,6 +38186,18 @@ var ParticleContainer = function (_core$Container) { _this.baseTexture = null; _this.setProperties(properties); + + /** + * The tint applied to the container. + * This is a hex value. A value of 0xFFFFFF will remove any tint effect. + * + * @private + * @member {number} + * @default 0xFFFFFF + */ + _this._tint = 0; + _this.tintRgb = new Float32Array(4); + _this.tint = 0xFFFFFF; return _this; } @@ -33467,14 +38231,21 @@ var ParticleContainer = function (_core$Container) { // PIXI.Container.prototype.updateTransform.call( this ); }; + /** + * The tint applied to the container. This is a hex value. + * A value of 0xFFFFFF will remove any tint effect. + ** IMPORTANT: This is a webGL only feature and will be ignored by the canvas renderer. + * @member {number} + * @default 0xFFFFFF + */ + + /** * Renders the container using the WebGL renderer * * @private * @param {PIXI.WebGLRenderer} renderer - The webgl renderer */ - - ParticleContainer.prototype.renderWebGL = function renderWebGL(renderer) { var _this2 = this; @@ -33534,11 +38305,7 @@ var ParticleContainer = function (_core$Container) { var finalWidth = 0; var finalHeight = 0; - var compositeOperation = renderer.blendModes[this.blendMode]; - - if (compositeOperation !== context.globalCompositeOperation) { - context.globalCompositeOperation = compositeOperation; - } + renderer.setBlendMode(this.blendMode); context.globalAlpha = this.worldAlpha; @@ -33551,7 +38318,7 @@ var ParticleContainer = function (_core$Container) { continue; } - var frame = child.texture.frame; + var frame = child._texture.frame; context.globalAlpha = this.worldAlpha * child.alpha; @@ -33590,9 +38357,9 @@ var ParticleContainer = function (_core$Container) { finalHeight = frame.height; } - var resolution = child.texture.baseTexture.resolution; + var resolution = child._texture.baseTexture.resolution; - context.drawImage(child.texture.baseTexture.source, frame.x * resolution, frame.y * resolution, frame.width * resolution, frame.height * resolution, positionX * resolution, positionY * resolution, finalWidth * resolution, finalHeight * resolution); + context.drawImage(child._texture.baseTexture.source, frame.x * resolution, frame.y * resolution, frame.width * resolution, frame.height * resolution, positionX * renderer.resolution, positionY * renderer.resolution, finalWidth * renderer.resolution, finalHeight * renderer.resolution); } }; @@ -33603,6 +38370,10 @@ var ParticleContainer = function (_core$Container) { * have been set to that value * @param {boolean} [options.children=false] - if set to true, all the children will have their * destroy method called as well. 'options' will be passed on to those calls. + * @param {boolean} [options.texture=false] - Only used for child Sprites if options.children is set to true + * Should it destroy the texture of the child sprite + * @param {boolean} [options.baseTexture=false] - Only used for child Sprites if options.children is set to true + * Should it destroy the base texture of the child sprite */ @@ -33619,12 +38390,24 @@ var ParticleContainer = function (_core$Container) { this._buffers = null; }; + _createClass(ParticleContainer, [{ + key: 'tint', + get: function get() { + return this._tint; + }, + set: function set(value) // eslint-disable-line require-jsdoc + { + this._tint = value; + (0, _utils.hex2rgb)(value, this.tintRgb); + } + }]); + return ParticleContainer; }(core.Container); exports.default = ParticleContainer; -},{"../core":61}],161:[function(require,module,exports){ +},{"../core":65,"../core/utils":124}],174:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -33649,7 +38432,7 @@ Object.defineProperty(exports, 'ParticleRenderer', { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -},{"./ParticleContainer":160,"./webgl/ParticleRenderer":163}],162:[function(require,module,exports){ +},{"./ParticleContainer":173,"./webgl/ParticleRenderer":176}],175:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -33670,7 +38453,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons * @author Mat Groves * * Big thanks to the very clever Matt DesLauriers https://github.com/mattdesl/ - * for creating the original pixi version! + * for creating the original PixiJS version! * Also a thanks to https://github.com/bchevalier for tweaking the tint and alpha so that * they now share 4 bytes on the vertex buffer * @@ -33868,16 +38651,6 @@ var ParticleBuffer = function () { this.staticBuffer.upload(); }; - /** - * Binds the buffers to the GPU - * - */ - - - ParticleBuffer.prototype.bind = function bind() { - this.vao.bind(); - }; - /** * Destroys the ParticleBuffer. * @@ -33899,7 +38672,7 @@ var ParticleBuffer = function () { exports.default = ParticleBuffer; -},{"../../core/utils/createIndicesForQuads":113,"pixi-gl-core":7}],163:[function(require,module,exports){ +},{"../../core/utils/createIndicesForQuads":122,"pixi-gl-core":7}],176:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -33930,7 +38703,7 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" * @author Mat Groves * * Big thanks to the very clever Matt DesLauriers https://github.com/mattdesl/ - * for creating the original pixi version! + * for creating the original PixiJS version! * Also a thanks to https://github.com/bchevalier for tweaking the tint and alpha so that they now * share 4 bytes on the vertex buffer * @@ -34052,6 +38825,7 @@ var ParticleRenderer = function (_core$ObjectRenderer) { var children = container.children; var maxSize = container._maxSize; var batchSize = container._batchSize; + var renderer = this.renderer; var totalChildren = children.length; if (totalChildren === 0) { @@ -34060,28 +38834,29 @@ var ParticleRenderer = function (_core$ObjectRenderer) { totalChildren = maxSize; } - var buffers = container._glBuffers[this.renderer.CONTEXT_UID]; + var buffers = container._glBuffers[renderer.CONTEXT_UID]; if (!buffers) { - buffers = container._glBuffers[this.renderer.CONTEXT_UID] = this.generateBuffers(container); + buffers = container._glBuffers[renderer.CONTEXT_UID] = this.generateBuffers(container); } + var baseTexture = children[0]._texture.baseTexture; + // if the uvs have not updated then no point rendering just yet! - this.renderer.setBlendMode(container.blendMode); + this.renderer.setBlendMode(core.utils.correctBlendMode(container.blendMode, baseTexture.premultipliedAlpha)); - var gl = this.renderer.gl; + var gl = renderer.gl; var m = container.worldTransform.copy(this.tempMatrix); - m.prepend(this.renderer._activeRenderTarget.projectionMatrix); + m.prepend(renderer._activeRenderTarget.projectionMatrix); this.shader.uniforms.projectionMatrix = m.toArray(true); - this.shader.uniforms.uAlpha = container.worldAlpha; - // make sure the texture is bound.. - var baseTexture = children[0]._texture.baseTexture; + this.shader.uniforms.uColor = core.utils.premultiplyRgba(container.tintRgb, container.worldAlpha, this.shader.uniforms.uColor, baseTexture.premultipliedAlpha); - this.renderer.bindTexture(baseTexture); + // make sure the texture is bound.. + this.shader.uniforms.uSampler = renderer.bindTexture(baseTexture); // now lets upload and render the buffers.. for (var i = 0, j = 0; i < totalChildren; i += batchSize, j += 1) { @@ -34103,11 +38878,8 @@ var ParticleRenderer = function (_core$ObjectRenderer) { } // bind the buffer - buffer.vao.bind().draw(gl.TRIANGLES, amount * 6).unbind(); - - // now draw those suckas! - // gl.drawElements(gl.TRIANGLES, amount * 6, gl.UNSIGNED_SHORT, 0); - // this.renderer.drawCount++; + renderer.bindVao(buffer.vao); + buffer.vao.draw(gl.TRIANGLES, amount * 6); } }; @@ -34345,7 +39117,7 @@ exports.default = ParticleRenderer; core.WebGLRenderer.registerPlugin('particle', ParticleRenderer); -},{"../../core":61,"./ParticleBuffer":162,"./ParticleShader":164}],164:[function(require,module,exports){ +},{"../../core":65,"./ParticleBuffer":175,"./ParticleShader":177}],177:[function(require,module,exports){ 'use strict'; exports.__esModule = true; @@ -34380,7 +39152,7 @@ var ParticleShader = function (_Shader) { // vertex shader ['attribute vec2 aVertexPosition;', 'attribute vec2 aTextureCoord;', 'attribute float aColor;', 'attribute vec2 aPositionCoord;', 'attribute vec2 aScale;', 'attribute float aRotation;', 'uniform mat3 projectionMatrix;', 'varying vec2 vTextureCoord;', 'varying float vColor;', 'void main(void){', ' vec2 v = aVertexPosition;', ' v.x = (aVertexPosition.x) * cos(aRotation) - (aVertexPosition.y) * sin(aRotation);', ' v.y = (aVertexPosition.x) * sin(aRotation) + (aVertexPosition.y) * cos(aRotation);', ' v = v + aPositionCoord;', ' gl_Position = vec4((projectionMatrix * vec3(v, 1.0)).xy, 0.0, 1.0);', ' vTextureCoord = aTextureCoord;', ' vColor = aColor;', '}'].join('\n'), // hello - ['varying vec2 vTextureCoord;', 'varying float vColor;', 'uniform sampler2D uSampler;', 'uniform float uAlpha;', 'void main(void){', ' vec4 color = texture2D(uSampler, vTextureCoord) * vColor * uAlpha;', ' if (color.a == 0.0) discard;', ' gl_FragColor = color;', '}'].join('\n'))); + ['varying vec2 vTextureCoord;', 'varying float vColor;', 'uniform sampler2D uSampler;', 'uniform vec4 uColor;', 'void main(void){', ' vec4 color = texture2D(uSampler, vTextureCoord) * vColor * uColor;', ' if (color.a == 0.0) discard;', ' gl_FragColor = color;', '}'].join('\n'))); } return ParticleShader; @@ -34388,7 +39160,7 @@ var ParticleShader = function (_Shader) { exports.default = ParticleShader; -},{"../../core/Shader":41}],165:[function(require,module,exports){ +},{"../../core/Shader":44}],178:[function(require,module,exports){ "use strict"; // References: @@ -34406,7 +39178,7 @@ if (!Math.sign) { }; } -},{}],166:[function(require,module,exports){ +},{}],179:[function(require,module,exports){ 'use strict'; var _objectAssign = require('object-assign'); @@ -34421,7 +39193,7 @@ if (!Object.assign) { // https://github.com/sindresorhus/object-assign // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign -},{"object-assign":21}],167:[function(require,module,exports){ +},{"object-assign":23}],180:[function(require,module,exports){ 'use strict'; require('./Object.assign'); @@ -34446,7 +39218,7 @@ if (!window.Uint16Array) { window.Uint16Array = Array; } -},{"./Math.sign":165,"./Object.assign":166,"./requestAnimationFrame":168}],168:[function(require,module,exports){ +},{"./Math.sign":178,"./Object.assign":179,"./requestAnimationFrame":181}],181:[function(require,module,exports){ (function (global){ 'use strict'; @@ -34518,401 +39290,98 @@ if (!global.requestAnimationFrame) { }; } -if (!global.cancelAnimationFrame) { - global.cancelAnimationFrame = function (id) { - return clearTimeout(id); - }; -} - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) - -},{}],169:[function(require,module,exports){ -'use strict'; - -exports.__esModule = true; - -var _core = require('../../core'); - -var core = _interopRequireWildcard(_core); - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var SharedTicker = core.ticker.shared; - -var CANVAS_START_SIZE = 16; -var DEFAULT_UPLOADS_PER_FRAME = 4; - -/** - * The prepare manager provides functionality to upload content to the GPU - * This cannot be done directly for Canvas like in WebGL, but the effect can be achieved by drawing - * textures to an offline canvas. - * This draw call will force the texture to be moved onto the GPU. - * - * @class - * @memberof PIXI - */ - -var CanvasPrepare = function () { - /** - * @param {PIXI.CanvasRenderer} renderer - A reference to the current renderer - */ - function CanvasPrepare(renderer) { - _classCallCheck(this, CanvasPrepare); - - /** - * Reference to the renderer. - * @type {PIXI.CanvasRenderer} - * @private - */ - this.renderer = renderer; - - /** - * An offline canvas to render textures to - * @type {HTMLCanvasElement} - * @private - */ - this.canvas = document.createElement('canvas'); - this.canvas.width = CANVAS_START_SIZE; - this.canvas.height = CANVAS_START_SIZE; - - /** - * The context to the canvas - * @type {CanvasRenderingContext2D} - * @private - */ - this.ctx = this.canvas.getContext('2d'); - - /** - * Collection of items to uploads at once. - * @type {Array<*>} - * @private - */ - this.queue = []; - - /** - * Collection of additional hooks for finding assets. - * @type {Array} - * @private - */ - this.addHooks = []; - - /** - * Collection of additional hooks for processing assets. - * @type {Array} - * @private - */ - this.uploadHooks = []; - - /** - * Callback to call after completed. - * @type {Array} - * @private - */ - this.completes = []; - - /** - * If prepare is ticking (running). - * @type {boolean} - * @private - */ - this.ticking = false; - - // Add textures to upload - this.register(findBaseTextures, uploadBaseTextures); - } - - /** - * Upload all the textures and graphics to the GPU. - * - * @param {Function|PIXI.DisplayObject|PIXI.Container} item - Either - * the container or display object to search for items to upload or - * the callback function, if items have been added using `prepare.add`. - * @param {Function} [done] - Optional callback when all queued uploads have completed - */ - - - CanvasPrepare.prototype.upload = function upload(item, done) { - if (typeof item === 'function') { - done = item; - item = null; - } - - // If a display object, search for items - // that we could upload - if (item) { - this.add(item); - } - - // Get the items for upload from the display - if (this.queue.length) { - this.numLeft = CanvasPrepare.UPLOADS_PER_FRAME; - - if (done) { - this.completes.push(done); - } - - if (!this.ticking) { - this.ticking = true; - SharedTicker.add(this.tick, this); - } - } else if (done) { - done(); - } - }; - - /** - * Handle tick update - * - * @private - */ - - - CanvasPrepare.prototype.tick = function tick() { - // Upload the graphics - while (this.queue.length && this.numLeft > 0) { - var item = this.queue[0]; - var uploaded = false; - - for (var i = 0, len = this.uploadHooks.length; i < len; i++) { - if (this.uploadHooks[i](this, item)) { - this.numLeft--; - this.queue.shift(); - uploaded = true; - break; - } - } - - if (!uploaded) { - this.queue.shift(); - } - } - - // We're finished - if (this.queue.length) { - this.numLeft = CanvasPrepare.UPLOADS_PER_FRAME; - } else { - this.ticking = false; - - SharedTicker.remove(this.tick, this); - - var completes = this.completes.slice(0); - - this.completes.length = 0; - - for (var _i = 0, _len = completes.length; _i < _len; _i++) { - completes[_i](); - } - } - }; - - /** - * Adds hooks for finding and uploading items. - * - * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array` - function must return `true` if it was able to add item to the queue. - * @param {Function} [uploadHook] - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and - * function must return `true` if it was able to handle upload of item. - * @return {PIXI.CanvasPrepare} Instance of plugin for chaining. - */ - - - CanvasPrepare.prototype.register = function register(addHook, uploadHook) { - if (addHook) { - this.addHooks.push(addHook); - } - - if (uploadHook) { - this.uploadHooks.push(uploadHook); - } - - return this; - }; - - /** - * Manually add an item to the uploading queue. - * - * @param {PIXI.DisplayObject|PIXI.Container|*} item - Object to add to the queue - * @return {PIXI.CanvasPrepare} Instance of plugin for chaining. - */ - - - CanvasPrepare.prototype.add = function add(item) { - // Add additional hooks for finding elements on special - // types of objects that - for (var i = 0, len = this.addHooks.length; i < len; i++) { - if (this.addHooks[i](item, this.queue)) { - break; - } - } - - // Get childen recursively - if (item instanceof core.Container) { - for (var _i2 = item.children.length - 1; _i2 >= 0; _i2--) { - this.add(item.children[_i2]); - } - } - - return this; - }; - - /** - * Destroys the plugin, don't use after this. - * - */ - - - CanvasPrepare.prototype.destroy = function destroy() { - if (this.ticking) { - SharedTicker.remove(this.tick, this); - } - this.ticking = false; - this.addHooks = null; - this.uploadHooks = null; - this.renderer = null; - this.completes = null; - this.queue = null; - this.ctx = null; - this.canvas = null; - }; - - return CanvasPrepare; -}(); - -/** - * The number of graphics or textures to upload to the GPU. - * - * @static - * @type {number} - * @default 4 - */ - - -exports.default = CanvasPrepare; -CanvasPrepare.UPLOADS_PER_FRAME = DEFAULT_UPLOADS_PER_FRAME; - -/** - * Built-in hook to upload PIXI.Texture objects to the GPU. - * - * @private - * @param {*} prepare - Instance of CanvasPrepare - * @param {*} item - Item to check - * @return {boolean} If item was uploaded. - */ -function uploadBaseTextures(prepare, item) { - if (item instanceof core.BaseTexture) { - var image = item.source; - - // Sometimes images (like atlas images) report a size of zero, causing errors on windows phone. - // So if the width or height is equal to zero then use the canvas size - // Otherwise use whatever is smaller, the image dimensions or the canvas dimensions. - var imageWidth = image.width === 0 ? prepare.canvas.width : Math.min(prepare.canvas.width, image.width); - var imageHeight = image.height === 0 ? prepare.canvas.height : Math.min(prepare.canvas.height, image.height); - - // Only a small subsections is required to be drawn to have the whole texture uploaded to the GPU - // A smaller draw can be faster. - prepare.ctx.drawImage(image, 0, 0, imageWidth, imageHeight, 0, 0, prepare.canvas.width, prepare.canvas.height); - - return true; - } - - return false; -} - -/** - * Built-in hook to find textures from Sprites. - * - * @private - * @param {PIXI.DisplayObject} item -Display object to check - * @param {Array<*>} queue - Collection of items to upload - * @return {boolean} if a PIXI.Texture object was found. - */ -function findBaseTextures(item, queue) { - // Objects with textures, like Sprites/Text - if (item instanceof core.BaseTexture) { - if (queue.indexOf(item) === -1) { - queue.push(item); - } - - return true; - } else if (item._texture && item._texture instanceof core.Texture) { - var texture = item._texture.baseTexture; - - if (queue.indexOf(texture) === -1) { - queue.push(texture); - } - - return true; - } - - return false; +if (!global.cancelAnimationFrame) { + global.cancelAnimationFrame = function (id) { + return clearTimeout(id); + }; } -core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare); +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../../core":61}],170:[function(require,module,exports){ +},{}],182:[function(require,module,exports){ 'use strict'; exports.__esModule = true; -var _WebGLPrepare = require('./webgl/WebGLPrepare'); +var _core = require('../core'); -Object.defineProperty(exports, 'webgl', { - enumerable: true, - get: function get() { - return _interopRequireDefault(_WebGLPrepare).default; - } -}); +var core = _interopRequireWildcard(_core); -var _CanvasPrepare = require('./canvas/CanvasPrepare'); +var _CountLimiter = require('./limiters/CountLimiter'); -Object.defineProperty(exports, 'canvas', { - enumerable: true, - get: function get() { - return _interopRequireDefault(_CanvasPrepare).default; - } -}); +var _CountLimiter2 = _interopRequireDefault(_CountLimiter); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -},{"./canvas/CanvasPrepare":169,"./webgl/WebGLPrepare":171}],171:[function(require,module,exports){ -'use strict'; - -exports.__esModule = true; - -var _core = require('../../core'); - -var core = _interopRequireWildcard(_core); - function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var SharedTicker = core.ticker.shared; -var DEFAULT_UPLOADS_PER_FRAME = 4; /** - * The prepare manager provides functionality to upload content to the GPU. + * Default number of uploads per frame using prepare plugin. + * + * @static + * @memberof PIXI.settings + * @name UPLOADS_PER_FRAME + * @type {number} + * @default 4 + */ +core.settings.UPLOADS_PER_FRAME = 4; + +/** + * The prepare manager provides functionality to upload content to the GPU. BasePrepare handles + * basic queuing functionality and is extended by {@link PIXI.prepare.WebGLPrepare} and {@link PIXI.prepare.CanvasPrepare} + * to provide preparation capabilities specific to their respective renderers. + * + * @example + * // Create a sprite + * const sprite = new PIXI.Sprite.fromImage('something.png'); * + * // Load object into GPU + * app.renderer.plugins.prepare.upload(sprite, () => { + * + * //Texture(s) has been uploaded to GPU + * app.stage.addChild(sprite); + * + * }) + * + * @abstract * @class - * @memberof PIXI + * @memberof PIXI.prepare */ -var WebGLPrepare = function () { +var BasePrepare = function () { /** - * @param {PIXI.WebGLRenderer} renderer - A reference to the current renderer + * @param {PIXI.SystemRenderer} renderer - A reference to the current renderer */ - function WebGLPrepare(renderer) { - _classCallCheck(this, WebGLPrepare); + function BasePrepare(renderer) { + var _this = this; + + _classCallCheck(this, BasePrepare); + + /** + * The limiter to be used to control how quickly items are prepared. + * @type {PIXI.prepare.CountLimiter|PIXI.prepare.TimeLimiter} + */ + this.limiter = new _CountLimiter2.default(core.settings.UPLOADS_PER_FRAME); /** * Reference to the renderer. - * @type {PIXI.WebGLRenderer} - * @private + * @type {PIXI.SystemRenderer} + * @protected */ this.renderer = renderer; + /** + * The only real difference between CanvasPrepare and WebGLPrepare is what they pass + * to upload hooks. That different parameter is stored here. + * @type {PIXI.prepare.CanvasPrepare|PIXI.WebGLRenderer} + * @protected + */ + this.uploadHookHelper = null; + /** * Collection of items to uploads at once. * @type {Array<*>} @@ -34948,21 +39417,42 @@ var WebGLPrepare = function () { */ this.ticking = false; - // Add textures and graphics to upload - this.register(findBaseTextures, uploadBaseTextures).register(findGraphics, uploadGraphics); + /** + * 'bound' call for prepareItems(). + * @type {Function} + * @private + */ + this.delayedTick = function () { + // unlikely, but in case we were destroyed between tick() and delayedTick() + if (!_this.queue) { + return; + } + _this.prepareItems(); + }; + + // hooks to find the correct texture + this.registerFindHook(findText); + this.registerFindHook(findTextStyle); + this.registerFindHook(findMultipleBaseTextures); + this.registerFindHook(findBaseTexture); + this.registerFindHook(findTexture); + + // upload hooks + this.registerUploadHook(drawText); + this.registerUploadHook(calculateTextStyle); } /** * Upload all the textures and graphics to the GPU. * - * @param {Function|PIXI.DisplayObject|PIXI.Container} item - Either - * the container or display object to search for items to upload or - * the callback function, if items have been added using `prepare.add`. + * @param {Function|PIXI.DisplayObject|PIXI.Container|PIXI.BaseTexture|PIXI.Texture|PIXI.Graphics|PIXI.Text} item - + * Either the container or display object to search for items to upload, the items to upload themselves, + * or the callback function, if items have been added using `prepare.add`. * @param {Function} [done] - Optional callback when all queued uploads have completed */ - WebGLPrepare.prototype.upload = function upload(item, done) { + BasePrepare.prototype.upload = function upload(item, done) { if (typeof item === 'function') { done = item; item = null; @@ -34976,15 +39466,13 @@ var WebGLPrepare = function () { // Get the items for upload from the display if (this.queue.length) { - this.numLeft = WebGLPrepare.UPLOADS_PER_FRAME; - if (done) { this.completes.push(done); } if (!this.ticking) { this.ticking = true; - SharedTicker.add(this.tick, this); + SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY); } } else if (done) { done(); @@ -34992,24 +39480,38 @@ var WebGLPrepare = function () { }; /** - * Handle tick update. + * Handle tick update + * + * @private + */ + + + BasePrepare.prototype.tick = function tick() { + setTimeout(this.delayedTick, 0); + }; + + /** + * Actually prepare items. This is handled outside of the tick because it will take a while + * and we do NOT want to block the current animation frame from rendering. * * @private */ - WebGLPrepare.prototype.tick = function tick() { + BasePrepare.prototype.prepareItems = function prepareItems() { + this.limiter.beginFrame(); // Upload the graphics - while (this.queue.length && this.numLeft > 0) { + while (this.queue.length && this.limiter.allowedToUpload()) { var item = this.queue[0]; var uploaded = false; - for (var i = 0, len = this.uploadHooks.length; i < len; i++) { - if (this.uploadHooks[i](this.renderer, item)) { - this.numLeft--; - this.queue.shift(); - uploaded = true; - break; + if (item && !item._destroyed) { + for (var i = 0, len = this.uploadHooks.length; i < len; i++) { + if (this.uploadHooks[i](this.uploadHookHelper, item)) { + this.queue.shift(); + uploaded = true; + break; + } } } @@ -35019,13 +39521,9 @@ var WebGLPrepare = function () { } // We're finished - if (this.queue.length) { - this.numLeft = WebGLPrepare.UPLOADS_PER_FRAME; - } else { + if (!this.queue.length) { this.ticking = false; - SharedTicker.remove(this.tick, this); - var completes = this.completes.slice(0); this.completes.length = 0; @@ -35033,25 +39531,39 @@ var WebGLPrepare = function () { for (var _i = 0, _len = completes.length; _i < _len; _i++) { completes[_i](); } + } else { + // if we are not finished, on the next rAF do this again + SharedTicker.addOnce(this.tick, this, core.UPDATE_PRIORITY.UTILITY); } }; /** - * Adds hooks for finding and uploading items. + * Adds hooks for finding items. * - * @param {Function} [addHook] - Function call that takes two parameters: `item:*, queue:Array` - function must return `true` if it was able to add item to the queue. - * @param {Function} [uploadHook] - Function call that takes two parameters: `renderer:WebGLRenderer, item:*` and - * function must return `true` if it was able to handle upload of item. - * @return {PIXI.WebGLPrepare} Instance of plugin for chaining. + * @param {Function} addHook - Function call that takes two parameters: `item:*, queue:Array` + * function must return `true` if it was able to add item to the queue. + * @return {PIXI.BasePrepare} Instance of plugin for chaining. */ - WebGLPrepare.prototype.register = function register(addHook, uploadHook) { + BasePrepare.prototype.registerFindHook = function registerFindHook(addHook) { if (addHook) { this.addHooks.push(addHook); } + return this; + }; + + /** + * Adds hooks for uploading items. + * + * @param {Function} uploadHook - Function call that takes two parameters: `prepare:CanvasPrepare, item:*` and + * function must return `true` if it was able to handle upload of item. + * @return {PIXI.BasePrepare} Instance of plugin for chaining. + */ + + + BasePrepare.prototype.registerUploadHook = function registerUploadHook(uploadHook) { if (uploadHook) { this.uploadHooks.push(uploadHook); } @@ -35062,12 +39574,13 @@ var WebGLPrepare = function () { /** * Manually add an item to the uploading queue. * - * @param {PIXI.DisplayObject|PIXI.Container|*} item - Object to add to the queue - * @return {PIXI.WebGLPrepare} Instance of plugin for chaining. + * @param {PIXI.DisplayObject|PIXI.Container|PIXI.BaseTexture|PIXI.Texture|PIXI.Graphics|PIXI.Text|*} item - Object to + * add to the queue + * @return {PIXI.CanvasPrepare} Instance of plugin for chaining. */ - WebGLPrepare.prototype.add = function add(item) { + BasePrepare.prototype.add = function add(item) { // Add additional hooks for finding elements on special // types of objects that for (var i = 0, len = this.addHooks.length; i < len; i++) { @@ -35092,7 +39605,7 @@ var WebGLPrepare = function () { */ - WebGLPrepare.prototype.destroy = function destroy() { + BasePrepare.prototype.destroy = function destroy() { if (this.ticking) { SharedTicker.remove(this.tick, this); } @@ -35102,34 +39615,99 @@ var WebGLPrepare = function () { this.renderer = null; this.completes = null; this.queue = null; + this.limiter = null; + this.uploadHookHelper = null; }; - return WebGLPrepare; + return BasePrepare; }(); /** - * The number of graphics or textures to upload to the GPU + * Built-in hook to find multiple textures from objects like AnimatedSprites. * - * @static - * @type {number} - * @default 4 + * @private + * @param {PIXI.DisplayObject} item - Display object to check + * @param {Array<*>} queue - Collection of items to upload + * @return {boolean} if a PIXI.Texture object was found. */ -exports.default = WebGLPrepare; -WebGLPrepare.UPLOADS_PER_FRAME = DEFAULT_UPLOADS_PER_FRAME; +exports.default = BasePrepare; +function findMultipleBaseTextures(item, queue) { + var result = false; + + // Objects with mutliple textures + if (item && item._textures && item._textures.length) { + for (var i = 0; i < item._textures.length; i++) { + if (item._textures[i] instanceof core.Texture) { + var baseTexture = item._textures[i].baseTexture; + + if (queue.indexOf(baseTexture) === -1) { + queue.push(baseTexture); + result = true; + } + } + } + } + + return result; +} /** - * Built-in hook to upload PIXI.Texture objects to the GPU. + * Built-in hook to find BaseTextures from Sprites. * * @private - * @param {PIXI.WebGLRenderer} renderer - instance of the webgl renderer + * @param {PIXI.DisplayObject} item - Display object to check + * @param {Array<*>} queue - Collection of items to upload + * @return {boolean} if a PIXI.Texture object was found. + */ +function findBaseTexture(item, queue) { + // Objects with textures, like Sprites/Text + if (item instanceof core.BaseTexture) { + if (queue.indexOf(item) === -1) { + queue.push(item); + } + + return true; + } + + return false; +} + +/** + * Built-in hook to find textures from objects. + * + * @private + * @param {PIXI.DisplayObject} item - Display object to check + * @param {Array<*>} queue - Collection of items to upload + * @return {boolean} if a PIXI.Texture object was found. + */ +function findTexture(item, queue) { + if (item._texture && item._texture instanceof core.Texture) { + var texture = item._texture.baseTexture; + + if (queue.indexOf(texture) === -1) { + queue.push(texture); + } + + return true; + } + + return false; +} + +/** + * Built-in hook to draw PIXI.Text to its texture. + * + * @private + * @param {PIXI.WebGLRenderer|PIXI.CanvasPrepare} helper - Not used by this upload handler * @param {PIXI.DisplayObject} item - Item to check * @return {boolean} If item was uploaded. */ -function uploadBaseTextures(renderer, item) { - if (item instanceof core.BaseTexture) { - renderer.textureManager.updateTexture(item); +function drawText(helper, item) { + if (item instanceof core.Text) { + // updating text will return early if it is not dirty + item.updateText(true); return true; } @@ -35138,16 +39716,18 @@ function uploadBaseTextures(renderer, item) { } /** - * Built-in hook to upload PIXI.Graphics to the GPU. + * Built-in hook to calculate a text style for a PIXI.Text object. * * @private - * @param {PIXI.WebGLRenderer} renderer - instance of the webgl renderer + * @param {PIXI.WebGLRenderer|PIXI.CanvasPrepare} helper - Not used by this upload handler * @param {PIXI.DisplayObject} item - Item to check * @return {boolean} If item was uploaded. */ -function uploadGraphics(renderer, item) { - if (item instanceof core.Graphics) { - renderer.plugins.graphics.updateGraphics(item); +function calculateTextStyle(helper, item) { + if (item instanceof core.TextStyle) { + var font = item.toFontString(); + + core.TextMetrics.measureFont(font); return true; } @@ -35156,22 +39736,24 @@ function uploadGraphics(renderer, item) { } /** - * Built-in hook to find textures from Sprites. + * Built-in hook to find Text objects. * * @private * @param {PIXI.DisplayObject} item - Display object to check * @param {Array<*>} queue - Collection of items to upload - * @return {boolean} if a PIXI.Texture object was found. + * @return {boolean} if a PIXI.Text object was found. */ -function findBaseTextures(item, queue) { - // Objects with textures, like Sprites/Text - if (item instanceof core.BaseTexture) { +function findText(item, queue) { + if (item instanceof core.Text) { + // push the text style to prepare it - this can be really expensive + if (queue.indexOf(item.style) === -1) { + queue.push(item.style); + } + // also push the text object so that we can render it (to canvas/texture) if needed if (queue.indexOf(item) === -1) { queue.push(item); } - - return true; - } else if (item._texture && item._texture instanceof core.Texture) { + // also push the Text's texture for upload to GPU var texture = item._texture.baseTexture; if (queue.indexOf(texture) === -1) { @@ -35184,6 +39766,416 @@ function findBaseTextures(item, queue) { return false; } +/** + * Built-in hook to find TextStyle objects. + * + * @private + * @param {PIXI.TextStyle} item - Display object to check + * @param {Array<*>} queue - Collection of items to upload + * @return {boolean} if a PIXI.TextStyle object was found. + */ +function findTextStyle(item, queue) { + if (item instanceof core.TextStyle) { + if (queue.indexOf(item) === -1) { + queue.push(item); + } + + return true; + } + + return false; +} + +},{"../core":65,"./limiters/CountLimiter":185}],183:[function(require,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _core = require('../../core'); + +var core = _interopRequireWildcard(_core); + +var _BasePrepare2 = require('../BasePrepare'); + +var _BasePrepare3 = _interopRequireDefault(_BasePrepare2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var CANVAS_START_SIZE = 16; + +/** + * The prepare manager provides functionality to upload content to the GPU + * This cannot be done directly for Canvas like in WebGL, but the effect can be achieved by drawing + * textures to an offline canvas. + * This draw call will force the texture to be moved onto the GPU. + * + * An instance of this class is automatically created by default, and can be found at renderer.plugins.prepare + * + * @class + * @extends PIXI.prepare.BasePrepare + * @memberof PIXI.prepare + */ + +var CanvasPrepare = function (_BasePrepare) { + _inherits(CanvasPrepare, _BasePrepare); + + /** + * @param {PIXI.CanvasRenderer} renderer - A reference to the current renderer + */ + function CanvasPrepare(renderer) { + _classCallCheck(this, CanvasPrepare); + + var _this = _possibleConstructorReturn(this, _BasePrepare.call(this, renderer)); + + _this.uploadHookHelper = _this; + + /** + * An offline canvas to render textures to + * @type {HTMLCanvasElement} + * @private + */ + _this.canvas = document.createElement('canvas'); + _this.canvas.width = CANVAS_START_SIZE; + _this.canvas.height = CANVAS_START_SIZE; + + /** + * The context to the canvas + * @type {CanvasRenderingContext2D} + * @private + */ + _this.ctx = _this.canvas.getContext('2d'); + + // Add textures to upload + _this.registerUploadHook(uploadBaseTextures); + return _this; + } + + /** + * Destroys the plugin, don't use after this. + * + */ + + + CanvasPrepare.prototype.destroy = function destroy() { + _BasePrepare.prototype.destroy.call(this); + this.ctx = null; + this.canvas = null; + }; + + return CanvasPrepare; +}(_BasePrepare3.default); + +/** + * Built-in hook to upload PIXI.Texture objects to the GPU. + * + * @private + * @param {*} prepare - Instance of CanvasPrepare + * @param {*} item - Item to check + * @return {boolean} If item was uploaded. + */ + + +exports.default = CanvasPrepare; +function uploadBaseTextures(prepare, item) { + if (item instanceof core.BaseTexture) { + var image = item.source; + + // Sometimes images (like atlas images) report a size of zero, causing errors on windows phone. + // So if the width or height is equal to zero then use the canvas size + // Otherwise use whatever is smaller, the image dimensions or the canvas dimensions. + var imageWidth = image.width === 0 ? prepare.canvas.width : Math.min(prepare.canvas.width, image.width); + var imageHeight = image.height === 0 ? prepare.canvas.height : Math.min(prepare.canvas.height, image.height); + + // Only a small subsections is required to be drawn to have the whole texture uploaded to the GPU + // A smaller draw can be faster. + prepare.ctx.drawImage(image, 0, 0, imageWidth, imageHeight, 0, 0, prepare.canvas.width, prepare.canvas.height); + + return true; + } + + return false; +} + +core.CanvasRenderer.registerPlugin('prepare', CanvasPrepare); + +},{"../../core":65,"../BasePrepare":182}],184:[function(require,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _WebGLPrepare = require('./webgl/WebGLPrepare'); + +Object.defineProperty(exports, 'webgl', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_WebGLPrepare).default; + } +}); + +var _CanvasPrepare = require('./canvas/CanvasPrepare'); + +Object.defineProperty(exports, 'canvas', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_CanvasPrepare).default; + } +}); + +var _BasePrepare = require('./BasePrepare'); + +Object.defineProperty(exports, 'BasePrepare', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_BasePrepare).default; + } +}); + +var _CountLimiter = require('./limiters/CountLimiter'); + +Object.defineProperty(exports, 'CountLimiter', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_CountLimiter).default; + } +}); + +var _TimeLimiter = require('./limiters/TimeLimiter'); + +Object.defineProperty(exports, 'TimeLimiter', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_TimeLimiter).default; + } +}); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +},{"./BasePrepare":182,"./canvas/CanvasPrepare":183,"./limiters/CountLimiter":185,"./limiters/TimeLimiter":186,"./webgl/WebGLPrepare":187}],185:[function(require,module,exports){ +"use strict"; + +exports.__esModule = true; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * CountLimiter limits the number of items handled by a {@link PIXI.prepare.BasePrepare} to a specified + * number of items per frame. + * + * @class + * @memberof PIXI + */ +var CountLimiter = function () { + /** + * @param {number} maxItemsPerFrame - The maximum number of items that can be prepared each frame. + */ + function CountLimiter(maxItemsPerFrame) { + _classCallCheck(this, CountLimiter); + + /** + * The maximum number of items that can be prepared each frame. + * @private + */ + this.maxItemsPerFrame = maxItemsPerFrame; + /** + * The number of items that can be prepared in the current frame. + * @type {number} + * @private + */ + this.itemsLeft = 0; + } + + /** + * Resets any counting properties to start fresh on a new frame. + */ + + + CountLimiter.prototype.beginFrame = function beginFrame() { + this.itemsLeft = this.maxItemsPerFrame; + }; + + /** + * Checks to see if another item can be uploaded. This should only be called once per item. + * @return {boolean} If the item is allowed to be uploaded. + */ + + + CountLimiter.prototype.allowedToUpload = function allowedToUpload() { + return this.itemsLeft-- > 0; + }; + + return CountLimiter; +}(); + +exports.default = CountLimiter; + +},{}],186:[function(require,module,exports){ +"use strict"; + +exports.__esModule = true; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * TimeLimiter limits the number of items handled by a {@link PIXI.BasePrepare} to a specified + * number of milliseconds per frame. + * + * @class + * @memberof PIXI + */ +var TimeLimiter = function () { + /** + * @param {number} maxMilliseconds - The maximum milliseconds that can be spent preparing items each frame. + */ + function TimeLimiter(maxMilliseconds) { + _classCallCheck(this, TimeLimiter); + + /** + * The maximum milliseconds that can be spent preparing items each frame. + * @private + */ + this.maxMilliseconds = maxMilliseconds; + /** + * The start time of the current frame. + * @type {number} + * @private + */ + this.frameStart = 0; + } + + /** + * Resets any counting properties to start fresh on a new frame. + */ + + + TimeLimiter.prototype.beginFrame = function beginFrame() { + this.frameStart = Date.now(); + }; + + /** + * Checks to see if another item can be uploaded. This should only be called once per item. + * @return {boolean} If the item is allowed to be uploaded. + */ + + + TimeLimiter.prototype.allowedToUpload = function allowedToUpload() { + return Date.now() - this.frameStart < this.maxMilliseconds; + }; + + return TimeLimiter; +}(); + +exports.default = TimeLimiter; + +},{}],187:[function(require,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _core = require('../../core'); + +var core = _interopRequireWildcard(_core); + +var _BasePrepare2 = require('../BasePrepare'); + +var _BasePrepare3 = _interopRequireDefault(_BasePrepare2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +/** + * The prepare manager provides functionality to upload content to the GPU. + * + * An instance of this class is automatically created by default, and can be found at renderer.plugins.prepare + * + * @class + * @extends PIXI.prepare.BasePrepare + * @memberof PIXI.prepare + */ +var WebGLPrepare = function (_BasePrepare) { + _inherits(WebGLPrepare, _BasePrepare); + + /** + * @param {PIXI.WebGLRenderer} renderer - A reference to the current renderer + */ + function WebGLPrepare(renderer) { + _classCallCheck(this, WebGLPrepare); + + var _this = _possibleConstructorReturn(this, _BasePrepare.call(this, renderer)); + + _this.uploadHookHelper = _this.renderer; + + // Add textures and graphics to upload + _this.registerFindHook(findGraphics); + _this.registerUploadHook(uploadBaseTextures); + _this.registerUploadHook(uploadGraphics); + return _this; + } + + return WebGLPrepare; +}(_BasePrepare3.default); +/** + * Built-in hook to upload PIXI.Texture objects to the GPU. + * + * @private + * @param {PIXI.WebGLRenderer} renderer - instance of the webgl renderer + * @param {PIXI.DisplayObject} item - Item to check + * @return {boolean} If item was uploaded. + */ + + +exports.default = WebGLPrepare; +function uploadBaseTextures(renderer, item) { + if (item instanceof core.BaseTexture) { + // if the texture already has a GL texture, then the texture has been prepared or rendered + // before now. If the texture changed, then the changer should be calling texture.update() which + // reuploads the texture without need for preparing it again + if (!item._glTextures[renderer.CONTEXT_UID]) { + renderer.textureManager.updateTexture(item); + } + + return true; + } + + return false; +} + +/** + * Built-in hook to upload PIXI.Graphics to the GPU. + * + * @private + * @param {PIXI.WebGLRenderer} renderer - instance of the webgl renderer + * @param {PIXI.DisplayObject} item - Item to check + * @return {boolean} If item was uploaded. + */ +function uploadGraphics(renderer, item) { + if (item instanceof core.Graphics) { + // if the item is not dirty and already has webgl data, then it got prepared or rendered + // before now and we shouldn't waste time updating it again + if (item.dirty || item.clearDirty || !item._webGL[renderer.plugins.graphics.CONTEXT_UID]) { + renderer.plugins.graphics.updateGraphics(item); + } + + return true; + } + + return false; +} + /** * Built-in hook to find graphics. * @@ -35204,21 +40196,21 @@ function findGraphics(item, queue) { core.WebGLRenderer.registerPlugin('prepare', WebGLPrepare); -},{"../../core":61}],172:[function(require,module,exports){ +},{"../../core":65,"../BasePrepare":182}],188:[function(require,module,exports){ (function (global){ 'use strict'; exports.__esModule = true; exports.loader = exports.prepare = exports.particles = exports.mesh = exports.loaders = exports.interaction = exports.filters = exports.extras = exports.extract = exports.accessibility = undefined; -var _deprecation = require('./deprecation'); +var _polyfill = require('./polyfill'); -Object.keys(_deprecation).forEach(function (key) { +Object.keys(_polyfill).forEach(function (key) { if (key === "default" || key === "__esModule") return; Object.defineProperty(exports, key, { enumerable: true, get: function get() { - return _deprecation[key]; + return _polyfill[key]; } }); }); @@ -35235,7 +40227,9 @@ Object.keys(_core).forEach(function (key) { }); }); -require('./polyfill'); +var _deprecation = require('./deprecation'); + +var _deprecation2 = _interopRequireDefault(_deprecation); var _accessibility = require('./accessibility'); @@ -35275,42 +40269,49 @@ var prepare = _interopRequireWildcard(_prepare); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } -// import polyfills -exports.accessibility = accessibility; -exports.extract = extract; -exports.extras = extras; -exports.filters = filters; -exports.interaction = interaction; -exports.loaders = loaders; -exports.mesh = mesh; -exports.particles = particles; -exports.prepare = prepare; +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +// export core +_core.utils.mixins.performMixins(); /** - * A premade instance of the loader that can be used to loader resources. - * + * Alias for {@link PIXI.loaders.shared}. * @name loader * @memberof PIXI - * @property {PIXI.loaders.Loader} + * @type {PIXI.loader.Loader} */ -// export libs - +// handle mixins now, after all code has been added, including deprecation -// export core -var loader = new loaders.Loader(); +// export libs +// import polyfills. Done as an export to make sure polyfills are imported first +var loader = loaders.shared || null; +exports.accessibility = accessibility; +exports.extract = extract; +exports.extras = extras; +exports.filters = filters; +exports.interaction = interaction; +exports.loaders = loaders; +exports.mesh = mesh; +exports.particles = particles; +exports.prepare = prepare; exports.loader = loader; -// Always export pixi globally. +// Apply the deprecations + +if (typeof _deprecation2.default === 'function') { + (0, _deprecation2.default)(exports); +} +// Always export PixiJS globally. global.PIXI = exports; // eslint-disable-line }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./accessibility":40,"./core":61,"./deprecation":118,"./extract":120,"./extras":129,"./filters":140,"./interaction":146,"./loaders":149,"./mesh":158,"./particles":161,"./polyfill":167,"./prepare":170}]},{},[172])(172) +},{"./accessibility":42,"./core":65,"./deprecation":130,"./extract":132,"./extras":141,"./filters":152,"./interaction":159,"./loaders":162,"./mesh":171,"./particles":174,"./polyfill":180,"./prepare":184}]},{},[188])(188) }); diff --git a/js/rpg_core/Graphics.js b/js/rpg_core/Graphics.js index 9be6ec9d..24208133 100644 --- a/js/rpg_core/Graphics.js +++ b/js/rpg_core/Graphics.js @@ -36,7 +36,7 @@ Graphics.initialize = function(width, height, type) { this._errorPrinter = null; this._canvas = null; this._video = null; - this._videoUnlocked = !Utils.isMobileDevice(); + this._videoUnlocked = false; this._videoLoading = false; this._upperCanvas = null; this._renderer = null; @@ -657,6 +657,8 @@ Graphics._updateRealScale = function() { if (this._stretchEnabled) { var h = window.innerWidth / this._width; var v = window.innerHeight / this._height; + if (h >= 1 && h - 0.01 <= 1) h = 1; + if (v >= 1 && v - 0.01 <= 1) v = 1; this._realScale = Math.min(h, v); } else { this._realScale = this._scale; @@ -1097,6 +1099,8 @@ Graphics._isVideoVisible = function() { Graphics._setupEventHandlers = function() { window.addEventListener('resize', this._onWindowResize.bind(this)); document.addEventListener('keydown', this._onKeyDown.bind(this)); + document.addEventListener('keydown', this._onTouchEnd.bind(this)); + document.addEventListener('mousedown', this._onTouchEnd.bind(this)); document.addEventListener('touchend', this._onTouchEnd.bind(this)); }; diff --git a/js/rpg_core/Patch.js b/js/rpg_core/Patch.js deleted file mode 100644 index 613bbe26..00000000 --- a/js/rpg_core/Patch.js +++ /dev/null @@ -1,28 +0,0 @@ -(function() { - //patch from triacontane (@triacontane) - //This patch clears mapchip atlas which was drawn before. - - var TileRenderer = PIXI.WebGLRenderer.__plugins.tile; - TileRenderer._clearTexture = null; - var _TileRenderer_initBounds = TileRenderer.prototype.initBounds; - TileRenderer.prototype.initBounds = function() { - _TileRenderer_initBounds.apply(this, arguments); - - //create blank canvas to clear texture. - var clearTexture = document.createElement('canvas'); - clearTexture.width = 1024; - clearTexture.height = 1024; - TileRenderer._clearTexture = clearTexture; - }; - - PIXI.glCore.GLTexture.prototype._hackSubImage = function(sprite) { - this.bind(); - var gl = this.gl; - var x = sprite.position.x; - var y = sprite.position.y; - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1); - gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, this.format, this.type, TileRenderer._clearTexture); - var baseTex = sprite.texture.baseTexture; - gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, this.format, this.type, baseTex.source); - }; -})(); \ No newline at end of file diff --git a/js/rpg_core/ShaderTilemap.js b/js/rpg_core/ShaderTilemap.js index d9f2d6f5..b6793915 100644 --- a/js/rpg_core/ShaderTilemap.js +++ b/js/rpg_core/ShaderTilemap.js @@ -8,15 +8,16 @@ function ShaderTilemap() { Tilemap.apply(this, arguments); this.roundPixels = true; -}; +} ShaderTilemap.prototype = Object.create(Tilemap.prototype); ShaderTilemap.prototype.constructor = ShaderTilemap; // we need this constant for some platforms (Samsung S4, S5, Tab4, HTC One H8) PIXI.glCore.VertexArrayObject.FORCE_NATIVE = true; -PIXI.GC_MODES.DEFAULT = PIXI.GC_MODES.AUTO; +PIXI.settings.GC_MODE = PIXI.GC_MODES.AUTO; PIXI.tilemap.TileRenderer.SCALE_MODE = PIXI.SCALE_MODES.NEAREST; +PIXI.tilemap.TileRenderer.DO_CLEAR = true; /** * Uploads animation state in renderer @@ -27,8 +28,8 @@ PIXI.tilemap.TileRenderer.SCALE_MODE = PIXI.SCALE_MODES.NEAREST; ShaderTilemap.prototype._hackRenderer = function(renderer) { var af = this.animationFrame % 4; if (af==3) af = 1; - renderer.plugins.tile.tileAnim[0] = af * this._tileWidth; - renderer.plugins.tile.tileAnim[1] = (this.animationFrame % 3) * this._tileHeight; + renderer.plugins.tilemap.tileAnim[0] = af * this._tileWidth; + renderer.plugins.tilemap.tileAnim[1] = (this.animationFrame % 3) * this._tileHeight; return renderer; }; diff --git a/js/rpg_core/Sprite.js b/js/rpg_core/Sprite.js index 8fd35110..607d67b3 100644 --- a/js/rpg_core/Sprite.js +++ b/js/rpg_core/Sprite.js @@ -457,7 +457,7 @@ Sprite.prototype._renderWebGL = function(renderer) { //copy of pixi-v4 internal code this.calculateVertices(); - if (this._isPicture) { + if (this.pluginName === 'sprite' && this._isPicture) { // use heavy renderer, which reduces artifacts and applies corrent blendMode, // but does not use multitexture optimization this._speedUpCustomBlendModes(renderer); @@ -465,8 +465,8 @@ Sprite.prototype._renderWebGL = function(renderer) { renderer.plugins.picture.render(this); } else { // use pixi super-speed renderer - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } } }; diff --git a/js/rpg_core/Utils.js b/js/rpg_core/Utils.js index 9c6c5562..7f97743f 100644 --- a/js/rpg_core/Utils.js +++ b/js/rpg_core/Utils.js @@ -26,9 +26,7 @@ Utils.RPGMAKER_NAME = 'MV'; * @type String * @final */ -Utils.RPGMAKER_VERSION = "1.4.1"; - -Utils.RPGMAKER_ENGINE = "community-1.2c"; +Utils.RPGMAKER_VERSION = "1.6.1"; /** * Checks whether the option is in the query string. @@ -39,7 +37,9 @@ Utils.RPGMAKER_ENGINE = "community-1.2c"; * @return {Boolean} True if the option is in the query string */ Utils.isOptionValid = function(name) { - return location.search.slice(1).split('&').contains(name); + if (location.search.slice(1).split('&').contains(name)) {return 1;}; + if (typeof nw !== "undefined" && nw.App.argv.length > 0 && nw.App.argv[0].split('&').contains(name)) {return 1;}; + return 0; }; /** diff --git a/js/rpg_core/WebAudio.js b/js/rpg_core/WebAudio.js index a8e99ae0..b248b2cb 100644 --- a/js/rpg_core/WebAudio.js +++ b/js/rpg_core/WebAudio.js @@ -148,16 +148,19 @@ WebAudio._createMasterGainNode = function() { * @private */ WebAudio._setupEventHandlers = function() { - document.addEventListener("touchend", function() { - var context = WebAudio._context; - if (context && context.state === "suspended" && typeof context.resume === "function") { - context.resume().then(function() { - WebAudio._onTouchStart(); - }) - } else { + var resumeHandler = function() { + var context = WebAudio._context; + if (context && context.state === "suspended" && typeof context.resume === "function") { + context.resume().then(function() { WebAudio._onTouchStart(); - } - }); + }) + } else { + WebAudio._onTouchStart(); + } + }; + document.addEventListener("keydown", resumeHandler); + document.addEventListener("mousedown", resumeHandler); + document.addEventListener("touchend", resumeHandler); document.addEventListener('touchstart', this._onTouchStart.bind(this)); document.addEventListener('visibilitychange', this._onVisibilityChange.bind(this)); }; @@ -542,6 +545,11 @@ WebAudio.prototype._onXhrLoad = function(xhr) { * @private */ WebAudio.prototype._startPlaying = function(loop, offset) { + if (this._loopLength > 0) { + while (offset >= this._loopStart + this._loopLength) { + offset -= this._loopLength; + } + } this._removeEndTimer(); this._removeNodes(); this._createNodes(); diff --git a/js/rpg_core/_header.js b/js/rpg_core/_header.js index 539f4ab3..9dcc1a77 100644 --- a/js/rpg_core/_header.js +++ b/js/rpg_core/_header.js @@ -1,3 +1,3 @@ //============================================================================= -// rpg_core.js v1.4.1 (community-1.2c) +// rpg_core.js v1.6.1 //============================================================================= diff --git a/js/rpg_managers/BattleManager.js b/js/rpg_managers/BattleManager.js index 8827cf71..aa33076e 100644 --- a/js/rpg_managers/BattleManager.js +++ b/js/rpg_managers/BattleManager.js @@ -38,6 +38,7 @@ BattleManager.initMembers = function() { this._escapeRatio = 0; this._escaped = false; this._rewards = {}; + this._turnForced = false; }; BattleManager.isBattleTest = function() { @@ -144,7 +145,7 @@ BattleManager.updateEvent = function() { return this.updateEventMain(); } } - return this.checkAbort2(); + return this.checkAbort(); }; BattleManager.updateEventMain = function() { @@ -327,6 +328,13 @@ BattleManager.endTurn = function() { this._logWindow.displayAutoAffectedStatus(battler); this._logWindow.displayRegeneration(battler); }, this); + if (this.isForcedTurn()) { + this._turnForced = false; + } +}; + +BattleManager.isForcedTurn = function () { + return this._turnForced; }; BattleManager.updateTurnEnd = function() { @@ -457,6 +465,7 @@ BattleManager.forceAction = function(battler) { BattleManager.processForcedAction = function() { if (this._actionForcedBattler) { + this._turnForced = true; this._subject = this._actionForcedBattler; this._actionForcedBattler = null; this.startAction(); @@ -484,14 +493,6 @@ BattleManager.checkBattleEnd = function() { }; BattleManager.checkAbort = function() { - if ($gameParty.isEmpty() || this.isAborting()) { - this.processAbort(); - return true; - } - return false; -}; - -BattleManager.checkAbort2 = function() { if ($gameParty.isEmpty() || this.isAborting()) { SoundManager.playEscape(); this._escaped = true; diff --git a/js/rpg_managers/ImageManager.js b/js/rpg_managers/ImageManager.js index 0afa5996..2196c280 100644 --- a/js/rpg_managers/ImageManager.js +++ b/js/rpg_managers/ImageManager.js @@ -99,7 +99,7 @@ ImageManager.loadNormalBitmap = function(path, hue) { var key = this._generateCacheKey(path, hue); var bitmap = this._imageCache.get(key); if (!bitmap) { - bitmap = Bitmap.load(path); + bitmap = Bitmap.load(decodeURIComponent(path)); bitmap.addLoadListener(function() { bitmap.rotateHue(hue); }); diff --git a/js/rpg_managers/_header.js b/js/rpg_managers/_header.js index 55cafc68..8115d6eb 100644 --- a/js/rpg_managers/_header.js +++ b/js/rpg_managers/_header.js @@ -1,3 +1,3 @@ //============================================================================= -// rpg_managers.js v1.4.1 (community-1.2c) +// rpg_managers.js v1.6.1 //============================================================================= diff --git a/js/rpg_objects/Game_Battler.js b/js/rpg_objects/Game_Battler.js index 7b5cf3f4..cee33ef4 100644 --- a/js/rpg_objects/Game_Battler.js +++ b/js/rpg_objects/Game_Battler.js @@ -433,8 +433,10 @@ Game_Battler.prototype.onAllActionsEnd = function() { Game_Battler.prototype.onTurnEnd = function() { this.clearResult(); this.regenerateAll(); - this.updateStateTurns(); - this.updateBuffTurns(); + if (!BattleManager.isForcedTurn()) { + this.updateStateTurns(); + this.updateBuffTurns(); + } this.removeStatesAuto(2); }; diff --git a/js/rpg_objects/Game_Interpreter.js b/js/rpg_objects/Game_Interpreter.js index a68a6fe9..7d2fd223 100644 --- a/js/rpg_objects/Game_Interpreter.js +++ b/js/rpg_objects/Game_Interpreter.js @@ -579,11 +579,19 @@ Game_Interpreter.prototype.command413 = function() { // Break Loop Game_Interpreter.prototype.command113 = function() { + var depth = 0; while (this._index < this._list.length - 1) { this._index++; var command = this.currentCommand(); - if (command.code === 413 && command.indent < this._indent) { - break; + + if (command.code === 112) + depth++; + + if (command.code === 413) { + if (depth > 0) + depth--; + else + break; } } return true; @@ -654,22 +662,26 @@ Game_Interpreter.prototype.command121 = function() { // Control Variables Game_Interpreter.prototype.command122 = function() { var value = 0; - switch (this._params[3]) { // Operand - case 0: // Constant - value = this._params[4]; - break; - case 1: // Variable - value = $gameVariables.value(this._params[4]); - break; - case 2: // Random - value = this._params[4] + Math.randomInt(this._params[5] - this._params[4] + 1); - break; - case 3: // Game Data - value = this.gameDataOperand(this._params[4], this._params[5], this._params[6]); - break; - case 4: // Script - value = eval(this._params[4]); - break; + switch (this._params[3]) { // Operand + case 0: // Constant + value = this._params[4]; + break; + case 1: // Variable + value = $gameVariables.value(this._params[4]); + break; + case 2: // Random + value = this._params[5] - this._params[4] + 1; + for (var i = this._params[0]; i <= this._params[1]; i++) { + this.operateVariable(i, this._params[2], this._params[4] + Math.randomInt(value)); + } + return true; + break; + case 3: // Game Data + value = this.gameDataOperand(this._params[4], this._params[5], this._params[6]); + break; + case 4: // Script + value = eval(this._params[4]); + break; } for (var i = this._params[0]; i <= this._params[1]; i++) { this.operateVariable(i, this._params[2], value); diff --git a/js/rpg_objects/_header.js b/js/rpg_objects/_header.js index bc34d622..0c06db78 100644 --- a/js/rpg_objects/_header.js +++ b/js/rpg_objects/_header.js @@ -1,3 +1,3 @@ //============================================================================= -// rpg_objects.js v1.4.1 (community-1.2c) +// rpg_objects.js v1.6.1 //============================================================================= diff --git a/js/rpg_scenes/_header.js b/js/rpg_scenes/_header.js index 58702c06..e3a13fa1 100644 --- a/js/rpg_scenes/_header.js +++ b/js/rpg_scenes/_header.js @@ -1,3 +1,3 @@ //============================================================================= -// rpg_scenes.js v1.4.1 (community-1.2c) +// rpg_scenes.js v1.6.1 //============================================================================= diff --git a/js/rpg_sprites/Spriteset_Battle.js b/js/rpg_sprites/Spriteset_Battle.js index 51f658e3..43ce46ef 100644 --- a/js/rpg_sprites/Spriteset_Battle.js +++ b/js/rpg_sprites/Spriteset_Battle.js @@ -117,6 +117,7 @@ Spriteset_Battle.prototype.battleback2Name = function() { }; Spriteset_Battle.prototype.overworldBattleback1Name = function() { + if ($gameMap.battleback1Name() === '') return ''; if ($gamePlayer.isInVehicle()) { return this.shipBattleback1Name(); } else { @@ -125,6 +126,7 @@ Spriteset_Battle.prototype.overworldBattleback1Name = function() { }; Spriteset_Battle.prototype.overworldBattleback2Name = function() { + if ($gameMap.battleback2Name() === '') return ''; if ($gamePlayer.isInVehicle()) { return this.shipBattleback2Name(); } else { diff --git a/js/rpg_sprites/_header.js b/js/rpg_sprites/_header.js index ac5f61c7..ce0ecf70 100644 --- a/js/rpg_sprites/_header.js +++ b/js/rpg_sprites/_header.js @@ -1,3 +1,3 @@ //============================================================================= -// rpg_sprites.js v1.4.1 (community-1.2c) +// rpg_sprites.js v1.6.1 //============================================================================= diff --git a/js/rpg_windows/Window_DebugRange.js b/js/rpg_windows/Window_DebugRange.js index 2a8f9f5f..292d7447 100644 --- a/js/rpg_windows/Window_DebugRange.js +++ b/js/rpg_windows/Window_DebugRange.js @@ -92,5 +92,4 @@ Window_DebugRange.prototype.processCancel = function() { Window_DebugRange.prototype.setEditWindow = function(editWindow) { this._editWindow = editWindow; - this.update(); }; diff --git a/js/rpg_windows/Window_EquipSlot.js b/js/rpg_windows/Window_EquipSlot.js index 22b27b91..68f5c545 100644 --- a/js/rpg_windows/Window_EquipSlot.js +++ b/js/rpg_windows/Window_EquipSlot.js @@ -69,7 +69,6 @@ Window_EquipSlot.prototype.setStatusWindow = function(statusWindow) { Window_EquipSlot.prototype.setItemWindow = function(itemWindow) { this._itemWindow = itemWindow; - this.update(); }; Window_EquipSlot.prototype.updateHelp = function() { diff --git a/js/rpg_windows/Window_ItemCategory.js b/js/rpg_windows/Window_ItemCategory.js index 59b650d8..dd9adeff 100644 --- a/js/rpg_windows/Window_ItemCategory.js +++ b/js/rpg_windows/Window_ItemCategory.js @@ -38,5 +38,4 @@ Window_ItemCategory.prototype.makeCommandList = function() { Window_ItemCategory.prototype.setItemWindow = function(itemWindow) { this._itemWindow = itemWindow; - this.update(); }; diff --git a/js/rpg_windows/Window_SkillType.js b/js/rpg_windows/Window_SkillType.js index 320a1510..548933ca 100644 --- a/js/rpg_windows/Window_SkillType.js +++ b/js/rpg_windows/Window_SkillType.js @@ -53,7 +53,6 @@ Window_SkillType.prototype.update = function() { Window_SkillType.prototype.setSkillWindow = function(skillWindow) { this._skillWindow = skillWindow; - this.update(); }; Window_SkillType.prototype.selectLast = function() { diff --git a/js/rpg_windows/_header.js b/js/rpg_windows/_header.js index a44f3be0..1d225682 100644 --- a/js/rpg_windows/_header.js +++ b/js/rpg_windows/_header.js @@ -1,3 +1,3 @@ //============================================================================= -// rpg_windows.js v1.4.1 (community-1.2c) +// rpg_windows.js v1.6.1 //============================================================================= diff --git a/rpg_core.json b/rpg_core.json index e58bfc59..df8e2d59 100644 --- a/rpg_core.json +++ b/rpg_core.json @@ -1,6 +1,5 @@ [ "js/rpg_core/_header.js", - "js/rpg_core/Patch.js", "js/rpg_core/JsExtensions.js", "js/rpg_core/Utils.js", "js/rpg_core/CacheEntry.js", From 3a86d4e3f8fda296c2e595edda9a08a6f905bfd1 Mon Sep 17 00:00:00 2001 From: krmbn0576 Date: Mon, 12 Nov 2018 18:45:32 +0900 Subject: [PATCH 2/3] community-1.3 --- js/rpg_core/Utils.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/rpg_core/Utils.js b/js/rpg_core/Utils.js index e389e462..ff4a4659 100644 --- a/js/rpg_core/Utils.js +++ b/js/rpg_core/Utils.js @@ -28,6 +28,8 @@ Utils.RPGMAKER_NAME = 'MV'; */ Utils.RPGMAKER_VERSION = "1.6.1"; +Utils.RPGMAKER_ENGINE = "community-1.3"; + /** * Checks whether the option is in the query string. * From e75688ec97c688cca035a84c280b7e085cbb0164 Mon Sep 17 00:00:00 2001 From: krmbn0576 Date: Mon, 12 Nov 2018 18:52:57 +0900 Subject: [PATCH 3/3] header 1.3 --- js/rpg_core/_header.js | 2 +- js/rpg_managers/_header.js | 2 +- js/rpg_objects/_header.js | 2 +- js/rpg_scenes/_header.js | 2 +- js/rpg_sprites/_header.js | 2 +- js/rpg_windows/_header.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/js/rpg_core/_header.js b/js/rpg_core/_header.js index 9dcc1a77..86942f27 100644 --- a/js/rpg_core/_header.js +++ b/js/rpg_core/_header.js @@ -1,3 +1,3 @@ //============================================================================= -// rpg_core.js v1.6.1 +// rpg_core.js v1.6.1 (community-1.3) //============================================================================= diff --git a/js/rpg_managers/_header.js b/js/rpg_managers/_header.js index 8115d6eb..bbd49ec0 100644 --- a/js/rpg_managers/_header.js +++ b/js/rpg_managers/_header.js @@ -1,3 +1,3 @@ //============================================================================= -// rpg_managers.js v1.6.1 +// rpg_managers.js v1.6.1 (community-1.3) //============================================================================= diff --git a/js/rpg_objects/_header.js b/js/rpg_objects/_header.js index 0c06db78..227d3ab8 100644 --- a/js/rpg_objects/_header.js +++ b/js/rpg_objects/_header.js @@ -1,3 +1,3 @@ //============================================================================= -// rpg_objects.js v1.6.1 +// rpg_objects.js v1.6.1 (community-1.3) //============================================================================= diff --git a/js/rpg_scenes/_header.js b/js/rpg_scenes/_header.js index e3a13fa1..4d4d839c 100644 --- a/js/rpg_scenes/_header.js +++ b/js/rpg_scenes/_header.js @@ -1,3 +1,3 @@ //============================================================================= -// rpg_scenes.js v1.6.1 +// rpg_scenes.js v1.6.1 (community-1.3) //============================================================================= diff --git a/js/rpg_sprites/_header.js b/js/rpg_sprites/_header.js index ce0ecf70..6ddeaced 100644 --- a/js/rpg_sprites/_header.js +++ b/js/rpg_sprites/_header.js @@ -1,3 +1,3 @@ //============================================================================= -// rpg_sprites.js v1.6.1 +// rpg_sprites.js v1.6.1 (community-1.3) //============================================================================= diff --git a/js/rpg_windows/_header.js b/js/rpg_windows/_header.js index 1d225682..efbf0253 100644 --- a/js/rpg_windows/_header.js +++ b/js/rpg_windows/_header.js @@ -1,3 +1,3 @@ //============================================================================= -// rpg_windows.js v1.6.1 +// rpg_windows.js v1.6.1 (community-1.3) //=============================================================================